Pointers
Metal defines two pointer types, Ptr
and VPtr
. The Ptr
pointer can either point
to an element in a container, or be a null pointer. The VPtr
pointer is guaranteed to point
to an element.
Pointers are invalidated when the container is modified, with the exception of the
removeAndAdvance
methods.
A pointer has a single type parameters, representing the singleton type of the pointed collection. Pointers
are implemented using value classes containing a primitive Long
.
Most of the container methods return possibly null Ptr
instances. To convert a Ptr
to a VPtr
, the following syntax is encouraged:
scala> import metal._
import metal._
scala> val container = mutable.HashSet(1, 2, 3)
container: metal.mutable.HashSet.S[Int] = Set(1, 2, 3)
scala> val p = container.ptr
p: metal.Ptr[container.type] = Ptr(1)
scala> p match {
| case IsVPtr(vp) =>
| // now `vp` is a `VPtr`
| println(vp.key)
| case _ =>
| println("container is empty")
| }
1
Thanks to name-based extractors, the code snippet above does not perform any allocations.
Several methods are implemented on Ptr
and VPtr
, and can be used to access the pointed
element.
scala> import metal._
import metal._
scala> import metal.syntax._
import metal.syntax._
scala> val m = mutable.HashMap(1 -> 2, 3 -> 4)
m: metal.mutable.HashMap.M[Int,Int] = Map(1 -> 2, 3 -> 4)
scala> // we request a pointer to the first element in the map (hash maps have an internal arbitrary order)
| val p = m.ptr
p: metal.Ptr[m.type] = Ptr(1)
scala> assert(!p.isNull)
scala> assert(p.nonNull)
scala> assert(p.keyOrElse(-1) > 0)
scala> // does not throw, `sys.error` is inlined by macros and only called when `p` is null
| p.keyOrElse(sys.error("")) > 0
res6: Boolean = true
scala> // same syntax for pointed values
| p.valueOrElse(-1)
res8: Int = 2
scala> p match {
| case IsVPtr(vp) =>
| // vp is now a non-null `VPtr`, the pointed key is available
| assert(vp.key > 0)
| assert(vp.value % 2 == 0)
| // we can ask for a (possibly null) pointer to the next element, according
| // to the hash map internal order
| val nxt = vp.next
| case _ =>
| }
scala> // we can look for keys
| val p1 = m.ptrFind(3)
p1: metal.Ptr[m.type] = Ptr(3)
scala> // and the same methods are available on that pointer
| assert(p1.nonNull)