@@ -85,7 +85,7 @@ class graph final {
8585 using vertex_properties_map_type = std::conditional_t <
8686 traits::c_empty_properties<vertex_properties_type>,
8787 empty_properties_map,
88- std::vector<std::unique_ptr< vertex_properties_type> >>;
88+ std::vector<vertex_properties_type>>;
8989
9090 using edge_type = typename traits_type::edge_type;
9191 using edge_properties_type = typename traits_type::edge_properties_type;
@@ -100,11 +100,8 @@ class graph final {
100100 graph () = default ;
101101
102102 explicit graph (const size_type n_vertices) : _n_vertices(n_vertices), _impl(n_vertices) {
103- if constexpr (traits::c_non_empty_properties<vertex_properties_type>) {
104- this ->_vertex_properties .reserve (n_vertices);
105- for (auto _ : this ->vertex_ids ())
106- this ->_vertex_properties .push_back (std::make_unique<vertex_properties_type>());
107- }
103+ if constexpr (traits::c_non_empty_properties<vertex_properties_type>)
104+ this ->_vertex_properties .resize (n_vertices);
108105 }
109106
110107 graph (graph&&) noexcept = default ;
@@ -129,10 +126,7 @@ class graph final {
129126 const auto new_vertex_id = static_cast <id_type>(this ->_n_vertices ++);
130127
131128 if constexpr (traits::c_non_empty_properties<vertex_properties_type>)
132- return vertex_descriptor{
133- new_vertex_id,
134- *this ->_vertex_properties .emplace_back (std::make_unique<vertex_properties_type>())
135- };
129+ return vertex_descriptor{new_vertex_id, this ->_vertex_properties .emplace_back ()};
136130 else
137131 return vertex_descriptor{new_vertex_id};
138132 }
@@ -143,22 +137,16 @@ class graph final {
143137 this ->_impl .add_vertex ();
144138 return vertex_descriptor{
145139 static_cast <id_type>(this ->_n_vertices ++),
146- *this ->_vertex_properties .emplace_back (
147- std::make_unique<vertex_properties_type>(std::move (properties))
148- )
140+ this ->_vertex_properties .emplace_back (std::move (properties))
149141 };
150142 }
151143
152144 void add_vertices (const size_type n) {
153145 this ->_impl .add_vertices (n);
154146 this ->_n_vertices += n;
155147
156- if constexpr (traits::c_non_empty_properties<vertex_properties_type>) {
157- const auto old_size = this ->_vertex_properties .size ();
158- this ->_vertex_properties .reserve (this ->_n_vertices );
159- for (auto _ = old_size; _ < this ->_n_vertices ; ++_)
160- this ->_vertex_properties .push_back (std::make_unique<vertex_properties_type>());
161- }
148+ if constexpr (traits::c_non_empty_properties<vertex_properties_type>)
149+ this ->_vertex_properties .resize (this ->_n_vertices );
162150 }
163151
164152 void add_vertices_with (
@@ -171,12 +159,12 @@ class graph final {
171159 this ->_impl .add_vertices (n);
172160 this ->_n_vertices += n;
173161
174- if constexpr (traits::c_non_empty_properties<vertex_properties_type>) {
175- for ( auto & properties : properties_rng)
176- this ->_vertex_properties .emplace_back (
177- std::make_unique<vertex_properties_type>(properties)
178- );
179- }
162+ if constexpr (traits::c_non_empty_properties<vertex_properties_type>)
163+ this -> _vertex_properties . insert (
164+ this ->_vertex_properties .end (),
165+ std::ranges::begin (properties_rng),
166+ std::ranges::end (properties_rng)
167+ );
180168 }
181169
182170 gl_attr_force_inline void remove_vertex (const id_type vertex_id) {
@@ -231,7 +219,7 @@ class graph final {
231219 [[nodiscard]] gl_attr_force_inline vertex_type vertex_unchecked (const id_type vertex_id
232220 ) const noexcept {
233221 if constexpr (traits::c_non_empty_properties<vertex_properties_type>)
234- return vertex_descriptor{vertex_id, * this ->_vertex_properties [vertex_id]};
222+ return vertex_descriptor{vertex_id, this ->_vertex_properties [vertex_id]};
235223 else
236224 return vertex_descriptor{vertex_id};
237225 }
@@ -241,21 +229,8 @@ class graph final {
241229 return this ->vertex_unchecked (vertex_id);
242230 }
243231
244- [[nodiscard]] gl_attr_force_inline auto vertices () const noexcept
245- requires(traits::c_empty_properties<vertex_properties_type>)
246- {
247- return this ->vertex_ids ()
248- | std::views::transform ([](const id_type id) { return vertex_descriptor{id}; });
249- }
250-
251- [[nodiscard]] gl_attr_force_inline auto vertices () const noexcept
252- requires(traits::c_non_empty_properties<vertex_properties_type>)
253- {
254- return this ->_vertex_properties | std::views::enumerate
255- | std::views::transform ([](const auto & x) {
256- const auto & [id, ptr] = x;
257- return vertex_descriptor{static_cast <id_type>(id), *ptr};
258- });
232+ [[nodiscard]] gl_attr_force_inline auto vertices () const noexcept {
233+ return this ->vertex_ids () | std::views::transform (this ->_create_vertex_descriptor ());
259234 }
260235
261236 [[nodiscard]] gl_attr_force_inline auto vertex_ids () const noexcept {
@@ -264,7 +239,7 @@ class graph final {
264239
265240 [[nodiscard]] gl_attr_force_inline auto neighbors (const id_type vertex_id) const {
266241 return this ->neighbor_ids (vertex_id)
267- | std::views::transform ([ this ]( const id_type id) { return this -> vertex (id); } );
242+ | std::views::transform (this -> _create_vertex_descriptor () );
268243 }
269244
270245 [[nodiscard]] gl_attr_force_inline auto neighbors (vertex_type vertex) const {
@@ -282,7 +257,7 @@ class graph final {
282257
283258 [[nodiscard]] gl_attr_force_inline auto predecessors (const id_type vertex_id) const {
284259 return this ->predecessor_ids (vertex_id)
285- | std::views::transform ([ this ]( const id_type id) { return this -> vertex (id); } );
260+ | std::views::transform (this -> _create_vertex_descriptor () );
286261 }
287262
288263 [[nodiscard]] gl_attr_force_inline auto predecessors (vertex_type vertex) const {
@@ -300,7 +275,7 @@ class graph final {
300275
301276 [[nodiscard]] gl_attr_force_inline auto successors (const id_type vertex_id) const {
302277 return this ->successor_ids (vertex_id)
303- | std::views::transform ([ this ]( const id_type id) { return this -> vertex (id); } );
278+ | std::views::transform (this -> _create_vertex_descriptor () );
304279 }
305280
306281 [[nodiscard]] gl_attr_force_inline auto successors (vertex_type vertex) const {
@@ -321,13 +296,13 @@ class graph final {
321296 requires(traits::c_non_empty_properties<vertex_properties_type>)
322297 {
323298 this ->_verify_vertex_id (id);
324- return * this ->_vertex_properties [id];
299+ return this ->_vertex_properties [id];
325300 }
326301
327302 [[nodiscard]] gl_attr_force_inline auto vertex_properties_map () const noexcept
328303 requires(traits::c_non_empty_properties<vertex_properties_type>)
329304 {
330- return util::deref_view (this ->_vertex_properties );
305+ return std::views::all (this ->_vertex_properties );
331306 }
332307
333308 // --- degree getters ---
@@ -635,7 +610,7 @@ class graph final {
635610 return false ;
636611
637612 if constexpr (traits::c_non_empty_properties<vertex_properties_type>)
638- if (not std::ranges::equal ( lhs._vertex_properties , rhs._vertex_properties , val_eq) )
613+ if (lhs._vertex_properties != rhs._vertex_properties )
639614 return false ;
640615
641616 if constexpr (traits::c_non_empty_properties<edge_properties_type>)
@@ -678,16 +653,10 @@ class graph final {
678653 using fmt_traits = io::detail::graph_fmt_traits<directional_tag>;
679654
680655 graph (const graph& other)
681- : _n_vertices{other._n_vertices }, _n_edges{other._n_edges }, _impl{other._impl } {
682- // Deep copy vertex properties
683- if constexpr (traits::c_non_empty_properties<vertex_properties_type>) {
684- this ->_vertex_properties .reserve (other._vertex_properties .size ());
685- for (const auto & property : other._vertex_properties )
686- this ->_vertex_properties .push_back (
687- std::make_unique<vertex_properties_type>(*property)
688- );
689- }
690-
656+ : _n_vertices{other._n_vertices },
657+ _n_edges{other._n_edges },
658+ _impl{other._impl },
659+ _vertex_properties{other._vertex_properties } {
691660 // Deep copy edge properties
692661 if constexpr (traits::c_non_empty_properties<edge_properties_type>) {
693662 this ->_edge_properties .reserve (other._edge_properties .size ());
@@ -731,6 +700,22 @@ class graph final {
731700 }
732701 }
733702
703+ // --- transformations ---
704+
705+ gl_attr_force_inline auto _create_vertex_descriptor () const noexcept
706+ requires(traits::c_empty_properties<vertex_properties_type>)
707+ {
708+ return [](const id_type id) { return vertex_type{id}; };
709+ }
710+
711+ gl_attr_force_inline auto _create_vertex_descriptor () const noexcept
712+ requires(traits::c_non_empty_properties<vertex_properties_type>)
713+ {
714+ return [&pmap = this ->_vertex_properties ](const id_type id) {
715+ return vertex_type{id, pmap[to_idx (id)]};
716+ };
717+ }
718+
734719 // --- I/O utility ---
735720
736721 struct concise_target_formatter {
@@ -898,13 +883,16 @@ class graph final {
898883 return is;
899884 }
900885
886+ // --- data members ---
887+
901888 size_type _n_vertices = 0uz;
902889 size_type _n_edges = 0uz;
903890
904- [[no_unique_address]] vertex_properties_map_type _vertex_properties{};
905- [[no_unique_address]] edge_properties_map_type _edge_properties{};
906-
907891 implementation_type _impl{};
892+
893+ // / @todo Replace mutability with proper const-correct getter overloads to ensure thread safety guarantees associated with the const qualifier
894+ [[no_unique_address]] mutable vertex_properties_map_type _vertex_properties{};
895+ [[no_unique_address]] edge_properties_map_type _edge_properties{};
908896};
909897
910898// --- general graph utility ---
0 commit comments