Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
FORMUS3IC_LAS3
/
embb
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
e518a31d
authored
Jun 11, 2015
by
Danila Klimenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code refactoring (const-correctness, internal interfaces)
parent
abd38fe8
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
549 additions
and
583 deletions
+549
-583
base_cpp/include/embb/base/atomic.h
+1
-1
base_cpp/include/embb/base/internal/atomic/atomic_base.h
+1
-2
containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h
+112
-0
containers_cpp/include/embb/containers/internal/hazard_pointer.h
+169
-0
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
+116
-212
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-rebalance.h
+94
-134
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
+56
-234
No files found.
base_cpp/include/embb/base/atomic.h
View file @
e518a31d
...
...
@@ -478,7 +478,7 @@ class Atomic<BaseType*> : public embb::base::internal::atomic::
public
:
Atomic
()
:
embb
::
base
::
internal
::
atomic
::
AtomicPointer
<
BaseType
,
ptrdiff_t
,
sizeof
(
BaseType
*
)
>
()
{}
Atomic
(
BaseType
*
p
)
:
embb
::
base
::
internal
::
atomic
::
explicit
Atomic
(
BaseType
*
p
)
:
embb
::
base
::
internal
::
atomic
::
AtomicPointer
<
BaseType
,
ptrdiff_t
,
sizeof
(
BaseType
*
)
>
(
p
)
{}
BaseType
*
operator
=
(
BaseType
*
p
)
{
...
...
base_cpp/include/embb/base/internal/atomic/atomic_base.h
View file @
e518a31d
...
...
@@ -177,8 +177,7 @@ CompareAndSwap(BaseType& expected, BaseType desired) {
compare_and_swap
(
&
AtomicValue
,
&
native_expected
,
native_desired
))
!=
0
?
true
:
false
;
if
(
!
return_val
)
expected
=
Load
();
memcpy
(
&
expected
,
&
native_expected
,
sizeof
(
expected
));
return
return_val
;
}
...
...
containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h
View file @
e518a31d
...
...
@@ -418,6 +418,118 @@ void HazardPointer< GuardType >::EnqueuePointerForDeletion(
template
<
typename
GuardType
>
const
double
embb
::
containers
::
internal
::
HazardPointer
<
GuardType
>::
RETIRE_THRESHOLD
=
1
.
25
f
;
template
<
typename
Type
>
UniqueHazardPointer
<
Type
>::
UniqueHazardPointer
()
:
hazard_guard_
(
NULL
),
undefined_guard_
(
NULL
),
active_
(
false
)
{}
template
<
typename
Type
>
UniqueHazardPointer
<
Type
>::
UniqueHazardPointer
(
AtomicTypePtr
&
hazard_guard
,
Type
*
undefined_guard
)
:
hazard_guard_
(
&
hazard_guard
),
undefined_guard_
(
undefined_guard
),
active_
(
LoadGuardedPointer
()
==
undefined_guard_
)
{}
template
<
typename
Type
>
UniqueHazardPointer
<
Type
>::~
UniqueHazardPointer
()
{
if
(
IsActive
())
ClearHazard
();
}
template
<
typename
Type
>
bool
UniqueHazardPointer
<
Type
>::
ProtectHazard
(
const
AtomicTypePtr
&
hazard
)
{
assert
(
OwnsHazardGuard
());
// Read the hazard and store it into the guard
StoreGuardedPointer
(
hazard
.
Load
());
// Check whether the guard is valid
SetActive
(
LoadGuardedPointer
()
==
hazard
.
Load
());
// Clear the guard if it is invalid
if
(
!
IsActive
())
ClearHazard
();
return
IsActive
();
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
ProtectSafe
(
Type
*
safe_ptr
)
{
assert
(
OwnsHazardGuard
());
StoreGuardedPointer
(
safe_ptr
);
SetActive
(
true
);
}
template
<
typename
Type
>
UniqueHazardPointer
<
Type
>::
operator
Type
*
()
const
{
assert
(
IsActive
());
return
LoadGuardedPointer
();
}
template
<
typename
Type
>
Type
*
UniqueHazardPointer
<
Type
>::
operator
->
()
const
{
assert
(
IsActive
());
return
LoadGuardedPointer
();
}
template
<
typename
Type
>
Type
&
UniqueHazardPointer
<
Type
>::
operator
*
()
const
{
assert
(
IsActive
());
return
*
(
LoadGuardedPointer
());
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
AdoptGuard
(
const
UniqueHazardPointer
&
other
)
{
assert
(
OwnsHazardGuard
());
StoreGuardedPointer
(
other
.
LoadGuardedPointer
());
SetActive
(
other
.
active_
);
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
Swap
(
UniqueHazardPointer
&
other
)
{
std
::
swap
(
hazard_guard_
,
other
.
hazard_guard_
);
std
::
swap
(
undefined_guard_
,
other
.
undefined_guard_
);
std
::
swap
(
active_
,
other
.
active_
);
}
template
<
typename
Type
>
Type
*
UniqueHazardPointer
<
Type
>::
ReleaseHazard
()
{
assert
(
IsActive
());
Type
*
released_hazard
=
LoadGuardedPointer
();
ClearHazard
();
SetActive
(
false
);
return
released_hazard
;
}
template
<
typename
Type
>
bool
UniqueHazardPointer
<
Type
>::
IsActive
()
const
{
return
active_
;
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
SetActive
(
bool
active
)
{
active_
=
active
;
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
ClearHazard
()
{
StoreGuardedPointer
(
undefined_guard_
);
}
template
<
typename
Type
>
Type
*
UniqueHazardPointer
<
Type
>::
LoadGuardedPointer
()
const
{
return
hazard_guard_
->
Load
();
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
StoreGuardedPointer
(
Type
*
ptr
)
{
hazard_guard_
->
Store
(
ptr
);
}
template
<
typename
Type
>
bool
UniqueHazardPointer
<
Type
>::
OwnsHazardGuard
()
const
{
return
hazard_guard_
!=
NULL
;
}
}
// namespace internal
}
// namespace containers
}
// namespace embb
...
...
containers_cpp/include/embb/containers/internal/hazard_pointer.h
View file @
e518a31d
...
...
@@ -529,6 +529,175 @@ class HazardPointer {
*/
void
EnqueuePointerForDeletion
(
GuardType
guardedElement
);
};
/**
* Ownership wrapper for a hazard pointer
*
* Uses an entry of the hazard table (guard) to provide protection for a single
* hazardous pointer. While providing standard pointer dereference and member
* access operators, it requires special care for pointer assignment (realized
* via 'ProtectHazard' method).
* On destruction, it clears the wrapped hazard table entry, releasing the
* protected hazardous pointer (if any).
*
* \tparam Type Type of the object to be protected by the hazard pointer
*/
template
<
typename
Type
>
class
UniqueHazardPointer
{
public
:
/** Typedef for a atomic pointer to the guarded object. */
typedef
embb
::
base
::
Atomic
<
Type
*>
AtomicTypePtr
;
/**
* Creates an uninitialized, empty wrapper.
*
* An uninitialized wrapper may only be swapped with another wrapper (using
* \c Swap() method) or checked for being active (using 'IsActive()' method,
* which should always return /c false for an uninitialized wrapper).
*/
UniqueHazardPointer
();
/**
* Creates a wrapper that uses the given hazard table entry (referred to as
* "guard") to protect hazardous pointers.
*
* \param[IN] hazard_guard Reference to a hazard table entry
* \param[IN] undefined_guard Dummy value used to clear the hazard table entry
*/
explicit
UniqueHazardPointer
(
AtomicTypePtr
&
hazard_guard
,
Type
*
undefined_guard
=
NULL
);
/**
* If initialized and active, clears the hazard table entry.
*/
~
UniqueHazardPointer
();
/**
* Tries to protect the given hazard using the wrapped guard.
* If it succeeds, the hazard may be safely dereferenced as long as the guard
* is not destroyed or reset to protect another hazard.
*
* \param hazard The hazard to be protected
* \return \c true if the specified hazard is now protected by the guard,
* \c false if the hazard was modified by a concurrent thread
*/
bool
ProtectHazard
(
const
AtomicTypePtr
&
hazard
);
/**
* Uses the wrapped guard to protect a pointer that is not hazardous yet.
*
* \param safe_ptr The pointer to be protected
*/
void
ProtectSafe
(
Type
*
safe_ptr
);
/**
* Type cast operator.
*
* \return The hazardous pointer protected by this wrapper
*/
operator
Type
*
()
const
;
/**
* Pointer member access operator.
*
* \return The hazardous pointer protected by this wrapper
*/
Type
*
operator
->
()
const
;
/**
* Pointer dereference operator.
*
* \return Reference to the object pointed to by the protected pointer
*/
Type
&
operator
*
()
const
;
/**
* Protects the hazard that is currently protected by another wrapper (so it
* becomes protected by two guards simultaneously). The other wrapper remains
* unmodified.
*
* \param other Another wrapper those protected pointer is to be protected by
* the calling wrapper
*/
void
AdoptGuard
(
const
UniqueHazardPointer
&
other
);
/**
* Swaps the guard ownership with another wrapper. Swaps not just the
* protected hazards, but the hazard guards themselves.
*
* \param other Another wrapper to swap guards with
*/
void
Swap
(
UniqueHazardPointer
&
other
);
/**
* Clears the hazard guard and returns the hazard previously protected by that
* guard.
*
* \return The hazardous pointer previously protected by this wrapper
*/
Type
*
ReleaseHazard
();
/**
* Check whether the wrapper is active.
*
* \return \c true if the wrapper is initialized and currently protecting some
* hazard, \c false otherwise
*/
bool
IsActive
()
const
;
private
:
/**
* Sets the 'active' flag of this wrapper.
*
* \param active The new value for the flag
*/
void
SetActive
(
bool
active
);
/**
* Reset the wrapped hazard guard to a state when it is not protecting any
* hazards.
*/
void
ClearHazard
();
/**
* Retrieves the hazardous pointer currently protected by the wrapped guard.
*
* \return The hazardous pointer protected by this wrapper
*/
Type
*
LoadGuardedPointer
()
const
;
/**
* Updates the wrapped guard to protect the specified hazardous pointer.
*
* \param ptr Hazardous pointer to be protected
*/
void
StoreGuardedPointer
(
Type
*
ptr
);
/**
* Check whether the wrapper is initialized (i.e. it wraps some hazard guard)
*
* \return \c true if this wrapper is initialized, \c false otherwise
*/
bool
OwnsHazardGuard
()
const
;
/**
* Disable copy construction and assignment.
*/
UniqueHazardPointer
(
const
UniqueHazardPointer
&
);
UniqueHazardPointer
&
operator
=
(
const
UniqueHazardPointer
&
);
/**
* Pointer to a hazard table entry (the guard) that is used to store the
* hazardous pointers
*/
AtomicTypePtr
*
hazard_guard_
;
/** Dummy value used to clear the hazard guard from any hazards */
Type
*
undefined_guard_
;
/** Flag set to true when the guard is protecting some hazardous pointer */
bool
active_
;
};
}
// namespace internal
}
// namespace containers
}
// namespace embb
...
...
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
View file @
e518a31d
...
...
@@ -44,8 +44,8 @@ namespace internal {
template
<
typename
Key
,
typename
Value
>
ChromaticTreeNode
<
Key
,
Value
>::
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
const
int
weight
,
const
ChildPointer
&
left
,
const
ChildPointer
&
right
)
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Node
*
left
,
Node
*
right
)
:
key_
(
key
),
value_
(
value
),
weight_
(
weight
),
...
...
@@ -55,7 +55,7 @@ ChromaticTreeNode(const Key& key, const Value& value, const int weight,
template
<
typename
Key
,
typename
Value
>
ChromaticTreeNode
<
Key
,
Value
>::
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
const
int
weight
)
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
)
:
key_
(
key
),
value_
(
value
),
weight_
(
weight
),
...
...
@@ -79,18 +79,44 @@ int ChromaticTreeNode<Key, Value>::GetWeight() const {
}
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeNode
<
Key
,
Value
>::
Atomic
ChildPointe
r
&
typename
ChromaticTreeNode
<
Key
,
Value
>::
Atomic
NodePt
r
&
ChromaticTreeNode
<
Key
,
Value
>::
GetLeft
()
{
return
left_
;
}
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeNode
<
Key
,
Value
>::
AtomicChildPointer
&
typename
ChromaticTreeNode
<
Key
,
Value
>::
Node
*
ChromaticTreeNode
<
Key
,
Value
>::
GetLeft
()
const
{
return
left_
.
Load
();
}
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeNode
<
Key
,
Value
>::
AtomicNodePtr
&
ChromaticTreeNode
<
Key
,
Value
>::
GetRight
()
{
return
right_
;
}
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeNode
<
Key
,
Value
>::
Node
*
ChromaticTreeNode
<
Key
,
Value
>::
GetRight
()
const
{
return
right_
.
Load
();
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeNode
<
Key
,
Value
>::
ReplaceChild
(
Node
*
old_child
,
Node
*
new_child
)
{
bool
replaced
=
false
;
if
(
left_
==
old_child
)
{
replaced
=
left_
.
CompareAndSwap
(
old_child
,
new_child
);
}
else
if
(
right_
==
old_child
)
{
replaced
=
right_
.
CompareAndSwap
(
old_child
,
new_child
);
}
return
replaced
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeNode
<
Key
,
Value
>::
Retire
()
{
retired_
=
true
;
}
...
...
@@ -105,133 +131,23 @@ embb::base::Mutex& ChromaticTreeNode<Key, Value>::GetMutex() {
return
mutex_
;
}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
UniqueHazardPointer
()
:
hazard_guard_
(
NULL
),
undefined_guard_
(
NULL
),
active_
(
false
)
{}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
UniqueHazardPointer
(
AtomicGuard
&
hazard_guard
,
GuardedPtr
undefined_guard
)
:
hazard_guard_
(
&
hazard_guard
),
undefined_guard_
(
undefined_guard
),
active_
(
LoadGuardedPointer
()
==
undefined_guard_
)
{}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
~
UniqueHazardPointer
()
{
if
(
IsActive
())
ClearHazard
();
}
template
<
typename
GuardedType
>
bool
UniqueHazardPointer
<
GuardedType
>::
ProtectHazard
(
const
AtomicGuard
&
hazard
)
{
assert
(
OwnsHazardGuard
());
// Read the hazard and store it into the guard
StoreGuardedPointer
(
hazard
.
Load
());
// Check whether the guard is valid
SetActive
(
LoadGuardedPointer
()
==
hazard
.
Load
());
// Clear the guard if it is invalid
if
(
!
IsActive
())
ClearHazard
();
return
IsActive
();
}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
operator
GuardedPtr
()
const
{
assert
(
IsActive
());
return
LoadGuardedPointer
();
}
template
<
typename
GuardedType
>
typename
UniqueHazardPointer
<
GuardedType
>::
GuardedPtr
UniqueHazardPointer
<
GuardedType
>::
operator
->
()
const
{
assert
(
IsActive
());
return
LoadGuardedPointer
();
}
template
<
typename
GuardedType
>
GuardedType
&
UniqueHazardPointer
<
GuardedType
>::
operator
*
()
const
{
assert
(
IsActive
());
return
*
(
LoadGuardedPointer
());
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
AdoptGuard
(
const
UniqueHazardPointer
<
GuardedType
>&
other
)
{
assert
(
OwnsHazardGuard
());
StoreGuardedPointer
(
other
.
LoadGuardedPointer
());
SetActive
(
other
.
active_
);
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
Swap
(
UniqueHazardPointer
<
GuardedType
>&
other
)
{
std
::
swap
(
hazard_guard_
,
other
.
hazard_guard_
);
std
::
swap
(
undefined_guard_
,
other
.
undefined_guard_
);
std
::
swap
(
active_
,
other
.
active_
);
}
template
<
typename
GuardedType
>
typename
UniqueHazardPointer
<
GuardedType
>::
GuardedPtr
UniqueHazardPointer
<
GuardedType
>::
ReleaseHazard
()
{
assert
(
IsActive
());
GuardedPtr
released_hazard
=
LoadGuardedPointer
();
ClearHazard
();
SetActive
(
false
);
return
released_hazard
;
}
template
<
typename
GuardedType
>
bool
UniqueHazardPointer
<
GuardedType
>::
IsActive
()
const
{
return
active_
;
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
SetActive
(
bool
active
)
{
active_
=
active
;
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
ClearHazard
()
{
StoreGuardedPointer
(
undefined_guard_
);
}
template
<
typename
GuardedType
>
typename
UniqueHazardPointer
<
GuardedType
>::
GuardedPtr
UniqueHazardPointer
<
GuardedType
>::
LoadGuardedPointer
()
const
{
return
hazard_guard_
->
Load
();
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
StoreGuardedPointer
(
GuardedPtr
ptr
)
{
hazard_guard_
->
Store
(
ptr
);
}
template
<
typename
GuardedType
>
bool
UniqueHazardPointer
<
GuardedType
>::
OwnsHazardGuard
()
const
{
return
hazard_guard_
!=
NULL
;
}
}
// namespace internal
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
ChromaticTree
(
size_t
capacity
,
Key
undefined_key
,
Value
undefined_value
,
Compare
compare
)
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(push)
#pragma warning(disable:4355)
#endif
:
free_node_callback_
(
*
this
,
&
ChromaticTree
::
FreeNode
),
:
node_hazard_manager_
(
embb
::
base
::
Function
<
void
,
Node
*>
(
*
this
,
&
ChromaticTree
::
FreeNode
),
NULL
,
10
),
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(pop)
#endif
node_hazard_manager_
(
free_node_callback_
,
NULL
,
10
),
undefined_key_
(
undefined_key
),
undefined_value_
(
undefined_value
),
compare_
(
compare
),
...
...
@@ -242,20 +158,20 @@ ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value,
entry_
(
node_pool_
.
Allocate
(
undefined_key_
,
undefined_value_
,
1
,
node_pool_
.
Allocate
(
undefined_key_
,
undefined_value_
),
static_cast
<
Node
Ptr
>
(
NULL
)))
{
static_cast
<
Node
*
>
(
NULL
)))
{
assert
(
entry_
!=
NULL
);
assert
(
entry_
->
GetLeft
()
.
Load
()
!=
NULL
);
assert
(
entry_
->
GetLeft
()
!=
NULL
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
~
ChromaticTree
()
{
Destruct
(
entry_
->
GetLeft
());
FreeNode
(
entry_
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
Get
(
const
Key
&
key
,
Value
&
value
)
{
HazardNodePtr
parent
(
node_hazard_manager_
.
GetGuardedPointer
(
0
));
HazardNodePtr
leaf
(
node_hazard_manager_
.
GetGuardedPointer
(
1
));
...
...
@@ -272,19 +188,19 @@ Get(const Key& key, Value& value) {
return
keys_are_equal
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
TryInsert
(
const
Key
&
key
,
const
Value
&
value
)
{
Value
old_value
;
return
TryInsert
(
key
,
value
,
old_value
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
TryInsert
(
const
Key
&
key
,
const
Value
&
value
,
Value
&
old_value
)
{
Node
Ptr
new_leaf
=
NULL
;
Node
Ptr
new_sibling
=
NULL
;
Node
Ptr
new_parent
=
NULL
;
Node
*
new_leaf
=
NULL
;
Node
*
new_sibling
=
NULL
;
Node
*
new_parent
=
NULL
;
bool
insertion_succeeded
=
false
;
bool
added_violation
=
false
;
...
...
@@ -330,9 +246,7 @@ TryInsert(const Key& key, const Value& value, Value& old_value) {
if
(
new_parent
==
NULL
)
break
;
}
NodePtr
expected
=
leaf
;
insertion_succeeded
=
GetPointerToChild
(
parent
,
leaf
)
.
CompareAndSwap
(
expected
,
new_parent
);
insertion_succeeded
=
parent
->
ReplaceChild
(
leaf
,
new_parent
);
assert
(
insertion_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
insertion_succeeded
)
continue
;
...
...
@@ -353,17 +267,17 @@ TryInsert(const Key& key, const Value& value, Value& old_value) {
return
insertion_succeeded
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
TryDelete
(
const
Key
&
key
)
{
Value
old_value
;
return
TryDelete
(
key
,
old_value
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
TryDelete
(
const
Key
&
key
,
Value
&
old_value
)
{
Node
Ptr
new_leaf
=
NULL
;
Node
*
new_leaf
=
NULL
;
bool
deletion_succeeded
=
false
;
bool
added_violation
=
false
;
...
...
@@ -396,7 +310,7 @@ TryDelete(const Key& key, Value& old_value) {
sibling
.
ProtectHazard
((
parent
->
GetLeft
()
==
leaf
)
?
parent
->
GetRight
()
:
parent
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
sibling
.
IsActive
())
continue
;
VERIFY_ADDRESS
(
static_cast
<
Node
Ptr
>
(
sibling
));
VERIFY_ADDRESS
(
static_cast
<
Node
*
>
(
sibling
));
// Verify that the leaf is still the parent's child
if
(
!
HasChild
(
parent
,
leaf
))
continue
;
...
...
@@ -419,9 +333,7 @@ TryDelete(const Key& key, Value& old_value) {
old_value
=
leaf
->
GetValue
();
NodePtr
expected
=
parent
;
deletion_succeeded
=
GetPointerToChild
(
grandparent
,
parent
)
.
CompareAndSwap
(
expected
,
new_leaf
);
deletion_succeeded
=
grandparent
->
ReplaceChild
(
parent
,
new_leaf
);
assert
(
deletion_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
deletion_succeeded
)
continue
;
...
...
@@ -441,31 +353,31 @@ TryDelete(const Key& key, Value& old_value) {
return
deletion_succeeded
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
size_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
size_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
GetCapacity
()
const
{
return
capacity_
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
const
Value
&
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
GetUndefinedValue
()
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
const
Value
&
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
GetUndefinedValue
()
const
{
return
undefined_value_
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
IsEmpty
()
const
{
return
IsLeaf
(
entry_
->
GetLeft
());
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
Search
(
const
Key
&
key
,
HazardNodePtr
&
leaf
,
HazardNodePtr
&
parent
)
{
bool
reached_leaf
=
false
;
while
(
!
reached_leaf
)
{
parent
.
Protect
Hazard
(
entry_
);
parent
.
Protect
Safe
(
entry_
);
leaf
.
ProtectHazard
(
entry_
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
continue
;
...
...
@@ -475,22 +387,22 @@ Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent) {
leaf
.
ProtectHazard
((
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
break
;
VERIFY_ADDRESS
(
static_cast
<
Node
Ptr
>
(
leaf
));
VERIFY_ADDRESS
(
static_cast
<
Node
*
>
(
leaf
));
reached_leaf
=
IsLeaf
(
leaf
);
}
}
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
Search
(
const
Key
&
key
,
HazardNodePtr
&
leaf
,
HazardNodePtr
&
parent
,
HazardNodePtr
&
grandparent
)
{
bool
reached_leaf
=
false
;
while
(
!
reached_leaf
)
{
grandparent
.
Protect
Hazard
(
entry_
);
parent
.
Protect
Hazard
(
entry_
);
grandparent
.
Protect
Safe
(
entry_
);
parent
.
Protect
Safe
(
entry_
);
leaf
.
ProtectHazard
(
entry_
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
continue
;
...
...
@@ -501,42 +413,34 @@ Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent,
leaf
.
ProtectHazard
((
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
break
;
VERIFY_ADDRESS
(
static_cast
<
Node
Ptr
>
(
leaf
));
VERIFY_ADDRESS
(
static_cast
<
Node
*
>
(
leaf
));
reached_leaf
=
IsLeaf
(
leaf
);
}
}
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
IsLeaf
(
const
Node
Ptr
&
node
)
const
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
IsLeaf
(
const
Node
*
node
)
const
{
return
node
->
GetLeft
()
==
NULL
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
IsSentinel
(
const
Node
Ptr
&
node
)
const
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
IsSentinel
(
const
Node
*
node
)
const
{
return
(
node
==
entry_
)
||
(
node
==
entry_
->
GetLeft
());
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
HasChild
(
const
Node
Ptr
&
parent
,
const
NodePtr
&
child
)
const
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
HasChild
(
const
Node
*
parent
,
const
Node
*
child
)
const
{
return
(
parent
->
GetLeft
()
==
child
||
parent
->
GetRight
()
==
child
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
typename
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
AtomicNodePtr
&
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
GetPointerToChild
(
const
NodePtr
&
parent
,
const
NodePtr
&
child
)
const
{
assert
(
HasChild
(
parent
,
child
));
return
(
parent
->
GetLeft
()
==
child
)
?
parent
->
GetLeft
()
:
parent
->
GetRight
();
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
Destruct
(
const
NodePtr
&
node
)
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
Destruct
(
Node
*
node
)
{
if
(
!
IsLeaf
(
node
))
{
Destruct
(
node
->
GetLeft
());
Destruct
(
node
->
GetRight
());
...
...
@@ -544,9 +448,9 @@ Destruct(const NodePtr& node) {
FreeNode
(
node
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
int
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
GetHeight
(
const
Node
Ptr
&
node
)
const
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
int
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
GetHeight
(
const
Node
*
node
)
const
{
int
height
=
0
;
if
(
node
!=
NULL
)
{
height
=
1
+
::
std
::
max
(
GetHeight
(
node
->
GetLeft
()),
...
...
@@ -555,21 +459,21 @@ GetHeight(const NodePtr& node) const {
return
height
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
IsBalanced
()
const
{
return
IsBalanced
(
entry_
->
GetLeft
());
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
IsBalanced
(
const
Node
Ptr
&
node
)
const
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
IsBalanced
(
const
Node
*
node
)
const
{
// Overweight violation
bool
has_violation
=
node
->
GetWeight
()
>
1
;
if
(
!
has_violation
&&
!
IsLeaf
(
node
))
{
NodePtr
left
=
node
->
GetLeft
();
NodePtr
right
=
node
->
GetRight
();
const
Node
*
left
=
node
->
GetLeft
();
const
Node
*
right
=
node
->
GetRight
();
// Red-red violation
has_violation
=
node
->
GetWeight
()
==
0
&&
...
...
@@ -584,27 +488,27 @@ IsBalanced(const NodePtr& node) const {
return
!
has_violation
;
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
RetireHazardousNode
(
HazardNodePtr
&
node
,
UniqueLock
&
node_lock
)
{
node
->
Retire
();
node_lock
.
Unlock
();
Node
Ptr
node_to_delete
=
node
.
ReleaseHazard
();
Node
*
node_to_delete
=
node
.
ReleaseHazard
();
node_hazard_manager_
.
EnqueuePointerForDeletion
(
node_to_delete
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
FreeNode
(
Node
Ptr
node
)
{
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
FreeNode
(
Node
*
node
)
{
#ifdef EMBB_DEBUG
node
->
GetLeft
()
=
reinterpret_cast
<
Node
Ptr
>
(
INVALID_POINTER
);
node
->
GetRight
()
=
reinterpret_cast
<
Node
Ptr
>
(
INVALID_POINTER
);
node
->
GetLeft
()
=
reinterpret_cast
<
Node
*
>
(
INVALID_POINTER
);
node
->
GetRight
()
=
reinterpret_cast
<
Node
*
>
(
INVALID_POINTER
);
#endif
node_pool_
.
Free
(
node
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
CleanUp
(
const
Key
&
key
)
{
HazardNodePtr
grandgrandparent
(
node_hazard_manager_
.
GetGuardedPointer
(
0
));
HazardNodePtr
grandparent
(
node_hazard_manager_
.
GetGuardedPointer
(
1
));
...
...
@@ -615,9 +519,9 @@ CleanUp(const Key& key) {
while
(
!
reached_leaf
)
{
bool
found_violation
=
false
;
grandgrandparent
.
Protect
Hazard
(
entry_
);
grandparent
.
Protect
Hazard
(
entry_
);
parent
.
Protect
Hazard
(
entry_
);
grandgrandparent
.
Protect
Safe
(
entry_
);
grandparent
.
Protect
Safe
(
entry_
);
parent
.
Protect
Safe
(
entry_
);
leaf
.
ProtectHazard
(
entry_
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
continue
;
...
...
@@ -629,7 +533,7 @@ CleanUp(const Key& key) {
leaf
.
ProtectHazard
((
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
break
;
VERIFY_ADDRESS
(
static_cast
<
Node
Ptr
>
(
leaf
));
VERIFY_ADDRESS
(
static_cast
<
Node
*
>
(
leaf
));
found_violation
=
(
leaf
->
GetWeight
()
>
1
)
||
(
leaf
->
GetWeight
()
==
0
&&
parent
->
GetWeight
()
==
0
);
...
...
@@ -659,10 +563,10 @@ CleanUp(const Key& key) {
HazardNodePtr node(node_hazard_manager_.GetGuardedPointer(h_num)); \
node.ProtectHazard(parent->method()); \
if (parent->IsRetired() || !node.IsActive()) return EMBB_BUSY; \
VERIFY_ADDRESS(static_cast<Node
Ptr
>(node))
VERIFY_ADDRESS(static_cast<Node
*
>(node))
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
embb_errors_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
embb_errors_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
Rebalance
(
HazardNodePtr
&
u
,
HazardNodePtr
&
ux
,
HazardNodePtr
&
uxx
,
HazardNodePtr
&
uxxx
)
{
// Protect node 'u'
...
...
@@ -730,8 +634,8 @@ Rebalance(HazardNodePtr& u, HazardNodePtr& ux, HazardNodePtr& uxx,
}
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
embb_errors_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
embb_errors_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
OverweightLeft
(
HazardNodePtr
&
u
,
UniqueLock
&
u_lock
,
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxx
,
UniqueLock
&
uxx_lock
,
...
...
@@ -876,8 +780,8 @@ OverweightLeft(HazardNodePtr& u, UniqueLock& u_lock,
}
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Nod
ePool
>
embb_errors_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Nod
ePool
>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
Valu
ePool
>
embb_errors_t
ChromaticTree
<
Key
,
Value
,
Compare
,
Valu
ePool
>::
OverweightRight
(
HazardNodePtr
&
u
,
UniqueLock
&
u_lock
,
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxx
,
UniqueLock
&
uxx_lock
,
...
...
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-rebalance.h
View file @
e518a31d
...
...
@@ -37,15 +37,15 @@ embb_errors_t BLK(
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
)
{
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
IsSentinel
(
u
)
?
1
:
ux
->
GetWeight
()
-
1
,
nxl
,
nxr
);
...
...
@@ -59,9 +59,7 @@ embb_errors_t BLK(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -78,15 +76,15 @@ embb_errors_t PUSH_L(
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
)
{
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
0
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
IsSentinel
(
u
)
?
1
:
ux
->
GetWeight
()
+
1
,
nxl
,
nxr
);
...
...
@@ -100,9 +98,7 @@ embb_errors_t PUSH_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -119,15 +115,15 @@ embb_errors_t PUSH_R(
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
)
{
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
0
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
IsSentinel
(
u
)
?
1
:
ux
->
GetWeight
()
+
1
,
nxl
,
nxr
);
...
...
@@ -141,9 +137,7 @@ embb_errors_t PUSH_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -159,11 +153,11 @@ embb_errors_t RB1_L(
HazardNodePtr
&
u
,
UniqueLock
&
u_lock
,
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
)
{
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
0
,
uxl
->
GetRight
(),
ux
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
ux
->
GetWeight
(),
uxl
->
GetLeft
(),
nxr
);
...
...
@@ -175,9 +169,7 @@ embb_errors_t RB1_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -192,11 +184,11 @@ embb_errors_t RB1_R(
HazardNodePtr
&
u
,
UniqueLock
&
u_lock
,
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
)
{
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
0
,
ux
->
GetLeft
(),
uxr
->
GetLeft
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
uxr
->
GetRight
());
...
...
@@ -208,9 +200,7 @@ embb_errors_t RB1_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -226,15 +216,15 @@ embb_errors_t RB2_L(
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxlr
,
UniqueLock
&
uxlr_lock
)
{
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
0
,
uxl
->
GetLeft
(),
uxlr
->
GetLeft
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
0
,
uxlr
->
GetRight
(),
ux
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxlr
->
GetKey
(),
uxlr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -248,9 +238,7 @@ embb_errors_t RB2_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -267,15 +255,15 @@ embb_errors_t RB2_R(
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrl
,
UniqueLock
&
uxrl_lock
)
{
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
0
,
uxrl
->
GetRight
(),
uxr
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
0
,
ux
->
GetLeft
(),
uxrl
->
GetLeft
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxrl
->
GetKey
(),
uxrl
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -289,9 +277,7 @@ embb_errors_t RB2_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -309,19 +295,19 @@ embb_errors_t W1_L(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrl
,
UniqueLock
&
uxrl_lock
)
{
Node
Ptr
nxll
=
node_pool_
.
Allocate
(
Node
*
nxll
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxlr
=
node_pool_
.
Allocate
(
Node
*
nxlr
=
node_pool_
.
Allocate
(
uxrl
->
GetKey
(),
uxrl
->
GetValue
(),
uxrl
->
GetWeight
()
-
1
,
uxrl
->
GetLeft
(),
uxrl
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxll
,
nxlr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
uxr
->
GetRight
());
...
...
@@ -337,9 +323,7 @@ embb_errors_t W1_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -358,19 +342,19 @@ embb_errors_t W1_R(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxlr
,
UniqueLock
&
uxlr_lock
)
{
Node
Ptr
nxrr
=
node_pool_
.
Allocate
(
Node
*
nxrr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxrl
=
node_pool_
.
Allocate
(
Node
*
nxrl
=
node_pool_
.
Allocate
(
uxlr
->
GetKey
(),
uxlr
->
GetValue
(),
uxlr
->
GetWeight
()
-
1
,
uxlr
->
GetLeft
(),
uxlr
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxrl
,
nxrr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
ux
->
GetWeight
(),
uxl
->
GetLeft
(),
nxr
);
...
...
@@ -386,9 +370,7 @@ embb_errors_t W1_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -407,19 +389,19 @@ embb_errors_t W2_L(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrl
,
UniqueLock
&
uxrl_lock
)
{
Node
Ptr
nxll
=
node_pool_
.
Allocate
(
Node
*
nxll
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxlr
=
node_pool_
.
Allocate
(
Node
*
nxlr
=
node_pool_
.
Allocate
(
uxrl
->
GetKey
(),
uxrl
->
GetValue
(),
0
,
uxrl
->
GetLeft
(),
uxrl
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxll
,
nxlr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
uxr
->
GetRight
());
...
...
@@ -435,9 +417,7 @@ embb_errors_t W2_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -456,19 +436,19 @@ embb_errors_t W2_R(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxlr
,
UniqueLock
&
uxlr_lock
)
{
Node
Ptr
nxrr
=
node_pool_
.
Allocate
(
Node
*
nxrr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxrl
=
node_pool_
.
Allocate
(
Node
*
nxrl
=
node_pool_
.
Allocate
(
uxlr
->
GetKey
(),
uxlr
->
GetValue
(),
0
,
uxlr
->
GetLeft
(),
uxlr
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxrl
,
nxrr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
ux
->
GetWeight
(),
uxl
->
GetLeft
(),
nxr
);
...
...
@@ -484,9 +464,7 @@ embb_errors_t W2_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -506,23 +484,23 @@ embb_errors_t W3_L(
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrl
,
UniqueLock
&
uxrl_lock
,
HazardNodePtr
&
uxrll
,
UniqueLock
&
uxrll_lock
)
{
Node
Ptr
nxlll
=
node_pool_
.
Allocate
(
Node
*
nxlll
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxll
=
node_pool_
.
Allocate
(
Node
*
nxll
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxlll
,
uxrll
->
GetLeft
());
Node
Ptr
nxlr
=
node_pool_
.
Allocate
(
Node
*
nxlr
=
node_pool_
.
Allocate
(
uxrl
->
GetKey
(),
uxrl
->
GetValue
(),
1
,
uxrll
->
GetRight
(),
uxrl
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxrll
->
GetKey
(),
uxrll
->
GetValue
(),
0
,
nxll
,
nxlr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
uxr
->
GetRight
());
...
...
@@ -540,9 +518,7 @@ embb_errors_t W3_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -563,23 +539,23 @@ embb_errors_t W3_R(
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxlr
,
UniqueLock
&
uxlr_lock
,
HazardNodePtr
&
uxlrr
,
UniqueLock
&
uxlrr_lock
)
{
Node
Ptr
nxrrr
=
node_pool_
.
Allocate
(
Node
*
nxrrr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxrr
=
node_pool_
.
Allocate
(
Node
*
nxrr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
uxlrr
->
GetRight
(),
nxrrr
);
Node
Ptr
nxrl
=
node_pool_
.
Allocate
(
Node
*
nxrl
=
node_pool_
.
Allocate
(
uxlr
->
GetKey
(),
uxlr
->
GetValue
(),
1
,
uxlr
->
GetLeft
(),
uxlrr
->
GetLeft
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxlrr
->
GetKey
(),
uxlrr
->
GetValue
(),
0
,
nxrl
,
nxrr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
ux
->
GetWeight
(),
uxl
->
GetLeft
(),
nxr
);
...
...
@@ -597,9 +573,7 @@ embb_errors_t W3_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -620,23 +594,23 @@ embb_errors_t W4_L(
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrl
,
UniqueLock
&
uxrl_lock
,
HazardNodePtr
&
uxrlr
,
UniqueLock
&
uxrlr_lock
)
{
Node
Ptr
nxll
=
node_pool_
.
Allocate
(
Node
*
nxll
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxrl
=
node_pool_
.
Allocate
(
Node
*
nxrl
=
node_pool_
.
Allocate
(
uxrlr
->
GetKey
(),
uxrlr
->
GetValue
(),
1
,
uxrlr
->
GetLeft
(),
uxrlr
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxll
,
uxrl
->
GetLeft
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
0
,
nxrl
,
uxr
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxrl
->
GetKey
(),
uxrl
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -654,9 +628,7 @@ embb_errors_t W4_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -677,23 +649,23 @@ embb_errors_t W4_R(
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxlr
,
UniqueLock
&
uxlr_lock
,
HazardNodePtr
&
uxlrl
,
UniqueLock
&
uxlrl_lock
)
{
Node
Ptr
nxrr
=
node_pool_
.
Allocate
(
Node
*
nxrr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxlr
=
node_pool_
.
Allocate
(
Node
*
nxlr
=
node_pool_
.
Allocate
(
uxlrl
->
GetKey
(),
uxlrl
->
GetValue
(),
1
,
uxlrl
->
GetLeft
(),
uxlrl
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
uxlr
->
GetRight
(),
nxrr
);
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
0
,
uxl
->
GetLeft
(),
nxlr
);
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxlr
->
GetKey
(),
uxlr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -711,9 +683,7 @@ embb_errors_t W4_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -733,19 +703,19 @@ embb_errors_t W5_L(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrr
,
UniqueLock
&
uxrr_lock
)
{
Node
Ptr
nxll
=
node_pool_
.
Allocate
(
Node
*
nxll
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxll
,
uxr
->
GetLeft
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxrr
->
GetKey
(),
uxrr
->
GetValue
(),
1
,
uxrr
->
GetLeft
(),
uxrr
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -761,9 +731,7 @@ embb_errors_t W5_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -782,19 +750,19 @@ embb_errors_t W5_R(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxll
,
UniqueLock
&
uxll_lock
)
{
Node
Ptr
nxrr
=
node_pool_
.
Allocate
(
Node
*
nxrr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
uxl
->
GetRight
(),
nxrr
);
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxll
->
GetKey
(),
uxll
->
GetValue
(),
1
,
uxll
->
GetLeft
(),
uxll
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -810,9 +778,7 @@ embb_errors_t W5_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -831,19 +797,19 @@ embb_errors_t W6_L(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxrl
,
UniqueLock
&
uxrl_lock
)
{
Node
Ptr
nxll
=
node_pool_
.
Allocate
(
Node
*
nxll
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
nxll
,
uxrl
->
GetLeft
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
1
,
uxrl
->
GetRight
(),
uxr
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxrl
->
GetKey
(),
uxrl
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -859,9 +825,7 @@ embb_errors_t W6_L(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -880,19 +844,19 @@ embb_errors_t W6_R(
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
,
HazardNodePtr
&
uxlr
,
UniqueLock
&
uxlr_lock
)
{
Node
Ptr
nxrr
=
node_pool_
.
Allocate
(
Node
*
nxrr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
1
,
uxlr
->
GetRight
(),
nxrr
);
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
1
,
uxl
->
GetLeft
(),
uxlr
->
GetLeft
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
uxlr
->
GetKey
(),
uxlr
->
GetValue
(),
ux
->
GetWeight
(),
nxl
,
nxr
);
...
...
@@ -908,9 +872,7 @@ embb_errors_t W6_R(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
@@ -928,15 +890,15 @@ embb_errors_t W7(
HazardNodePtr
&
ux
,
UniqueLock
&
ux_lock
,
HazardNodePtr
&
uxl
,
UniqueLock
&
uxl_lock
,
HazardNodePtr
&
uxr
,
UniqueLock
&
uxr_lock
)
{
Node
Ptr
nxl
=
node_pool_
.
Allocate
(
Node
*
nxl
=
node_pool_
.
Allocate
(
uxl
->
GetKey
(),
uxl
->
GetValue
(),
uxl
->
GetWeight
()
-
1
,
uxl
->
GetLeft
(),
uxl
->
GetRight
());
Node
Ptr
nxr
=
node_pool_
.
Allocate
(
Node
*
nxr
=
node_pool_
.
Allocate
(
uxr
->
GetKey
(),
uxr
->
GetValue
(),
uxr
->
GetWeight
()
-
1
,
uxr
->
GetLeft
(),
uxr
->
GetRight
());
Node
Ptr
nx
=
node_pool_
.
Allocate
(
Node
*
nx
=
node_pool_
.
Allocate
(
ux
->
GetKey
(),
ux
->
GetValue
(),
IsSentinel
(
u
)
?
1
:
ux
->
GetWeight
()
+
1
,
nxl
,
nxr
);
...
...
@@ -950,9 +912,7 @@ embb_errors_t W7(
return
EMBB_NOMEM
;
}
NodePtr
expected
=
ux
;
bool
rotation_succeeded
=
GetPointerToChild
(
u
,
ux
)
.
CompareAndSwap
(
expected
,
nx
);
bool
rotation_succeeded
=
u
->
ReplaceChild
(
ux
,
nx
);
assert
(
rotation_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
rotation_succeeded
)
return
EMBB_BUSY
;
...
...
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
View file @
e518a31d
...
...
@@ -50,8 +50,8 @@ namespace internal {
template
<
typename
Key
,
typename
Value
>
class
ChromaticTreeNode
{
public
:
typedef
ChromaticTreeNode
<
Key
,
Value
>
*
ChildPointer
;
typedef
embb
::
base
::
Atomic
<
ChildPointer
>
AtomicChildPointe
r
;
typedef
ChromaticTreeNode
<
Key
,
Value
>
Node
;
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePt
r
;
/**
* Creates a node with given parameters.
...
...
@@ -62,8 +62,8 @@ class ChromaticTreeNode {
* \param[IN] left Pointer to the left child node
* \param[IN] right Pointer to the right child node
*/
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
const
int
weight
,
const
ChildPointer
&
left
,
const
ChildPointer
&
right
);
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Node
*
left
,
Node
*
right
);
/**
* Creates a node given only a key-value pair. Node will have no child nodes
...
...
@@ -73,7 +73,7 @@ class ChromaticTreeNode {
* \param[IN] value Value of the new node
* \param[IN] weight Weight of the new node
*/
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
const
int
weight
=
1
);
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
=
1
);
/**
* Accessor for the stored key.
...
...
@@ -101,14 +101,30 @@ class ChromaticTreeNode {
*
* \return Reference to the left child pointer
*/
AtomicChildPointer
&
GetLeft
();
AtomicNodePtr
&
GetLeft
();
Node
*
GetLeft
()
const
;
/**
* Accessor for the right child pointer.
*
* \return Reference to the right child pointer
*/
AtomicChildPointer
&
GetRight
();
AtomicNodePtr
&
GetRight
();
Node
*
GetRight
()
const
;
/**
* Tries to replace one of the child pointers that compares equal to
* \c old_child with the \c new_child using an atomic compare-and-swap
* operation. If neither left nor right child pointer is pointing to
* \c old_child, returns \c false.
*
* \param old_child[IN] Pointer to an old child node to compare against
* \param new_child[IN] Pointer to the new child node
*
* \return \c true if one of the child pointers is now pointing to
* \c new_child, \c false otherwise
*/
bool
ReplaceChild
(
Node
*
old_child
,
Node
*
new_child
);
/**
* Marks node for deletion from the tree
...
...
@@ -136,183 +152,16 @@ class ChromaticTreeNode {
ChromaticTreeNode
(
const
ChromaticTreeNode
&
);
ChromaticTreeNode
&
operator
=
(
const
ChromaticTreeNode
&
);
const
Key
key_
;
/**< Stored key */
const
Value
value_
;
/**< Stored value */
const
int
weight_
;
/**< Weight of the node */
Atomic
ChildPointer
left_
;
/**< Pointer to left child node */
Atomic
ChildPointer
right_
;
/**< Pointer to right child node */
const
Key
key_
;
/**< Stored key */
const
Value
value_
;
/**< Stored value */
const
int
weight_
;
/**< Weight of the node */
Atomic
NodePtr
left_
;
/**< Pointer to left child node */
Atomic
NodePtr
right_
;
/**< Pointer to right child node */
embb
::
base
::
Atomic
<
bool
>
retired_
;
/**< Retired (marked for deletion) flag */
embb
::
base
::
Mutex
mutex_
;
/**< Fine-grained locking tree: per node mutex */
};
/**
* Ownership wrapper for a hazard pointer
*
* Uses an entry of the hazard table to provide protection for a single
* hazardous pointer. While providing standard pointer dereference and member
* access operators, it requires special care for pointer assignment (realized
* via 'ProtectHazard' method).
* On destruction, it clears the wrapped hazard table entry, releasing the
* protected hazardous pointer (if any).
*
* \tparam GuardedType Type of the object to be protected by the hazard pointer
*/
template
<
typename
GuardedType
>
class
UniqueHazardPointer
{
public
:
/**
* Typedef for a pointer to the guarded object.
*/
typedef
GuardedType
*
GuardedPtr
;
/**
* Typedef for a atomic pointer to the guarded object.
*/
typedef
embb
::
base
::
Atomic
<
GuardedPtr
>
AtomicGuard
;
/**
* Creates an uninitialized, empty wrapper.
*
* An uninitialized wrapper may only be swapped with another wrapper (using
* \c Swap() method) or checked for being active (using 'IsActive()' method,
* which should always return /c false for an uninitialized wrapper).
*/
UniqueHazardPointer
();
/**
* Creates a wrapper that uses the given hazard table entry (referred to as
* "guard") to protect hazardous pointers.
*
* \param[IN] hazard_guard Reference to a hazard table entry
* \param[IN] undefined_guard Dummy value used to clear the hazard table entry
*/
explicit
UniqueHazardPointer
(
AtomicGuard
&
hazard_guard
,
GuardedPtr
undefined_guard
=
NULL
);
/**
* If initialized and active, clears the hazard table entry.
*/
~
UniqueHazardPointer
();
/**
* Tries to protect the given hazard using the wrapped hazard pointer (guard).
* If it succeeds, the hazard may be safely dereferenced as long as the guard
* is not destroyed or reset to protect another hazard.
*
* \param hazard The hazard to be protected
* \return \c true if the specified hazard is now protected by the guard,
* \c false if the hazard was modified by a concurrent thread
*/
bool
ProtectHazard
(
const
AtomicGuard
&
hazard
);
/**
* Type cast operator.
*
* \return The hazardous pointer protected by this wrapper
*/
operator
GuardedPtr
()
const
;
/**
* Pointer member access operator.
*
* \return The hazardous pointer protected by this wrapper
*/
GuardedPtr
operator
->
()
const
;
/**
* Pointer dereference operator.
*
* \return Reference to the object pointed to by the protected pointer
*/
GuardedType
&
operator
*
()
const
;
/**
* Protects the hazard that is currently protected by another wrapper (so it
* becomes protected by two guards simultaneously). The other wrapper remains
* unmodified.
*
* \param other Another wrapper those protected pointer is to be protected by
* the calling wrapper
*/
void
AdoptGuard
(
const
UniqueHazardPointer
<
GuardedType
>&
other
);
/**
* Swaps the guard ownership with another wrapper. Swaps not just the
* protected hazards, but the hazard guards themselves.
*
* \param other Another wrapper to swap guards with
*/
void
Swap
(
UniqueHazardPointer
<
GuardedType
>&
other
);
/**
* Clears the hazard guard and returns the hazard previously protected by that
* guard.
*
* \return The hazardous pointer previously protected by this wrapper
*/
GuardedPtr
ReleaseHazard
();
/**
* Check whether the wrapper is active.
*
* \return \c true if the wrapper is initialized and currently protecting some
* hazard, \c false otherwise
*/
bool
IsActive
()
const
;
private
:
/**
* Sets the 'active' flag of this wrapper.
*
* \param active The new value for the flag
*/
void
SetActive
(
bool
active
);
/**
* Reset the wrapped hazard guard to a state when it is not protecting any
* hazards.
*/
void
ClearHazard
();
/**
* Retrieves the hazardous pointer currently protected by the wrapped guard.
*
* \return The hazardous pointer protected by this wrapper
*/
GuardedPtr
LoadGuardedPointer
()
const
;
/**
* Updates the wrapped guard to protect the specified hazardous pointer.
*
* \param ptr Hazardous pointer to be protected
*/
void
StoreGuardedPointer
(
GuardedPtr
ptr
);
/**
* Check whether the wrapper is initialized (i.e. it wraps some hazard guard)
*
* \return \c true if this wrapper is initialized, \c false otherwise
*/
bool
OwnsHazardGuard
()
const
;
/**
* Disable copy construction and assignment.
*/
UniqueHazardPointer
(
const
UniqueHazardPointer
&
);
UniqueHazardPointer
&
operator
=
(
const
UniqueHazardPointer
&
);
/**
* Pointer to a hazard table entry (the guard) that is used to store the
* hazardous pointers
*/
AtomicGuard
*
hazard_guard_
;
/** Dummy value used to clear the hazard guard from any hazards */
GuardedPtr
undefined_guard_
;
/** Flag set to true when the guard is protecting some hazardous pointer */
bool
active_
;
};
}
// namespace internal
namespace
test
{
...
...
@@ -330,20 +179,19 @@ class TreeTest;
* Implements a balanced BST with support for \c Get, \c Insert and \c Delete
* operations.
*
* \tparam Key Key type
* \tparam Value Value type
* \tparam Compare Custom comparator type for the keys. An object of the
* type \c Compare must must be a functor taking two
* arguments \c rhs and \c lhs of type \c Key and
* returning \c true if and only if <tt>(rhs < lhs)</tt> holds
* \tparam
NodePool The object pool type used for allocation/deallocation
*
of tree node
s.
* \tparam Key
Key type
* \tparam Value
Value type
* \tparam Compare
Custom comparator type for the keys. An object of the
*
type \c Compare must must be a functor taking two
*
arguments \c rhs and \c lhs of type \c Key and
*
returning \c true if and only if <tt>(rhs < lhs)</tt> holds
* \tparam
ValuePool Type of the value pool to be used inside object pools for
*
tree nodes and operation object
s.
*/
template
<
typename
Key
,
typename
Value
,
typename
Compare
=
::
std
::
less
<
Key
>
,
typename
NodePool
=
ObjectPool
<
internal
::
ChromaticTreeNode
<
Key
,
Value
>
,
LockFreeTreeValuePool
<
bool
,
false
>
>
typename
ValuePool
=
LockFreeTreeValuePool
<
bool
,
false
>
>
class
ChromaticTree
{
public
:
...
...
@@ -465,7 +313,7 @@ class ChromaticTree {
*
* \return Object of type \c Value that is used by the tree as a dummy value
*/
const
Value
&
GetUndefinedValue
();
const
Value
&
GetUndefinedValue
()
const
;
/**
* Checks whether the tree is currently empty.
...
...
@@ -475,26 +323,16 @@ class ChromaticTree {
bool
IsEmpty
()
const
;
private
:
/**
* Typedef for a node of the tree.
*/
/** Typedef for a node of the tree. */
typedef
internal
::
ChromaticTreeNode
<
Key
,
Value
>
Node
;
/**
* Typedef for a pointer to a node of the tree.
*/
typedef
internal
::
ChromaticTreeNode
<
Key
,
Value
>*
NodePtr
;
/**
* Typedef for an atomic pointer to a node of the tree.
*/
typedef
embb
::
base
::
Atomic
<
NodePtr
>
AtomicNodePtr
;
/**
* Typedef for an pointer to a node protected by a Hazard Pointer.
*/
/** Typedef for an atomic pointer to a node of the tree. */
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
/** Typedef for an pointer to a node protected by a Hazard Pointer. */
typedef
internal
::
UniqueHazardPointer
<
Node
>
HazardNodePtr
;
/**
* Typedef for the UniqueLock class.
*/
/** Typedef for the UniqueLock class. */
typedef
embb
::
base
::
UniqueLock
<
embb
::
base
::
Mutex
>
UniqueLock
;
/** Typedef for an object pool for tree nodes. */
typedef
ObjectPool
<
Node
,
ValuePool
>
NodePool
;
/**
...
...
@@ -528,7 +366,7 @@ class ChromaticTree {
*
* \return \c true if the given node is a leaf, \c false otherwise
*/
bool
IsLeaf
(
const
Node
Ptr
&
node
)
const
;
bool
IsLeaf
(
const
Node
*
node
)
const
;
/**
* Checks whether the given node is a sentinel node.
...
...
@@ -537,7 +375,7 @@ class ChromaticTree {
*
* \return \c true if the given node is a sentinel node, \c false otherwise
*/
bool
IsSentinel
(
const
Node
Ptr
&
node
)
const
;
bool
IsSentinel
(
const
Node
*
node
)
const
;
/**
* Checks whether the given node has a specified child node.
...
...
@@ -548,22 +386,8 @@ class ChromaticTree {
* \return \c true if \c child is a child node of \c parent, \c false
* otherwise
*/
bool
HasChild
(
const
NodePtr
&
parent
,
const
NodePtr
&
child
)
const
;
/**
* Accessor for the child pointer of a given parent to the specified child.
*
* \pre The \c child has to be an actual child of the \c parent.
*
* \param[IN] parent Parent node
* \param[IN] child Child node of the \c parent
*
* \return Reference to a member pointer of the \c parent that points to
* the \c child
*/
AtomicNodePtr
&
GetPointerToChild
(
const
NodePtr
&
parent
,
const
NodePtr
&
child
)
const
;
bool
HasChild
(
const
Node
*
parent
,
const
Node
*
child
)
const
;
/**
* Destroys all the nodes of a subtree rooted at the given node, including the
* node itself.
...
...
@@ -572,7 +396,7 @@ class ChromaticTree {
*
* \param node Root of the subtree to be destroyed
*/
void
Destruct
(
const
NodePtr
&
node
);
void
Destruct
(
Node
*
node
);
/**
* Computes the hight of the subtree rooted at the given node.
...
...
@@ -584,7 +408,7 @@ class ChromaticTree {
* \return The height of a subtree rooted at node \c node. (The height of a
* leaf node is defined to be zero).
*/
int
GetHeight
(
const
Node
Ptr
&
node
)
const
;
int
GetHeight
(
const
Node
*
node
)
const
;
/**
* Check whether the tree is currently in a balanced state (if it is a valid
...
...
@@ -601,7 +425,7 @@ class ChromaticTree {
*
* \return \c true if the tree is balanced, \c false otherwise
*/
bool
IsBalanced
(
const
Node
Ptr
&
node
)
const
;
bool
IsBalanced
(
const
Node
*
node
)
const
;
/**
* Free a tree node using the Hazard Pointers memory reclamation routines.
...
...
@@ -616,7 +440,7 @@ class ChromaticTree {
*
* \param[IN] node A node to be freed.
*/
void
FreeNode
(
Node
Ptr
node
);
void
FreeNode
(
Node
*
node
);
/**
* Follows the path from the root to some leaf (directed by the given key) and
...
...
@@ -654,23 +478,21 @@ class ChromaticTree {
// directly inside the class definition.
# include <embb/containers/internal/lock_free_chromatic_tree-rebalance.h>
/** Callback functor for the hazard pointer that frees retired nodes */
embb
::
base
::
Function
<
void
,
NodePtr
>
free_node_callback_
;
/** Hazard pointer instance for protection of node pointers */
embb
::
containers
::
internal
::
HazardPointer
<
NodePtr
>
node_hazard_manager_
;
internal
::
HazardPointer
<
Node
*
>
node_hazard_manager_
;
const
Key
undefined_key_
;
/**< A dummy key used by the tree */
const
Value
undefined_value_
;
/**< A dummy value used by the tree */
const
Compare
compare_
;
/**< Comparator object for the keys */
size_t
capacity_
;
/**< User-requested capacity of the tree */
NodePool
node_pool_
;
/**< Comparator object for the keys */
const
AtomicNodePtr
entry_
;
/**< Pointer to the sentinel node used as
Node
*
const
entry_
;
/**< Pointer to the sentinel node used as
* the entry point into the tree */
/**
* Friending the test class for white-box testing
*/
friend
class
test
::
TreeTest
<
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>
>
;
friend
class
test
::
TreeTest
<
ChromaticTree
>
;
};
}
// namespace containers
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment