Skip to content

Commit

Permalink
Merge pull request #3174 from vrurg/problem-solving-99
Browse files Browse the repository at this point in the history
Provide means of preserving the decontainerization of values on Hash -> Map coercion

This solution provides a way to control decontainerization of values my `Map` externally by supplying `:DECONT` named argument to `STORE` method when called with `:INITALIZE`. _This would allow any other `Map`-deriving class to provide functionality similar to that of `Hash` with minimum amount of code._
  • Loading branch information
vrurg committed Sep 18, 2019
2 parents 971b5ec + b67171e commit 7e5bd31
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/core.c/Hash.pm6
Expand Up @@ -17,7 +17,7 @@ my class Hash { # declared in BOOTSTRAP
nqp::create(Map), Map, '$!storage',
nqp::getattr(self,Map,'$!storage')
),
nqp::create(Map).STORE(self, :INITIALIZE)
nqp::create(Map).STORE(self, :INITIALIZE, :DECONT)
)
}
method clone(Hash:D:) is raw {
Expand Down
181 changes: 142 additions & 39 deletions src/core.c/Map.pm6
Expand Up @@ -295,8 +295,23 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
!! "Cannot change key '{key}' in an immutable {self.^name}"
}

# Directly copy from the other Map's internals: the only thing we need
# to do, is to decontainerize the values.
# Directly copy from the other Map's internals.
method !STORE_MAP_FROM_MAP_DECONT(\map --> Nil) {
nqp::if(
nqp::elems(my \other := nqp::getattr(map,Map,'$!storage')),
nqp::stmts(
(my \iter := nqp::iterator(other)),
nqp::while(
iter,
nqp::bindkey(
$!storage,
nqp::iterkey_s(nqp::shift(iter)),
nqp::decont(nqp::iterval(iter))
)
)
)
)
}
method !STORE_MAP_FROM_MAP(\map --> Nil) {
nqp::if(
nqp::elems(my \other := nqp::getattr(map,Map,'$!storage')),
Expand All @@ -307,7 +322,7 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
nqp::bindkey(
$!storage,
nqp::iterkey_s(nqp::shift(iter)),
nqp::decont(nqp::iterval(iter)) # get rid of any containers
nqp::iterval(iter)
)
)
)
Expand All @@ -317,7 +332,7 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
# Directly copy from the Object Hash's internals, but pay respect to the
# fact that we're only interested in the values (which contain a Pair with
# the object key and a value that we need to decontainerize.
method !STORE_MAP_FROM_OBJECT_HASH(\map --> Nil) {
method !STORE_MAP_FROM_OBJECT_HASH_DECONT(\map --> Nil) {
nqp::if(
nqp::elems(my \other := nqp::getattr(map,Map,'$!storage')),
nqp::stmts(
Expand All @@ -327,7 +342,7 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
nqp::bindkey(
$!storage,
nqp::getattr(
(my \pair := nqp::iterval(nqp::shift(iter))),
(my Mu \pair := nqp::iterval(nqp::shift(iter))),
Pair, '$!key'
).Str,
nqp::decont(nqp::getattr(pair,Pair,'$!value'))
Expand All @@ -336,8 +351,34 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
)
)
}
method !STORE_MAP_FROM_OBJECT_HASH(\map --> Nil) {
nqp::if(
nqp::elems(my \other := nqp::getattr(map,Map,'$!storage')),
nqp::stmts(
(my \iter := nqp::iterator(other)),
nqp::while(
iter,
nqp::bindkey(
$!storage,
nqp::getattr(
(my Mu \pair := nqp::iterval(nqp::shift(iter))),
Pair, '$!key'
).Str,
nqp::getattr(pair,Pair,'$!value')
)
)
)
)
}

# Copy the contents of a Mappy thing that's not in a container.
method !STORE_MAP_DECONT(\map --> Nil) {
nqp::if(
nqp::eqaddr(map.keyof,Str(Any)), # is it not an Object Hash?
self!STORE_MAP_FROM_MAP_DECONT(map),
self!STORE_MAP_FROM_OBJECT_HASH_DECONT(map)
)
}
method !STORE_MAP(\map --> Nil) {
nqp::if(
nqp::eqaddr(map.keyof,Str(Any)), # is it not an Object Hash?
Expand All @@ -347,69 +388,131 @@ my class Map does Iterable does Associative { # declared in BOOTSTRAP
}

# Store the contents of an iterator into the Map
method !STORE_MAP_FROM_ITERATOR_DECONT(\iter --> Map:D) is raw {
nqp::stmts(
nqp::until(
nqp::eqaddr((my Mu $x := iter.pull-one),IterationEnd),
nqp::if(
nqp::istype($x,Pair),
nqp::bindkey(
$!storage,
nqp::getattr(nqp::decont($x),Pair,'$!key').Str,
nqp::decont(nqp::getattr(nqp::decont($x),Pair,'$!value'))
),
nqp::if(
(nqp::istype($x,Map) && nqp::not_i(nqp::iscont($x))),
self!STORE_MAP_DECONT($x),
nqp::if(
nqp::eqaddr((my Mu $y := iter.pull-one),IterationEnd),
nqp::if(
nqp::istype($x,Failure),
$x.throw,
X::Hash::Store::OddNumber.new(
found => self.elems * 2 + 1,
last => $x
).throw
),
nqp::bindkey($!storage,$x.Str,nqp::decont($y))
)
)
)
),
self
)
}
method !STORE_MAP_FROM_ITERATOR(\iter --> Map:D) is raw {
nqp::stmts(
nqp::until(
nqp::eqaddr((my Mu $x := iter.pull-one),IterationEnd),
nqp::if(
nqp::istype($x,Pair),
nqp::bindkey(
$!storage,
nqp::getattr(nqp::decont($x),Pair,'$!key').Str,
nqp::getattr(nqp::decont($x),Pair,'$!value')
),
nqp::until(
nqp::eqaddr((my Mu $x := iter.pull-one),IterationEnd),
nqp::if(
(nqp::istype($x,Map) && nqp::not_i(nqp::iscont($x))),
self!STORE_MAP($x),
nqp::istype($x,Pair),
nqp::bindkey(
$!storage,
nqp::getattr(nqp::decont($x),Pair,'$!key').Str,
nqp::getattr(nqp::decont($x),Pair,'$!value')
),
nqp::if(
nqp::eqaddr((my Mu $y := iter.pull-one),IterationEnd),
(nqp::istype($x,Map) && nqp::not_i(nqp::iscont($x))),
self!STORE_MAP($x),
nqp::if(
nqp::istype($x,Failure),
$x.throw,
X::Hash::Store::OddNumber.new(
found => self.elems * 2 + 1,
last => $x
).throw
),
nqp::bindkey($!storage,$x.Str,$y)
nqp::eqaddr((my Mu $y := iter.pull-one),IterationEnd),
nqp::if(
nqp::istype($x,Failure),
$x.throw,
X::Hash::Store::OddNumber.new(
found => self.elems * 2 + 1,
last => $x
).throw
),
nqp::bindkey($!storage,$x.Str,$y)
)
)
)
)
),
self
),
self
)
}

proto method STORE(Map:D: |) {*}
multi method STORE(Map:D: Map:D \map, :$INITIALIZE! --> Map:D) {
multi method STORE(Map:D: Map:D \map, :$INITIALIZE!, :$DECONT? --> Map:D) {
nqp::if(
nqp::eqaddr(map.keyof,Str(Any)), # is it not an Object Hash?
nqp::if(
nqp::elems(my \other := nqp::getattr(map,Map,'$!storage')),
nqp::if(
nqp::eqaddr(map.WHAT,Map),
nqp::p6bindattrinvres(self,Map,'$!storage',other),
nqp::p6bindattrinvres(
self,Map,'$!storage',nqp::clone(other)
nqp::if(
$DECONT,
samewith(map.iterator, :INITIALIZE, :$DECONT),
nqp::p6bindattrinvres(
self,Map,'$!storage',nqp::clone(other)
)
)
),
self # nothing to do
),
nqp::p6bindattrinvres(
self, Map, '$!storage',
nqp::stmts(
(my \new_map := nqp::p6bindattrinvres(nqp::create(self), Map, '$!storage', nqp::hash)),
nqp::p6bindattrinvres(
nqp::create(self), Map, '$!storage', nqp::hash
)!STORE_MAP_FROM_OBJECT_HASH(map)
self, Map, '$!storage',
nqp::if(
$DECONT,
new_map!STORE_MAP_FROM_OBJECT_HASH_DECONT(map),
new_map!STORE_MAP_FROM_OBJECT_HASH(map)
)
)
)
)
}
multi method STORE(Map:D: \to_store, :$INITIALIZE! --> Map:D) {
multi method STORE(Map:D: Iterator:D \iter, :$INITIALIZE!, :$DECONT? --> Map:D) {
nqp::p6bindattrinvres(
self, Map, '$!storage',
nqp::getattr(
nqp::p6bindattrinvres(
nqp::create(self), Map, '$!storage', nqp::hash
)!STORE_MAP_FROM_ITERATOR(to_store.iterator),
nqp::stmts(
(my \new_map := nqp::p6bindattrinvres(nqp::create(self), Map, '$!storage', nqp::hash)),
nqp::if(
$DECONT,
new_map!STORE_MAP_FROM_ITERATOR_DECONT(iter),
new_map!STORE_MAP_FROM_ITERATOR(iter)
)
),
Map, '$!storage'
)
)
}
multi method STORE(Map:D: \to_store, :$INITIALIZE!, :$DECONT? --> Map:D) {
nqp::p6bindattrinvres(
self, Map, '$!storage',
nqp::getattr(
nqp::stmts(
(my \new_map := nqp::p6bindattrinvres(nqp::create(self), Map, '$!storage', nqp::hash)),
nqp::if(
$DECONT,
new_map!STORE_MAP_FROM_ITERATOR_DECONT(to_store.iterator),
new_map!STORE_MAP_FROM_ITERATOR(to_store.iterator)
)
),
Map, '$!storage'
)
)
Expand Down

0 comments on commit 7e5bd31

Please sign in to comment.