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
b3b79150
authored
Mar 26, 2015
by
Tobias Fuchs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
containers_cpp: implementing Multiset, extended LLX/SCX interface
parent
5e44f597
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
178 additions
and
39 deletions
+178
-39
containers_cpp/include/embb/containers/internal/multiset-inl.h
+49
-26
containers_cpp/include/embb/containers/internal/primitives/llx_scx-inl.h
+18
-0
containers_cpp/include/embb/containers/multiset.h
+76
-9
containers_cpp/include/embb/containers/primitives/llx_scx.h
+29
-0
containers_cpp/test/main.cc
+3
-3
containers_cpp/test/multiset_test.cc
+3
-1
No files found.
containers_cpp/include/embb/containers/internal/multiset-inl.h
View file @
b3b79150
...
...
@@ -37,42 +37,69 @@ namespace containers {
namespace
internal
{
template
<
typename
Type
>
MultisetNode
<
Type
>::
MultisetNode
(
const
Type
&
key
,
size_t
count
,
node_ptr_t
next
)
:
inline
MultisetNode
<
Type
>::
MultisetNode
()
:
key_
()
{
count_
.
Store
(
0
);
next_
.
Store
(
0
);
}
template
<
typename
Type
>
inline
MultisetNode
<
Type
>::
MultisetNode
(
const
Type
&
key
,
size_t
count
,
node_ptr_t
next
)
:
key_
(
key
),
count_
(
count
),
next_
(
next
)
{
}
template
<
typename
Type
>
inline
MultisetNode
<
Type
>::
MultisetNode
(
const
MultisetNode
<
Type
>
&
other
)
:
key_
(
other
.
key_
)
{
count_
.
Store
(
other
.
count_
.
Load
());
next_
.
Store
(
other
.
next_
.
Load
());
}
template
<
typename
Type
>
inline
MultisetNode
<
Type
>
&
MultisetNode
<
Type
>::
operator
=
(
MultisetNode
<
Type
>
&
rhs
)
{
key_
=
rhs
.
key_
;
count_
.
Store
(
rhs
.
count_
.
Load
());
next_
.
Store
(
rhs
.
next_
.
Load
());
}
template
<
typename
Type
>
inline
Type
&
MultisetNode
<
Type
>::
Key
()
const
{
return
key_
;
}
template
<
typename
Type
>
inline
embb
::
base
::
Atomic
<
size_t
>
&
MultisetNode
<
Type
>::
Count
()
{
return
count_
;
inline
embb
::
base
::
Atomic
<
size_t
>
*
MultisetNode
<
Type
>::
Count
()
{
return
&
count_
;
}
template
<
typename
Type
>
inline
embb
::
base
::
Atomic
<
node_ptr_t
>
&
MultisetNode
<
Type
>::
Next
()
{
return
next_
;
inline
embb
::
base
::
Atomic
<
primitives
::
LlxScxRecord
<
internal
::
MultisetNode
<
Type
>
>
*
>
*
MultisetNode
<
Type
>::
Next
()
{
return
&
next_
;
}
}
// namespace internal
template
<
typename
Type
,
Type
UndefinedKey
,
class
ValuePool
>
Multiset
<
Type
,
UndefinedKey
,
ValuePool
>::
Multiset
(
size_t
capacity
)
:
node_pool_
(
capacity
),
llx_scx_
(
NUM_LLX_SCX_LINKS
)
{
internal
::
MultisetNode
<
Type
>
sentinel_node
(
UndefinedKey
,
0
,
UNDEFINED_POINTER
);
head_
=
node_pool_
.
Allocate
(
sentinel_node
);
tail_
=
node_pool_
.
Allocate
(
sentinel_node
);
head_
->
Next
().
Store
(
tail_
);
tail_
->
Next
().
Store
(
UNDEFINED_POINTER
);
(
*
head_
)
->
Next
()
->
Store
(
tail_
);
(
*
tail_
)
->
Next
()
->
Store
(
UNDEFINED_POINTER
);
}
template
<
typename
Type
,
Type
UndefinedKey
,
class
ValuePool
>
bool
Multiset
<
Type
,
UndefinedKey
,
ValuePool
>::
Search
(
const
Type
key
,
node_ptr_t
&
node
,
node_ptr_t
&
next
)
{
primitives
::
LlxScxRecord
<
internal
::
MultisetNode
<
Type
>
>
*
&
node
,
primitives
::
LlxScxRecord
<
internal
::
MultisetNode
<
Type
>
>
*
&
next
)
{
node
=
head_
;
next
=
tail_
;
while
(
key
>
next
->
Key
()
&&
next
->
Key
()
!=
UndefinedKey
)
{
...
...
@@ -86,7 +113,7 @@ template< typename Type, Type UndefinedKey, class ValuePool >
size_t
Multiset
<
Type
,
UndefinedKey
,
ValuePool
>::
Get
(
Type
key
)
{
node_ptr_t
node
,
next
;
if
(
Search
(
key
,
node
,
next
))
{
return
next
->
Count
().
Load
();
return
(
*
next
)
->
Count
()
->
Load
();
}
return
0
;
}
...
...
@@ -96,39 +123,37 @@ void Multiset<Type, UndefinedKey, ValuePool>::Insert(Type key, size_t count) {
if
(
count
==
0
)
{
return
;
}
while
(
true
)
{
for
(;;
)
{
node_ptr_t
node
,
next
,
local_next
;
Search
(
key
,
node
,
next
);
// Key value is stored in node->next as head node
// is sentinel.
if
(
key
==
next
->
Key
())
{
if
(
key
==
(
*
next
)
->
Key
())
{
node_ptr_t
local_next
;
// Key already present in multiset, increment count of its node:
// LLX(r:next)
if
(
llx_scx_
.
TryLoadLinked
(
next
,
local_next
))
{
if
(
llx_scx_
.
TryLoadLinked
(
next
,
*
local_next
))
{
internal
::
FixedSizeList
<
node_ptr_t
>
linked_deps
(
1
);
linked_deps
.
PushBack
(
next
);
// SCX(fld:next->count, value:next->count + count, V:<next>);
if
(
llx_scx_
.
TryStoreConditional
(
next
->
Count
(),
local_next
->
Count
()
->
Load
()
+
count
,
(
*
next
)
->
Count
(),
(
*
local_next
)
->
Count
()
->
Load
()
+
count
,
linked_deps
))
{
return
;
}
}
}
else
{
}
else
{
// Key not present in multiset yet, add node:
node_ptr_t
local_node
;
if
(
llx_scx_
.
TryLoadLinked
(
node
,
local_node
)
&&
next
==
local_node
->
Next
())
{
if
(
llx_scx_
.
TryLoadLinked
(
node
,
local_node
)
&&
next
==
(
*
local_node
)
->
Next
())
{
internal
::
FixedSizeList
<
node_ptr_t
>
linked_deps
(
1
);
linked_deps
.
PushBack
(
node
);
node_t
new_node
(
internal
::
MultisetNode
<
Type
>
(
key
,
count
,
next
));
node_ptr_t
new_node_ptr
=
node_pool_
.
Allocate
(
new_node
);
if
(
llx_scx_
.
TryStoreConditional
(
node
->
Next
(),
new_node_ptr
,
linked_deps
))
{
return
;
}
else
{
}
else
{
// Insert failed, return new node object to pool:
node_pool_
.
Free
(
new_node_ptr
);
}
...
...
@@ -142,7 +167,7 @@ bool Multiset<Type, UndefinedKey, ValuePool>::TryDelete(Type key, size_t count)
if
(
count
==
0
)
{
return
false
;
}
while
(
true
)
{
for
(;;
)
{
node_ptr_t
node
,
next
,
local_node
,
local_next
;
Search
(
key
,
node
,
next
);
if
(
llx_scx_
.
TryLoadLinked
(
node
,
local_node
)
&&
...
...
@@ -152,8 +177,7 @@ bool Multiset<Type, UndefinedKey, ValuePool>::TryDelete(Type key, size_t count)
// Key not present in multiset or existing count less
// than amount of elements requested for deletion:
return
false
;
}
else
if
(
local_next
->
Count
()
>
count
)
{
}
else
if
(
local_next
->
Count
()
>
count
)
{
// Inserting a new node with decremented count instead
// of decrementing the exising node's count to reduce
// number of linked dependencies in SCX.
...
...
@@ -167,8 +191,7 @@ bool Multiset<Type, UndefinedKey, ValuePool>::TryDelete(Type key, size_t count)
node
->
Next
(),
new_node_ptr
,
linked_deps
,
finalize_deps
))
{
return
true
;
}
}
else
{
}
else
{
assert
(
local_next
->
Count
()
==
count
);
node_ptr_t
local_next_next
;
if
(
llx_scx_
.
TryLoadLinked
(
next
->
Next
(),
local_next_next
))
{
...
...
@@ -181,7 +204,7 @@ bool Multiset<Type, UndefinedKey, ValuePool>::TryDelete(Type key, size_t count)
finalize_deps
.
PushBack
(
next
);
finalize_deps
.
PushBack
(
local_next_next
);
if
(
llx_scx_
.
TryStoreConditional
(
node
->
Next
(),
new_next_next_ptr
,
linked_deps
,
finalize_deps
)
{
node
->
Next
(),
new_next_next_ptr
,
linked_deps
,
finalize_deps
)
)
{
return
true
;
}
else
{
...
...
containers_cpp/include/embb/containers/internal/primitives/llx_scx-inl.h
View file @
b3b79150
...
...
@@ -130,6 +130,14 @@ bool LlxScx<UserData, ValuePool>::TryLoadLinked(
}
template
<
typename
UserData
,
typename
ValuePool
>
bool
LlxScx
<
UserData
,
ValuePool
>::
TryLoadLinked
(
DataRecord_t
*
const
data_record
,
DataRecord_t
&
user_data
)
{
bool
finalized
;
return
TryLoadLinked
(
data_record
,
user_data
,
finalized
);
}
template
<
typename
UserData
,
typename
ValuePool
>
template
<
typename
FieldType
>
bool
LlxScx
<
UserData
,
ValuePool
>::
TryStoreConditional
(
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
...
...
@@ -191,6 +199,16 @@ bool LlxScx<UserData, ValuePool>::TryStoreConditional(
}
template
<
typename
UserData
,
typename
ValuePool
>
template
<
typename
FieldType
>
bool
LlxScx
<
UserData
,
ValuePool
>::
TryStoreConditional
(
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
FieldType
value
,
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
&
linked_deps
)
{
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
finalize_deps
(
0
);
return
TryStoreConditional
(
field
,
value
,
linked_deps
,
finalize_deps
);
}
template
<
typename
UserData
,
typename
ValuePool
>
bool
LlxScx
<
UserData
,
ValuePool
>::
TryValidateLink
(
const
DataRecord_t
&
field
)
{
return
true
;
// @TODO
...
...
containers_cpp/include/embb/containers/multiset.h
View file @
b3b79150
...
...
@@ -42,15 +42,43 @@ namespace internal {
template
<
typename
Type
>
class
MultisetNode
{
private
:
typedef
primitives
::
LlxScxRecord
<
internal
::
MultisetNode
<
Type
>
>
*
node_ptr_t
;
typedef
primitives
::
LlxScxRecord
<
internal
::
MultisetNode
<
Type
>
>
*
node_ptr_t
;
public
:
MultisetNode
(
const
Type
&
key
,
size_t
count
,
node_ptr_t
next
);
/**
* Default constructor, creates an empty node
*/
inline
MultisetNode
();
/**
* Constructor, creates a multiset entry as node in a linked list
*/
inline
MultisetNode
(
const
Type
&
key
,
size_t
count
,
node_ptr_t
next
);
/**
* Copy constructor
*/
inline
MultisetNode
(
const
MultisetNode
<
Type
>
&
other
);
inline
Type
&
Key
();
/**
* Assignment operator
*/
inline
MultisetNode
<
Type
>
&
operator
=
(
MultisetNode
<
Type
>
&
rhs
);
/**
* Returns the key value contained in this multiset element
*/
inline
Type
&
Key
()
const
;
inline
embb
::
base
::
Atomic
<
size_t
>
*
Count
()
const
;
/**
* Returns the count number of this multiset element
*/
inline
embb
::
base
::
Atomic
<
size_t
>
*
Count
();
/**
* Returns a CAS-enabled pointer to this element's successor element
*/
inline
embb
::
base
::
Atomic
<
node_ptr_t
>
*
Next
();
private
:
...
...
@@ -75,16 +103,50 @@ class Multiset {
static
const
size_t
NUM_LLX_SCX_LINKS
=
3
;
public
:
/**
* Constructor, creates a multiset for a maximum number \c capacity of
* elements.
*/
Multiset
(
size_t
capacity
);
size_t
Get
(
Type
key
);
/**
* Returns the number of occurrences of the given key in the multiset
*
* \returns The number of occurrences of the key, or 0 if the key is not
* contained in the multiset
*/
size_t
Get
(
Type
key
///< [IN] The element key to search in the multiset
);
void
Insert
(
Type
key
,
size_t
count
);
/**
* Adds an element \c key with \c count occurrences to the multiset.
*/
void
Insert
(
Type
key
,
///< [IN] The element key to add to the multiset */
size_t
count
///< [IN] The amount of occurrences of the key to add */
);
bool
TryDelete
(
Type
key
,
size_t
count
);
/**
* Tentatively removes \c count occurrences of element \c key from the
* multiset
*
* \returns True if the given amount of occurrences have been removed
* successfully, or false if the multiset did not contain the
* given occurrences of \c key
*/
bool
TryDelete
(
Type
key
,
///< [IN] The element key to remove from the multiset */
size_t
count
///< [IN] The amount of occurrences to remove */
);
private
:
void
Search
(
bool
Search
(
const
Type
key
,
///< [IN] The element key to search in the multiset
node_ptr_t
&
node
,
...
...
@@ -94,6 +156,11 @@ class Multiset {
);
private
:
/**
* Prevent default construction
*/
Multiset
();
ObjectPool
<
node_t
,
ValuePool
>
node_pool_
;
node_ptr_t
head_
;
node_ptr_t
tail_
;
...
...
@@ -103,6 +170,6 @@ class Multiset {
}
// namespace containers
}
// namespace embb
//
#include <embb/containers/internal/multiset-inl.h>
#include <embb/containers/internal/multiset-inl.h>
#endif // EMBB_CONTAINERS_MULTISET_H_
containers_cpp/include/embb/containers/primitives/llx_scx.h
View file @
b3b79150
...
...
@@ -348,6 +348,19 @@ class LlxScx {
);
/**
* Tentatively performs an LLX (extended load-linked) operation on given
* LLX/SCX data record.
* Returns true and stores result in given reference variable on success,
* otherwise returns false.
*/
bool
TryLoadLinked
(
DataRecord_t
*
const
data_record
,
/**< [IN] Pointer to data record to load */
DataRecord_t
&
data
/**< [OUT] Atomic snapshot of data record */
);
/**
* Tentatively performs a single-record Store-Conditional operation on
* given LLX/SCX data record.
* Returns true if the given value has been stored successfully, otherwise
...
...
@@ -366,6 +379,22 @@ class LlxScx {
);
/**
* Tentatively performs a single-record Store-Conditional operation on
* given LLX/SCX data record.
* Returns true if the given value has been stored successfully, otherwise
* false.
*/
template
<
typename
FieldType
>
bool
TryStoreConditional
(
embb
::
base
::
Atomic
<
FieldType
>
*
field
,
/**< [IN] Pointer to the field the value will be stored into */
FieldType
value
,
/**< [IN] Value to store */
embb
::
containers
::
internal
::
FixedSizeList
<
DataRecord_t
*>
&
linked_deps
/**< [IN] Data records linked to this store operation */
);
/**
* Performs a VLX (extended validate link) operation on given LLX data
* record.
* Returns true if the calling thread's link obtained by its most recent
...
...
containers_cpp/test/main.cc
View file @
b3b79150
...
...
@@ -41,7 +41,7 @@
#include "./hazard_pointer_test.h"
#include "./object_pool_test.h"
#include "./llx_scx_test.h"
#include "./multiset_test.h"
//
#include "./multiset_test.h"
#define COMMA ,
...
...
@@ -58,7 +58,7 @@ using embb::containers::test::QueueTest;
using
embb
::
containers
::
test
::
StackTest
;
using
embb
::
containers
::
test
::
ObjectPoolTest
;
using
embb
::
containers
::
test
::
LlxScxTest
;
using
embb
::
containers
::
test
::
MultisetTest
;
//
using embb::containers::test::MultisetTest;
PT_MAIN
(
"Data Structures C++"
)
{
unsigned
int
max_threads
=
static_cast
<
unsigned
int
>
(
...
...
@@ -75,7 +75,7 @@ PT_MAIN("Data Structures C++") {
PT_RUN
(
ObjectPoolTest
<
LockFreeTreeValuePool
<
bool
COMMA
false
>
>
);
PT_RUN
(
ObjectPoolTest
<
WaitFreeArrayValuePool
<
bool
COMMA
false
>
>
);
PT_RUN
(
LlxScxTest
);
PT_RUN
(
MultisetTest
);
//
PT_RUN(MultisetTest);
PT_EXPECT
(
embb_get_bytes_allocated
()
==
0
);
}
containers_cpp/test/multiset_test.cc
View file @
b3b79150
...
...
@@ -25,7 +25,7 @@
*/
#include <multiset_test.h>
#include <embb/containers/multiset.h>
//
#include <embb/containers/multiset.h>
namespace
embb
{
namespace
containers
{
...
...
@@ -38,6 +38,7 @@ MultisetTest::MultisetTest() :
}
void
MultisetTest
::
SerialTest
()
{
#if 0
Multiset<char, '-'> multiset(3);
multiset.Insert('a', 5);
multiset.Insert('b', 5);
...
...
@@ -51,6 +52,7 @@ void MultisetTest::SerialTest() {
PT_ASSERT(multiset.TryDelete('a', 1));
PT_ASSERT(multiset.TryDelete('b', 1));
PT_ASSERT(multiset.TryDelete('c', 1));
#endif
}
}
// namespace test
...
...
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