Namespaces

Enumerations

enum class NodeOptions : uint64_t
Name Value Comments
None 0 --
AllowCopy (1 << 0)

By default, nodes will not allow either copy construction or copy
assignment. Directly copying the contents of node storage for a structure
which is currently in a container cannot be allowed. The result would be
to have two objects, one of which is actually in a container, and the other
of which is only sort-of in the container.

Because of this, if code attempts to expand either the copy constructor or
assignment operator, by default it will trigger a static assert.

It may be the case, however, that a user wishes to allow copying of their
structure while the source and destination structure are _not_ in any
containers. In this case, pass the NodeOptions::AllowCopy flag. Nodes
will permit copying, but will runtime ZX_DEBUG_ASSERT if either the source
or destination exist within a container at the time of the copy. In builds
with ZX_DEBUG_ASSERTs disabled, neither the source nor the destination's
internal node contents will be modified. So, in the case of the following
code:

MyStructure
&
A = *(container.begin());
MyStructure B = A;
MyStructure
&
C = get_a_structure_reference_from_somewhere();
C = A;

++ A will remain in the container unmodified.
++ B will be in no container (as it was just constructed).
++ C either will either remain in its container if it had been in one, or
will remain in no container if not.

Finally, it is possible that a user actually _does_ wish to copy the
contents of a structure out of a container using either copy construction
or using copy assignment. If this is the case, pass the
NodeOptions::AllowCopyFromContainer flag. In addition to allowing the copy
constructor and assignment operators, the debug asserts will be disabled in
this situation. Users may copy the contents of their node, but not mutate
any container membership state as part of the process.

AllowCopyFromContainer (1 << 1)

By default, nodes will not allow either copy construction or copy
assignment. Directly copying the contents of node storage for a structure
which is currently in a container cannot be allowed. The result would be
to have two objects, one of which is actually in a container, and the other
of which is only sort-of in the container.

Because of this, if code attempts to expand either the copy constructor or
assignment operator, by default it will trigger a static assert.

It may be the case, however, that a user wishes to allow copying of their
structure while the source and destination structure are _not_ in any
containers. In this case, pass the NodeOptions::AllowCopy flag. Nodes
will permit copying, but will runtime ZX_DEBUG_ASSERT if either the source
or destination exist within a container at the time of the copy. In builds
with ZX_DEBUG_ASSERTs disabled, neither the source nor the destination's
internal node contents will be modified. So, in the case of the following
code:

MyStructure
&
A = *(container.begin());
MyStructure B = A;
MyStructure
&
C = get_a_structure_reference_from_somewhere();
C = A;

++ A will remain in the container unmodified.
++ B will be in no container (as it was just constructed).
++ C either will either remain in its container if it had been in one, or
will remain in no container if not.

Finally, it is possible that a user actually _does_ wish to copy the
contents of a structure out of a container using either copy construction
or using copy assignment. If this is the case, pass the
NodeOptions::AllowCopyFromContainer flag. In addition to allowing the copy
constructor and assignment operators, the debug asserts will be disabled in
this situation. Users may copy the contents of their node, but not mutate
any container membership state as part of the process.

AllowMove (1 << 2)

See the AllowCopy and AllowCopyFromConainer flags for details. AllowMove
and AllowMoveFromContainer are the same, simply applied to the rvalue
constructor and assignment operators of the node.

AllowMoveFromContainer (1 << 3)

See the AllowCopy and AllowCopyFromConainer flags for details. AllowMove
and AllowMoveFromContainer are the same, simply applied to the rvalue
constructor and assignment operators of the node.

AllowCopyMove static_cast<uint64_t>(AllowCopy) | static_cast<uint64_t>(AllowMove)

Convenience definitions

AllowCopyMoveFromContainer static_cast<uint64_t>(AllowCopyFromContainer) | static_cast<uint64_t>(AllowMoveFromContainer)

Convenience definitions

AllowMultiContainerUptr (1 << 4)

Allow an object to exist in multiple containers at once, even if one or
more of those containers tracks the object using a unique_ptr (or any other
non-copyable pointer type).

Generally, it would be a mistake to define an object which can exist in
multiple containers concurrently, and track those objects in their
containers using unique_ptr semantics. In theory, it should be impossible
for two different containers to track the same object at the same time,
each using something like a unique_ptr. This would violate the uniqueness of
the pointer.

Because of this, the ContainableBaseClasses helper (see below) will, by
default, complain and refuse to build if someone attempts to use it in
conjunction with a Containable mix-in which tracks objects using
unique_ptr-style pointers if there are any other containers in the
Containable list.

