Skip to content

Commit

Permalink
pw_containers: Multiple container example
Browse files Browse the repository at this point in the history
It is possible to add intrusive items to multiple containers, but only
if those containers have disjoint value_types. This isn't entirely
intuitive, so this CL adds examples, unit tests, and docs to make it
easier.

Additionally, in order facilitate the aforementioned unit tests, the
base type for map items has been unified into `pw::IntrusiveMapItem`,
and the intrusive item type used by `CheckItemType` has been renamed
to `pw::containers::internal::IntrusiveItem`.

Change-Id: I6bf99d4814d95bd12679edb16cd900013044badd
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/237472
Commit-Queue: Aaron Green <[email protected]>
Lint: Lint 🤖 <[email protected]>
Reviewed-by: Wyatt Hepler <[email protected]>
  • Loading branch information
nopsledder authored and CQ Bot Account committed Sep 25, 2024
1 parent cfa4da0 commit 819dd2c
Show file tree
Hide file tree
Showing 20 changed files with 505 additions and 123 deletions.
35 changes: 21 additions & 14 deletions pw_containers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ cc_library(
)

cc_library(
name = "intrusive",
srcs = ["intrusive.cc"],
hdrs = ["public/pw_containers/internal/intrusive.h"],
name = "intrusive_item",
srcs = ["intrusive_item.cc"],
hdrs = ["public/pw_containers/internal/intrusive_item.h"],
implementation_deps = ["//pw_assert"],
includes = ["public"],
)
Expand All @@ -76,7 +76,7 @@ cc_library(
"public/pw_containers/internal/intrusive_list_iterator.h",
],
includes = ["public"],
deps = [":intrusive"],
deps = [":intrusive_item"],
)

