option optimization (#6253)

This commit is contained in:
Arne Döring 2018-04-11 16:50:27 +02:00 • committed by Andreas Rumpf
commit e7edc7ec7f

View file

@ -69,26 +69,51 @@
## discard ## discard
import typetraits import typetraits
type
SomePointer = ref | ptr | pointer
type type
Option*[T] = object Option*[T] = object
## An optional type that stores its value and state separately in a boolean. ## An optional type that stores its value and state separately in a boolean.
when T is SomePointer:
val: T
else:
val: T val: T
has: bool has: bool
UnpackError* = ref object of ValueError UnpackError* = ref object of ValueError
proc some*[T](val: T): Option[T] = proc some*[T](val: T): Option[T] =
## Returns a ``Option`` that has this value. ## Returns a ``Option`` that has this value.
when T is SomePointer:
assert val != nil
result.val = val
else:
result.has = true result.has = true
result.val = val result.val = val
proc none*(T: typedesc): Option[T] = proc option*[T](val: T): Option[T] =
## Returns a ``Option`` for this type that has no value. ## Can be used to convert a pointer type to an option type. It
result.has = false ## converts ``nil`` to the none-option.
result.val = val
when T isnot SomePointer:
result.has = true
proc isSome*[T](self: Option[T]): bool = proc none*(T: typedesc): Option[T] =
## Returns an ``Option`` for this type that has no value.
# the default is the none type
discard
proc isSome*[T](self: Option[T]): bool {.inline.} =
when T is SomePointer:
self.val != nil
else:
self.has self.has
proc isNone*[T](self: Option[T]): bool = proc isNone*[T](self: Option[T]): bool {.inline.} =
when T is SomePointer:
self.val == nil
else:
not self.has not self.has
proc unsafeGet*[T](self: Option[T]): T = proc unsafeGet*[T](self: Option[T]): T =
@ -112,13 +137,13 @@ proc get*[T](self: Option[T], otherwise: T): T =
proc map*[T](self: Option[T], callback: proc (input: T)) = proc map*[T](self: Option[T], callback: proc (input: T)) =
## Applies a callback to the value in this Option ## Applies a callback to the value in this Option
if self.has: if self.isSome:
callback(self.val) callback(self.val)
proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] = 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 ## 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. ## containing the new value. If this option is None, None will be returned
if self.has: if self.isSome:
some[R]( callback(self.val) ) some[R]( callback(self.val) )
else: else:
none(R) 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 ## 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 ## `true`, the option is returned as a Some. If it returns false, it is
## returned as a None. ## returned as a None.
if self.has and not callback(self.val): if self.isSome and not callback(self.val):
none(T) none(T)
else: else:
self self
@ -256,3 +281,12 @@ when isMainModule:
check(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!")) check(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
check(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string)) 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))