mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-05 20:47:53 +00:00
option optimization (#6253)
This commit is contained in:
committed by
Andreas Rumpf
parent
6baca58693
commit
e7edc7ec7f
@@ -69,27 +69,52 @@
|
||||
## discard
|
||||
import typetraits
|
||||
|
||||
type
|
||||
SomePointer = ref | ptr | pointer
|
||||
|
||||
type
|
||||
Option*[T] = object
|
||||
## An optional type that stores its value and state separately in a boolean.
|
||||
val: T
|
||||
has: bool
|
||||
when T is SomePointer:
|
||||
val: T
|
||||
else:
|
||||
val: T
|
||||
has: bool
|
||||
|
||||
UnpackError* = ref object of ValueError
|
||||
|
||||
proc some*[T](val: T): Option[T] =
|
||||
## Returns a ``Option`` that has this value.
|
||||
result.has = true
|
||||
when T is SomePointer:
|
||||
assert val != nil
|
||||
result.val = val
|
||||
else:
|
||||
result.has = true
|
||||
result.val = val
|
||||
|
||||
proc option*[T](val: T): Option[T] =
|
||||
## Can be used to convert a pointer type to an option type. It
|
||||
## converts ``nil`` to the none-option.
|
||||
result.val = val
|
||||
when T isnot SomePointer:
|
||||
result.has = true
|
||||
|
||||
proc none*(T: typedesc): Option[T] =
|
||||
## Returns a ``Option`` for this type that has no value.
|
||||
result.has = false
|
||||
## Returns an ``Option`` for this type that has no value.
|
||||
# the default is the none type
|
||||
discard
|
||||
|
||||
proc isSome*[T](self: Option[T]): bool =
|
||||
self.has
|
||||
proc isSome*[T](self: Option[T]): bool {.inline.} =
|
||||
when T is SomePointer:
|
||||
self.val != nil
|
||||
else:
|
||||
self.has
|
||||
|
||||
proc isNone*[T](self: Option[T]): bool =
|
||||
not self.has
|
||||
proc isNone*[T](self: Option[T]): bool {.inline.} =
|
||||
when T is SomePointer:
|
||||
self.val == nil
|
||||
else:
|
||||
not self.has
|
||||
|
||||
proc unsafeGet*[T](self: Option[T]): T =
|
||||
## Returns the value of a ``some``. Behavior is undefined for ``none``.
|
||||
@@ -112,14 +137,14 @@ proc get*[T](self: Option[T], otherwise: T): T =
|
||||
|
||||
proc map*[T](self: Option[T], callback: proc (input: T)) =
|
||||
## Applies a callback to the value in this Option
|
||||
if self.has:
|
||||
if self.isSome:
|
||||
callback(self.val)
|
||||
|
||||
proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] =
|
||||
## Applies a callback to the value in this Option and returns an option
|
||||
## containing the new value. If this option is None, None will be returned.
|
||||
if self.has:
|
||||
some[R](callback(self.val))
|
||||
## containing the new value. If this option is None, None will be returned
|
||||
if self.isSome:
|
||||
some[R]( callback(self.val) )
|
||||
else:
|
||||
none(R)
|
||||
|
||||
@@ -142,7 +167,7 @@ proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] =
|
||||
## Applies a callback to the value in this Option. If the callback returns
|
||||
## `true`, the option is returned as a Some. If it returns false, it is
|
||||
## returned as a None.
|
||||
if self.has and not callback(self.val):
|
||||
if self.isSome and not callback(self.val):
|
||||
none(T)
|
||||
else:
|
||||
self
|
||||
@@ -155,7 +180,7 @@ proc `==`*(a, b: Option): bool =
|
||||
proc `$`*[T](self: Option[T]): string =
|
||||
## Get the string representation of this option. If the option has a value,
|
||||
## the result will be `Some(x)` where `x` is the string representation of the contained value.
|
||||
## If the option does not have a value, the result will be `None[T]` where `T` is the name of
|
||||
## If the option does not have a value, the result will be `None[T]` where `T` is the name of
|
||||
## the type contained in the option.
|
||||
if self.has:
|
||||
"Some(" & $self.val & ")"
|
||||
@@ -256,3 +281,12 @@ when isMainModule:
|
||||
|
||||
check(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
|
||||
check(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))
|
||||
|
||||
test "SomePointer":
|
||||
var intref: ref int
|
||||
check(option(intref).isNone)
|
||||
intref.new
|
||||
check(option(intref).isSome)
|
||||
|
||||
let tmp = option(intref)
|
||||
check(sizeof(tmp) == sizeof(ptr int))
|
||||
|
||||
Reference in New Issue
Block a user