cc_library(
Expand Down Expand Up @@ -109,7 +109,7 @@ cc_library(
)

cc_library(
name = "intrusive_map_common",
name = "intrusive_map",
srcs = [
"aa_tree.cc",
"aa_tree_item.cc",
Expand All @@ -118,27 +118,21 @@ cc_library(
"public/pw_containers/internal/aa_tree.h",
"public/pw_containers/internal/aa_tree_item.h",
"public/pw_containers/internal/aa_tree_iterator.h",
"public/pw_containers/intrusive_map.h",
],
includes = ["public"],
deps = [
":intrusive",
":intrusive_item",
"//pw_assert",
"//pw_bytes:packed_ptr",
],
)

cc_library(
name = "intrusive_map",
hdrs = ["public/pw_containers/intrusive_map.h"],
includes = ["public"],
deps = [":intrusive_map_common"],
)

cc_library(
name = "intrusive_multimap",
hdrs = ["public/pw_containers/intrusive_multimap.h"],
includes = ["public"],
deps = [":intrusive_map_common"],
deps = [":intrusive_map"],
)

cc_library(
Expand Down Expand Up @@ -399,3 +393,16 @@ pw_cc_test(
"//pw_span",
],
)

pw_cc_test(
name = "intrusive_item_test",
srcs = ["intrusive_item_test.cc"],
deps = [
":intrusive_forward_list",
":intrusive_list",
":intrusive_map",
":intrusive_multimap",
"//pw_compilation_testing:negative_compilation_testing",
"//pw_unit_test",
],
)
34 changes: 21 additions & 13 deletions pw_containers/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ pw_source_set("wrapped_iterator") {
public = [ "public/pw_containers/wrapped_iterator.h" ]
}

pw_source_set("intrusive") {
pw_source_set("intrusive_item") {
public_configs = [ ":public_include_path" ]
public = [ "public/pw_containers/internal/intrusive.h" ]
sources = [ "intrusive.cc" ]
public = [ "public/pw_containers/internal/intrusive_item.h" ]
sources = [ "intrusive_item.cc" ]
deps = [ dir_pw_assert ]
}

Expand All @@ -156,7 +156,7 @@ pw_source_set("intrusive_list_common") {
"public/pw_containers/internal/intrusive_list_item.h",
"public/pw_containers/internal/intrusive_list_iterator.h",
]
public_deps = [ ":intrusive" ]
public_deps = [ ":intrusive_item" ]
}

pw_source_set("intrusive_forward_list") {
Expand Down Expand Up @@ -184,15 +184,16 @@ pw_source_set("legacy_intrusive_list") {
public_deps = [ ":intrusive_forward_list" ]
}

pw_source_set("intrusive_map_common") {
pw_source_set("intrusive_map") {
public_configs = [ ":public_include_path" ]
public = [
"public/pw_containers/internal/aa_tree.h",
"public/pw_containers/internal/aa_tree_item.h",
"public/pw_containers/internal/aa_tree_iterator.h",
"public/pw_containers/intrusive_map.h",
]
public_deps = [
":intrusive",
":intrusive_item",
"$dir_pw_bytes:packed_ptr",
dir_pw_assert,
]
Expand All @@ -202,16 +203,10 @@ pw_source_set("intrusive_map_common") {
]
}

pw_source_set("intrusive_map") {
public_configs = [ ":public_include_path" ]
public = [ "public/pw_containers/intrusive_map.h" ]
public_deps = [ ":intrusive_map_common" ]
}

pw_source_set("intrusive_multimap") {
public_configs = [ ":public_include_path" ]
public = [ "public/pw_containers/intrusive_multimap.h" ]
public_deps = [ ":intrusive_map_common" ]
public_deps = [ ":intrusive_map" ]
}

pw_test_group("tests") {
Expand All @@ -222,6 +217,7 @@ pw_test_group("tests") {
":inline_deque_test",
":inline_queue_test",
":intrusive_forward_list_test",
":intrusive_item_test",
":intrusive_list_test",
":intrusive_map_test",
":intrusive_multimap_test",
Expand Down Expand Up @@ -398,13 +394,25 @@ pw_test("intrusive_multimap_test") {
negative_compilation_tests = true
}

pw_test("intrusive_item_test") {
sources = [ "intrusive_item_test.cc" ]
deps = [
":intrusive_forward_list",
":intrusive_list",
":intrusive_map",
":intrusive_multimap",
]
negative_compilation_tests = true
}

pw_doc_group("docs") {
inputs = [
"examples/flat_map.cc",
"examples/intrusive_forward_list.cc",
"examples/intrusive_list.cc",
"examples/intrusive_map.cc",
"examples/intrusive_multimap.cc",
"examples/listed_and_mapped.cc",
"examples/wrapped_iterator.cc",
]
sources = [ "docs.rst" ]
Expand Down
39 changes: 22 additions & 17 deletions pw_containers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ pw_add_library(pw_containers INTERFACE
pw_containers.inline_deque
pw_containers.inline_queue
pw_containers.intrusive_list
pw_containers.intrusive_map
pw_containers.vector
)

Expand Down Expand Up @@ -147,13 +146,13 @@ pw_add_library(pw_containers.wrapped_iterator INTERFACE
public
)

pw_add_library(pw_containers.intrusive STATIC
pw_add_library(pw_containers.intrusive_item STATIC
HEADERS
public/pw_containers/internal/intrusive.h
public/pw_containers/internal/intrusive_item.h
PUBLIC_INCLUDES
public
SOURCES
intrusive.cc
intrusive_item.cc
PRIVATE_DEPS
pw_assert
)
Expand All @@ -166,7 +165,7 @@ pw_add_library(pw_containers.intrusive_list_common INTERFACE
PUBLIC_INCLUDES
public
PUBLIC_DEPS
pw_containers.intrusive
pw_containers.intrusive_item
)

pw_add_library(pw_containers.intrusive_forward_list INTERFACE
Expand Down Expand Up @@ -199,38 +198,30 @@ pw_add_library(pw_containers.legacy_intrusive_list INTERFACE
pw_containers.intrusive_forward_list
)

pw_add_library(pw_containers.intrusive_map_common STATIC
pw_add_library(pw_containers.intrusive_map STATIC
HEADERS
public/pw_containers/internal/aa_tree.h
public/pw_containers/internal/aa_tree_item.h
public/pw_containers/internal/aa_tree_iterator.h
public/pw_containers/intrusive_map.h
PUBLIC_INCLUDES
public
PUBLIC_DEPS
pw_assert
pw_bytes.packed_ptr
pw_containers.intrusive
pw_containers.intrusive_item
SOURCES
aa_tree.cc
aa_tree_item.cc
)

pw_add_library(pw_containers.intrusive_map INTERFACE
HEADERS
public/pw_containers/intrusive_map.h
PUBLIC_INCLUDES
public
PUBLIC_DEPS
pw_containers.intrusive_map_common
)

pw_add_library(pw_containers.intrusive_multimap INTERFACE
HEADERS
public/pw_containers/intrusive_multimap.h
PUBLIC_INCLUDES
public
PUBLIC_DEPS
pw_containers.intrusive_map_common
pw_containers.intrusive_map
)

pw_add_test(pw_containers.algorithm_test
Expand Down Expand Up @@ -404,4 +395,18 @@ pw_add_test(pw_containers.intrusive_multimap_test
pw_containers
)

pw_add_test(pw_containers.intrusive_item_test
SOURCES
intrusive_item_test.cc
PRIVATE_DEPS
pw_compilation_testing._pigweed_only_negative_compilation
pw_containers.intrusive_forward_list
pw_containers.intrusive_list
pw_containers.intrusive_map
pw_containers.intrusive_multimap
GROUPS
modules
pw_containers
)

add_subdirectory(examples)
27 changes: 26 additions & 1 deletion pw_containers/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,32 @@ Example
:language: cpp
:linenos:
:start-after: [pw_containers-intrusive_multimap]
:end-before: [pw_containers-intrusive_multimap
:end-before: [pw_containers-intrusive_multimap]

------------------------------------
Using items with multiple containers
------------------------------------
Intrusive items may be used with multiple containers, provided each of those
containers is templated on a type that is not derived from any of the others.
This can be achieved by multiply inheriting from distinct type:

.. literalinclude:: examples/listed_and_mapped.cc
:language: cpp
:linenos:
:start-after: [pw_containers-listed_and_mapped]
:end-before: [pw_containers-listed_and_mapped]

If one or more types is derived from another, the compiler will fail to build
with an error that ``ItemType`` is ambiguous or found in multiple base classes.

Creating per-list types is fairly trivial, but per-map types are slightly more
involved. To facilitate this, the module provides a helper class
``pw::IntrusiveMapItemWithKey``, as seen in the example above.. This class
handles defining a unique type for a map or multimap of items that include their
keys.

.. doxygenclass:: pw::IntrusiveMapItemWithKey
:members:

-----------------------
pw::containers::FlatMap
Expand Down
11 changes: 11 additions & 0 deletions pw_containers/examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ pw_cc_test(
deps = ["//pw_containers:intrusive_multimap"],
)

pw_cc_test(
name = "listed_and_mapped",
srcs = ["listed_and_mapped.cc"],
deps = [
"//pw_containers:intrusive_list",
"//pw_containers:intrusive_map",
"//pw_result",
"//pw_status",
],
)

pw_cc_test(
name = "wrapped_iterator",
srcs = ["wrapped_iterator.cc"],
Expand Down
11 changes: 11 additions & 0 deletions pw_containers/examples/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ pw_test("intrusive_multimap") {
sources = [ "intrusive_multimap.cc" ]
}

pw_test("listed_and_mapped") {
deps = [
"$dir_pw_containers:intrusive_list",
"$dir_pw_containers:intrusive_map",
dir_pw_result,
dir_pw_status,
]
sources = [ "listed_and_mapped.cc" ]
}

pw_test("wrapped_iterator") {
deps = [ "$dir_pw_containers:wrapped_iterator" ]
sources = [ "wrapped_iterator.cc" ]
Expand All @@ -55,6 +65,7 @@ pw_test_group("examples") {
":intrusive_list",
":intrusive_map",
":intrusive_multimap",
":listed_and_mapped",
":wrapped_iterator",
]
}
10 changes: 10 additions & 0 deletions pw_containers/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ pw_add_test(pw_containers.examples.intrusive_multimap
intrusive_multimap.cc
)

pw_add_test(pw_containers.examples.listed_and_mapped
PRIVATE_DEPS
pw_containers.intrusive_list
pw_containers.intrusive_map
pw_result
pw_status
SOURCES
listed_and_mapped.cc
)

pw_add_test(pw_containers.examples.wrapped_iterator
PRIVATE_DEPS
pw_containers.wrapped_iterator
Expand Down
2 changes: 1 addition & 1 deletion pw_containers/examples/intrusive_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void VisitLibrary(pw::IntrusiveMap<uint32_t, Book>& book_bag) {

namespace {

TEST(IntrusiveMapExampleTest, TBD) {
TEST(IntrusiveMapExampleTest, VisitLibrary) {
examples::Book book = {"One Hundred Years of Solitude", 17522865u};
pw::IntrusiveMap<uint32_t, examples::Book> book_bag;
book_bag.insert(book);
Expand Down
2 changes: 1 addition & 1 deletion pw_containers/examples/intrusive_multimap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void VisitLibrary(pw::IntrusiveMultiMap<uint32_t, Book>& book_bag) {

namespace {

TEST(IntrusiveMultiMapExampleTest, TBD) {
TEST(IntrusiveMultiMapExampleTest, VisitLibrary) {
pw::IntrusiveMultiMap<uint32_t, examples::Book> book_bag1;
examples::VisitLibrary(book_bag1);

Expand Down
Loading

0 comments on commit 819dd2c

Please sign in to comment.