Skip to content

Commit b576fd4

Browse files
committed
Add Boost Software License and update README
- Add LICENSE file with Boost Software License 1.0 - Update README.md to reflect Phase 8 completion - Document all three graph containers (dynamic_graph, compressed_graph, undirected_adjacency_list) - Update test statistics (3866 tests, 36004 assertions) - Add license reference to README - Refactor undirected_adjacency_list to use dedicated value classes - Replace graph_value_wrapper/conditional inheritance with ual_edge_value/ual_vertex_value - Add GV=void specialization removing graph_value_ overhead - Fix all base_type references to use base_value_type - Update graph value storage to use [[no_unique_address]] member
1 parent 3ee81e9 commit b576fd4

4 files changed

Lines changed: 645 additions & 113 deletions

File tree

LICENSE

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Boost Software License - Version 1.0 - August 17th, 2003
2+
3+
Permission is hereby granted, free of charge, to any person or organization
4+
obtaining a copy of the software and accompanying documentation covered by
5+
this license (the "Software") to use, reproduce, display, distribute,
6+
execute, and transmit the Software, and to prepare derivative works of the
7+
Software, and to permit third-parties to whom the Software is furnished to
8+
do so, all subject to the following:
9+
10+
The copyright notices in the Software and this entire statement, including
11+
the above license grant, this restriction and the following disclaimer,
12+
must be included in all copies of the Software, in whole or in part, and
13+
all derivative works of the Software, unless such copies or derivative
14+
works are solely in the form of machine-executable object code generated by
15+
a source language processor.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This library provides the foundation for a complete graph library following the
1212
- **Range-Based Design**: Graphs as ranges of vertices, where each vertex is a range of edges
1313
- **Documentation**: Comprehensive documentation following P1709 conventions
1414

15-
**Current Status**: Phase 7 complete - All core CPOs, value access CPOs, optional partitioning/sourced edge CPOs, adjacency list concepts, and adjacency list traits implemented with comprehensive tests. Ready for first container implementation.
15+
**Current Status**: Phase 8 complete - All graph containers implemented (`dynamic_graph`, `compressed_graph`, `undirected_adjacency_list`) with comprehensive test coverage (3866 tests, 36004 assertions). Core CPOs, value access CPOs, partitioning/sourced edge CPOs, adjacency list concepts, and traits are all fully implemented.
1616

1717
## Features
1818

@@ -418,7 +418,25 @@ Unit tests and documentation for each CPO added.
418418
* Runtime verification tests for trait correctness
419419
* Integration tests with existing CPO framework
420420

