summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorArne Döring <arne.doering@gmx.net>2018-04-11 16:50:27 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-04-11 16:50:27 +0200
commite7edc7ec7f5990c80f0bb1ff9d1cd7f0b000bb0e (patch)
tree99acc56bcb8f4044e4a5cc78db03aef8f308dd3b /lib/pure
parent6baca58693672f8fc9485272b3c350d0b0b77163 (diff)
downloadNim-e7edc7ec7f5990c80f0bb1ff9d1cd7f0b000bb0e.tar.gz
option optimization (#6253)
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/options.nim64
1 files changed, 49 insertions, 15 deletions
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index 6d2869bff..8a771be71 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -70,26 +70,51 @@
 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))