typedef x::ref<valueObj
> valueRef; typedef x::ptr<valueObj
> valuePtr; typedef x::hier<keyClass
,valueRef
> hierclass;keyClass
keyelement; std::list<keyClass
> key; hierclass h=hierclass::create(); hierclass::base::readlock lock=h->create_readlock();
A reader lock implements navigation of a hierachical container, without making any changes to it. Note, though, that after retrieving a value object from the container, there's nothing that prohibits the contents of the referenced object from being modified, but this is outside the scope covered by the reader lock. Multiple reader locks can get created concurrently.
A reader lock is a reference-counted object that can be freely passed around. Note that although the reader and writer locks implement thread-safe access to the hierarchical container, each individual reader or a writer lock can only be accessed by one thread a time.
create_readlock
() creates a new reader lock.
If there's an existing writer lock,
create_readlock
() waits until the writer lock
goes out of scope and gets destroyed.
auto lock2=lock->clone();
Each reader lock represents a key in the hierarchy, either a key with
a value, or an intermediate key without a value.
A new reader lock created by
create_readlock
() initially
represents the hierarchy's root, or an empty key. The root
node is no different
than any other node in the hierarchy, and may even have a value, but
it always exists even in an otherwise completely empty hierarchy.
clone
() results in another reader lock,
that initially points to the same key.
Always use clone
() to create another
read lock. Invoking create_readlock
()
again can result in a deadlock with a pending writer lock from
another thread.
A pending writer lock may block new reader locks, and the existing
reader lock in the same thread can trigger a deadlock, with the
thread waiting for the writer lock, and the writer lock thread
waiting for the existing reader lock to go away.
valuePtr ptr=lock->entry(); bool flag=lock->exists(); const std::list<keyClass> &name=lock->name();
entry
()
returns a x::ptr
of the value of the lock's current node, which may be
null if this is an intermediate node, without a value.
exists
() checks if the x::ptr
would be null.
Finally,
name
()
returns the current node's key.
keyelement element; key valuekey; bool flag=lock->parent(); bool flag=lock->child(element); std::set<keyClass> children=lock->children(); bool flag=lock->child(key, true);
parent
()
returns true
if the lock's current node has
a parent node. parent
() returns
false
if the lock's current node is the hierarchy's
root node, with a null key, true
otherwise, since
all other nodes must have a parent node.
child
() takes a key element, and returns a flag
indicating whether the current node has an inferior, or a child node
for the given key; either a node with a value, or an intermediate node
without a value.
children
() enumerates all such nodes that
exist.
The first argument of the two argument version of
child
() is a list of key elements, a complete
key path. If the second argument is false
,
child
() returns true
only if the specified inferior node, to the lock's current node,
exists and has a value. If the second argument is
true
child
() returns
true
if the specified inferior node exists, with a
value, or if there's any intermediate node with a value.
bool flag=lock->to_parent(); bool flag=lock->to_child(element); bool flag=lock->to_child(key, true);
to_parent
() and
to_child
() are similar to
parent
() and
child
(), but they also change the lock's
current node if they return true
.
They use the same criteria as
parent
() and
child
(), for the return value, and the
lock's current position is unchanged with the
false
return value.
For the two-argument version of
to_child
(), if the second parameter is
true
, the lock gets repositioned to the specified
inferior child node, if it has a value, or to its closest intermediate
node with a value, if to_child
() returns
true
.