421-
### 📋 Phase 8: First Container Implementation (PLANNED)
421+
### ✅ Phase 8: Graph Container Implementations (COMPLETE)
422+
- [x] **dynamic_graph** - Flexible directed graph with configurable vertex/edge containers ✅
423+
- Multiple container combinations: vector-of-vector (vov), vector-of-list (vol), vector-of-forward_list (vofl)
424+
- Partition support for distributed/NUMA-aware graphs
425+
- Sourced edges optional (track source vertex in edge)
426+
- Comprehensive test coverage: 1000+ test cases
427+
- [x] **compressed_graph** - Read-only compressed sparse row (CSR) format ✅
428+
- Optimal for static graph algorithms
429+
- Minimal memory footprint
430+
- O(1) vertex access, O(degree) edge iteration
431+
- Partition support
432+
- [x] **undirected_adjacency_list** - Undirected graph with dual-list design ✅
433+
- Each edge stored in two linked lists (one per endpoint)
434+
- O(1) edge removal from both vertices
435+
- Template defaults aligned with other graphs (VV, EV, GV default to `void`)
436+
- Modern `eproj` constructor pattern (consistent with dynamic_graph)
437+
- 94 test cases, 525 assertions
438+
- Full CPO conformance (47+ functions)
439+
422440
### 📋 Phase 9: Basic Algorithms (PLANNED)
423441
- [ ] Foundational algorithms in `include/graph/algorithm/`:
424442
- `breadth_first_search.hpp` - BFS traversal
@@ -465,13 +483,16 @@ desc/
465483
│ └── graph_utility.hpp # Utility CPOs (stub)
466484
├── scripts/ # Build and maintenance scripts
467485
│ └── format.sh # Code formatting script
468-
├── tests/ # Unit tests (535 tests, all passing)
486+
├── tests/ # Unit tests (3866 tests, all passing)
469487
│ ├── test_adjacency_list_edge_concepts.cpp
470488
│ ├── test_adjacency_list_traits.cpp
471489
│ ├── test_adjacency_list_vertex_concepts.cpp
490+
│ ├── test_compressed_graph.cpp
491+
│ ├── test_compressed_graph_cpo.cpp
472492
│ ├── test_contains_edge_cpo.cpp
473493
│ ├── test_degree_cpo.cpp
474494
│ ├── test_descriptor_traits.cpp
495+
│ ├── test_dynamic_graph_*.cpp # Multiple dynamic_graph test files
475496
│ ├── test_edge_concepts.cpp
476497
│ ├── test_edge_descriptor.cpp
477498
│ ├── test_edge_value_cpo.cpp
@@ -488,6 +509,8 @@ desc/
488509
│ ├── test_target_cpo.cpp
489510
│ ├── test_target_id_cpo.cpp
490511
│ ├── test_type_aliases.cpp
512+
│ ├── test_undirected_adjacency_list.cpp
513+
│ ├── test_undirected_adjacency_list_cpo.cpp
491514
│ ├── test_vertex_concepts.cpp
492515
│ ├── test_vertex_descriptor.cpp
493516
│ ├── test_vertex_id_cpo.cpp
@@ -722,7 +745,7 @@ Contributions are welcome! Please:
722745

723746
## License
724747

725-
[License information to be determined]
748+
This library is distributed under the [Boost Software License 1.0](LICENSE). See the [LICENSE](LICENSE) file for details.
726749

727750
## Acknowledgments
728751

