option optimization (#6253)

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

View File

@@ -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))