There are special cases, however, where a user might want this behavior to
be permitted. Consider an object whose lifecycle is managed by a central
list of unique_ptrs, but which can also exist on a temporary list which
tracks the objects using raw pointers for strictly algorithmic purposes.
Provided that the user carefully ensures that the object does not disappear
from the central list while it exists on the temporary list, this should be
completely fine. More concretely, the following should be allowed provided
that the user opts in.

using MainList = operation::TaggedDoublyLinkedList
<std
::unique_ptr
<Obj
>, MainListTag>;
using TmpList = operation::TaggedSinglyLinkedList
<Obj
*, TmpListTag>;

operation::Mutex all_objects_lock;
MainList all_objects TA_GUARDED(all_objects_lock);

void do_interesting_things() TA_EXCL(all_objects_lock) {
operation::AutoLock lock(
&all
_objects_lock);
TmpList interesting_objects;

for (auto
&
obj : all_objects) {
if (object_is_interesting(obj)) {
interesting_objects.push(obj);
}
}

do_interesting_things_to_interesting_objects(std::move(interesting_objects));
}

Users who have carefully considered the lifecycle management of their
objects and wish to allow this behavior should pass the
AllowMultiContainerUptr option to their Containable mix-in.

AllowRemoveFromContainer (1 << 5)

Nodes with this flag permitted to be directly removed from their container,
without needing to go through the container's erase method.

AllowClearUnsafe (1 << 6)

Enables the |clear_unsafe| operation on containers of unmanaged pointers.

ReservedBits 0xF000000000000000

Reserved bits reserved for testing purposes and should always be ignored by
node implementations.

A set of flag-style options which can be applied to container nodes in order

to control and sanity check their behavior and compatibility at compile time.

To control node options, users pass a set of options to either the

containable mix-in class (SinglyLinkedLisable, DoublyLinkedListable, or

WAVLTreeContainable), or directly to the node instance in the case that the

user is specifying custom container traits.

Defined at line 64 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/intrusive_container_utils.h

enum class SizeOrder
Name Value
N 0
Constant 1

An enumeration which can be used as a template argument on list types to

control the order of operation needed to compute the size of the list. When

set to SizeOrder::N, the list's size will not be maintained and there will be

no valid size() method to call. The only way to fetch the size of a list

would be via |size_slow()|. Alternatively, a user may specify

SizeOrder::Constant. In this case, the storage size of the list itself will

grow by a size_t, and the size of the list will be maintained as elements are

added and removed.

Defined at line 365 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/intrusive_container_utils.h

Records

Functions

  • template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
    bool is_pow2 (T val)

    is_pow2

    <T

    >(T val)

    Tests to see if val (which may be any unsigned integer type) is a power of 2

    or not. 0 is not considered to be a power of 2.

    Defined at line 22 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/algorithm.h

  • template <class T, class U, class L = std::conditional_t<sizeof(T) >= sizeof(U), T, U>, class = std::enable_if_t<std::is_unsigned_v<T>>, class = std::enable_if_t<std::is_unsigned_v<U>>>
    const L round_up (const T & val_, const U & multiple_)

    round_up rounds up val until it is divisible by multiple.

    Zero is divisible by all multiples.

    Defined at line 31 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/algorithm.h

  • operation::NodeOptions operator| (operation::NodeOptions A, operation::NodeOptions B)

    Helper functions which make it a bit easier to use the enum class NodeOptions

    in a flag style fashion.

    The | operator will take two options and or them together to produce their

    composition without needing to do all sorts of nasty casting. In other

    words:

    operation::NodeOptions::AllowX | operation::NodeOptions::AllowY

    is legal.

    The

    &

    operator is overloaded to perform the bitwise and of the

    underlying flags and test against zero returning a bool. This allows us to

    say things like:

    if constexpr (SomeOptions | operation::NodeOptions::AllowX) { ... }

    Defined at line 196 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/intrusive_container_utils.h

  • bool operator& (operation::NodeOptions A, operation::NodeOptions B)

    Defined at line 202 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/intrusive_container_utils.h

  • template <typename TagType = DefaultObjectTag, typename Containable>
    bool InContainer (const Containable & c)

    These are free function because making it a member function presents

    complicated lookup issues since the specific Containable classes exist as

    members of the ContainableBaseClasses

    <

    ...>, and you'd need to say

    obj.template GetContainableByTag

    <TagType

    >().InContainer (or

    RemoveFromContainer), which is super ugly.

    Defined at line 340 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/intrusive_container_utils.h

  • template <typename TagType = DefaultObjectTagtypename Containable>
    auto RemoveFromContainer (Containable & c)

    Defined at line 349 of file ../../src/devices/lib/dev-operation/include/lib/operation/helpers/intrusive_container_utils.h