include/graph/container/detail/undirected_adjacency_list_impl.hpp

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ template <typename VV,
527527
ual_edge<VV, EV, GV, VId, VContainer, Alloc>::ual_edge(graph_type& g,
528528
vertex_key_type ukey,
529529
vertex_key_type vkey) noexcept
530-
: base_type(), vertex_edge_list_inward_link_type(ukey), vertex_edge_list_outward_link_type(vkey) {
530+
: base_value_type(), vertex_edge_list_inward_link_type(ukey), vertex_edge_list_outward_link_type(vkey) {
531531
link_back(g.vertices()[ukey], g.vertices()[vkey]);
532532
}
533533

@@ -542,7 +542,7 @@ ual_edge<VV, EV, GV, VId, VContainer, Alloc>::ual_edge(graph_type& g,
542542
vertex_key_type ukey,
543543
vertex_key_type vkey,
544544
const edge_value_type& val) noexcept
545-
: base_type(val), vertex_edge_list_inward_link_type(ukey), vertex_edge_list_outward_link_type(vkey) {
545+
: base_value_type(val), vertex_edge_list_inward_link_type(ukey), vertex_edge_list_outward_link_type(vkey) {
546546
link_back(g.vertices()[ukey], g.vertices()[vkey]);
547547
}
548548

@@ -557,7 +557,7 @@ ual_edge<VV, EV, GV, VId, VContainer, Alloc>::ual_edge(graph_type& g,
557557
vertex_key_type ukey,
558558
vertex_key_type vkey,
559559
edge_value_type&& val) noexcept
560-
: base_type(move(val)), vertex_edge_list_inward_link_type(ukey), vertex_edge_list_outward_link_type(vkey) {
560+
: base_value_type(move(val)), vertex_edge_list_inward_link_type(ukey), vertex_edge_list_outward_link_type(vkey) {
561561
link_back(g.vertices()[ukey], g.vertices()[vkey]);
562562
}
563563

@@ -569,7 +569,7 @@ template <typename VV,
569569
class VContainer,
570570
typename Alloc>
571571
ual_edge<VV, EV, GV, VId, VContainer, Alloc>::ual_edge(graph_type& g, vertex_iterator ui, vertex_iterator vi) noexcept
572-
: base_type()
572+
: base_value_type()
573573
, vertex_edge_list_inward_link_type(vertex_key(g, ui))
574574
, vertex_edge_list_outward_link_type(vertex_key(g, vi)) {
575575
link_back(*ui, *vi);
@@ -586,7 +586,7 @@ ual_edge<VV, EV, GV, VId, VContainer, Alloc>::ual_edge(graph_type& g,
586586
vertex_iterator ui,
587587
vertex_iterator vi,
588588
const edge_value_type& val) noexcept
589-
: base_type(val)
589+
: base_value_type(val)
590590
, vertex_edge_list_inward_link_type(vertex_key(g, ui))
591591
, vertex_edge_list_outward_link_type(vertex_key(g, vi)) {
592592
link_back(*ui, *vi);
@@ -603,7 +603,7 @@ ual_edge<VV, EV, GV, VId, VContainer, Alloc>::ual_edge(graph_type& g,
603603
vertex_iterator ui,
604604
vertex_iterator vi,
605605
edge_value_type&& val) noexcept
606-
: base_type(move(val))
606+
: base_value_type(move(val))
607607
, vertex_edge_list_inward_link_type(vertex_key(g, ui))
608608
, vertex_edge_list_outward_link_type(vertex_key(g, vi)) {
609609
link_back(*ui, *vi);
@@ -843,7 +843,7 @@ template <typename VV,
843843
ual_vertex<VV, EV, GV, VId, VContainer, Alloc>::ual_vertex([[maybe_unused]] vertex_set& vertices,
844844
[[maybe_unused]] vertex_index index,
845845
const vertex_value_type& val)
846-
: base_type(val) {}
846+
: base_value_type(val) {}
847847
template <typename VV,
848848
typename EV,
849849
typename GV,
@@ -854,7 +854,7 @@ template <typename VV,
854854
ual_vertex<VV, EV, GV, VId, VContainer, Alloc>::ual_vertex([[maybe_unused]] vertex_set& vertices,
855855
[[maybe_unused]] vertex_index index,
856856
vertex_value_type&& val) noexcept
857-
: base_type(move(val)) {}
857+
: base_value_type(move(val)) {}
858858

859859

860860
template <typename VV,
@@ -1181,7 +1181,7 @@ template <typename GV_>
11811181
requires (!std::is_void_v<GV_> && !std::is_same_v<std::remove_cvref_t<GV_>, undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>>)
11821182
undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjacency_list(const GV_& val,
11831183
const allocator_type& alloc)
1184-
: base_type(val), vertices_(alloc), edge_alloc_(alloc) {}
1184+
: vertices_(alloc), edge_alloc_(alloc), graph_value_(val) {}
11851185

11861186
template <typename VV,
11871187
typename EV,
@@ -1194,7 +1194,7 @@ template <typename GV_>
11941194
requires (!std::is_void_v<GV_> && !std::is_same_v<std::remove_cvref_t<GV_>, undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>>)
11951195
undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjacency_list(GV_&& val,
11961196
const allocator_type& alloc)
1197-
: base_type(std::forward<GV_>(val)), vertices_(alloc), edge_alloc_(alloc) {}
1197+
: vertices_(alloc), edge_alloc_(alloc), graph_value_(std::forward<GV_>(val)) {}
11981198

11991199

12001200
// clang-format off
@@ -1211,7 +1211,7 @@ undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjace
12111211
const VProj& vproj,
12121212
const GV_& gv,
12131213
const Alloc& alloc)
1214-
: base_type(gv), vertices_(alloc), edge_alloc_(alloc)
1214+
: vertices_(alloc), edge_alloc_(alloc), graph_value_(gv)
12151215
// clang-format on
12161216
{
12171217
// Handle empty case - no vertices or edges to create
@@ -1356,7 +1356,7 @@ template <typename VV,
13561356
typename Alloc>
13571357
undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjacency_list(
13581358
const initializer_list<tuple<vertex_key_type, vertex_key_type, edge_value_type>>& ilist, const Alloc& alloc)
1359-
: base_type(), vertices_(alloc), edge_alloc_(alloc) {
1359+
: vertices_(alloc), edge_alloc_(alloc) {
13601360
// Evaluate max vertex key needed
13611361
vertex_key_type max_vtx_key = vertex_key_type();
13621362
for (auto& edge_data : ilist) {
@@ -1389,7 +1389,7 @@ template <typename VV,
13891389
typename Alloc>
13901390
undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjacency_list(
13911391
const initializer_list<tuple<vertex_key_type, vertex_key_type>>& ilist, const Alloc& alloc)
1392-
: base_type(), vertices_(alloc), edge_alloc_(alloc) {
1392+
: vertices_(alloc), edge_alloc_(alloc) {
13931393
// Evaluate max vertex key needed
13941394
vertex_key_type max_vtx_key = vertex_key_type();
13951395
for (auto& edge_data : ilist) {
@@ -1423,8 +1423,8 @@ template <typename VV,
14231423
typename Alloc>
14241424
undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjacency_list(
14251425
const undirected_adjacency_list& other)
1426-
: base_type(static_cast<const base_type&>(other))
1427-
, edge_alloc_(other.edge_alloc_) {
1426+
: edge_alloc_(other.edge_alloc_)
1427+
, graph_value_(other.graph_value_) {
14281428
// Reserve space and copy vertices (with empty edge lists)
14291429
vertices_.reserve(other.vertices_.size());
14301430

@@ -1435,12 +1435,9 @@ undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjace
14351435
++loop_count;
14361436
if constexpr (std::is_void_v<VV>) {
14371437
vertices_.emplace_back();
1438-
} else if constexpr (detail::graph_value_needs_wrap<VV>::value) {
1439-
// VV is a scalar/array/union/reference type - use graph_value_wrapper's .value member
1440-
vertices_.emplace_back(vertices_, static_cast<vertex_key_type>(vertices_.size()),
1441-
static_cast<const typename vertex_type::base_type&>(v).value);
14421438
} else {
1443-
vertices_.emplace_back(vertices_, static_cast<vertex_key_type>(vertices_.size()), static_cast<const VV&>(v));
1439+
// Access vertex value member directly
1440+
vertices_.emplace_back(vertices_, static_cast<vertex_key_type>(vertices_.size()), v.value);
14441441
}
14451442
}
14461443

@@ -1455,11 +1452,9 @@ undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::undirected_adjace
14551452
if (ukey == src_key && src_key <= tgt_key) {
14561453
if constexpr (std::is_void_v<EV>) {
14571454
create_edge(src_key, tgt_key);
1458-
} else if constexpr (detail::graph_value_needs_wrap<EV>::value) {
1459-
// EV is a scalar/array/union/reference type - use graph_value_wrapper's .value member
1460-
create_edge(src_key, tgt_key, static_cast<const typename edge_type::base_type&>(*uv).value);
14611455
} else {
1462-
create_edge(src_key, tgt_key, static_cast<const EV&>(*uv));
1456+
// Access edge value member directly
1457+
create_edge(src_key, tgt_key, uv->value);
14631458
}
14641459
}
14651460
}
@@ -1863,7 +1858,7 @@ template <typename VV,
18631858
typename Alloc>
18641859
void undirected_adjacency_list<VV, EV, GV, VId, VContainer, Alloc>::swap(undirected_adjacency_list& rhs) {
18651860
using std::swap;
1866-
swap(static_cast<base_type&>(*this), static_cast<base_type&>(rhs));
1861+
swap(graph_value_, rhs.graph_value_);
18671862
vertices_.swap(rhs.vertices_);
18681863
swap(edges_size_, rhs.edges_size_);
18691864
swap(edge_alloc_, rhs.edge_alloc_);

0 commit comments

Comments
 (0)