From c224cb2e39a0ff337195633a36fb3b57c0212b7f Mon Sep 17 00:00:00 2001 From: Dominik Drexler Date: Fri, 19 Apr 2024 18:32:12 +0200 Subject: [PATCH] added iterators for factory and segmented vector --- include/loki/details/pddl/factory.hpp | 55 +++++++++++++-- .../loki/details/utils/segmented_vector.hpp | 70 +++++++++++++++++++ tests/unit/pddl/factory.cpp | 57 +++++++++++++++ 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 tests/unit/pddl/factory.cpp diff --git a/include/loki/details/pddl/factory.hpp b/include/loki/details/pddl/factory.hpp index 95eeaa1d..c56a79b5 100644 --- a/include/loki/details/pddl/factory.hpp +++ b/include/loki/details/pddl/factory.hpp @@ -22,7 +22,6 @@ #include "loki/details/utils/segmented_vector.hpp" #include -#include #include #include #include @@ -49,8 +48,6 @@ class PDDLFactory size_t m_count = 0; - std::mutex m_mutex; - public: explicit PDDLFactory(size_t elements_per_segment) : m_persistent_vector(SegmentedVector(elements_per_segment)) {} @@ -59,7 +56,6 @@ class PDDLFactory template [[nodiscard]] HolderType const* get_or_create(Args&&... args) { - std::lock_guard hold(m_mutex); /* Construct and insert the element in persistent memory. */ size_t identifier = m_count; // Ensure that element with identifier i is stored at position i. @@ -90,6 +86,10 @@ class PDDLFactory return element_ptr; } + /** + * Accessors + */ + /// @brief Returns a pointer to an existing object with the given identifier. [[nodiscard]] HolderType const* get(size_t identifier) const { @@ -101,6 +101,53 @@ class PDDLFactory throw std::invalid_argument("invalid identifier"); } + /** + * Iterators + */ + class const_iterator + { + private: + typename SegmentedVector::const_iterator m_iter; + + public: + using difference_type = std::ptrdiff_t; + using value_type = HolderType; + using pointer = HolderType*; + using reference = HolderType&; + using iterator_category = std::forward_iterator_tag; + + const_iterator(const SegmentedVector& persistent_vector, bool begin) : m_iter(begin ? persistent_vector.begin() : persistent_vector.end()) + { + } + + [[nodiscard]] decltype(auto) operator*() const { return *m_iter; } + + const_iterator& operator++() + { + ++m_iter; + return *this; + } + + const_iterator operator++(int) + { + const_iterator tmp = *this; + ++(*this); + return tmp; + } + + [[nodiscard]] bool operator==(const const_iterator& other) const { return m_iter == other.m_iter; } + + [[nodiscard]] bool operator!=(const const_iterator& other) const { return !(*this == other); } + }; + + [[nodiscard]] const_iterator begin() const { return const_iterator(m_persistent_vector, true); } + + [[nodiscard]] const_iterator end() const { return const_iterator(m_persistent_vector, false); } + + /** + * Capacity + */ + size_t size() const { return m_count; } }; diff --git a/include/loki/details/utils/segmented_vector.hpp b/include/loki/details/utils/segmented_vector.hpp index faaf3fe1..c765d2c9 100644 --- a/include/loki/details/utils/segmented_vector.hpp +++ b/include/loki/details/utils/segmented_vector.hpp @@ -58,6 +58,9 @@ class SegmentedVector public: explicit SegmentedVector(size_t elements_per_segment) : m_elements_per_segment(elements_per_segment), m_size(0), m_capacity(0) {} + /** + * Modifiers + */ const T& push_back(T value) { // Increase capacity if necessary @@ -75,6 +78,10 @@ class SegmentedVector return segment.back(); } + /** + * Accessors + */ + T& operator[](size_t pos) { assert(pos < size()); @@ -87,6 +94,69 @@ class SegmentedVector return m_data[segment_index(pos)][element_index(pos)]; } + /** + * Iterators + */ + class const_iterator + { + private: + typename std::vector>::const_iterator m_outer_iter; + typename std::vector>::const_iterator m_outer_end; + typename std::vector::const_iterator m_inner_iter; + + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + using iterator_category = std::forward_iterator_tag; + + const_iterator(const std::vector>& data, bool begin) : m_outer_iter(begin ? data.begin() : data.end()), m_outer_end(data.end()) + { + // Dereferencing end() is undefined behavior, so we must check before initializing the inner iterator. + if (begin && m_outer_iter != m_outer_end) + { + m_inner_iter = m_outer_iter->begin(); + } + } + + [[nodiscard]] decltype(auto) operator*() const { return *m_inner_iter; } + + const_iterator& operator++() + { + if (++m_inner_iter == m_outer_iter->end()) + { + if (++m_outer_iter != m_outer_end) + { + m_inner_iter = m_outer_iter->begin(); + } + } + return *this; + } + + const_iterator operator++(int) + { + const_iterator tmp = *this; + ++(*this); + return tmp; + } + + [[nodiscard]] bool operator==(const const_iterator& other) const + { + return m_outer_iter == other.m_outer_iter && (m_outer_iter == m_outer_end || m_inner_iter == other.m_inner_iter); + } + + [[nodiscard]] bool operator!=(const const_iterator& other) const { return !(*this == other); } + }; + + [[nodiscard]] const_iterator begin() const { return const_iterator(m_data, true); } + + [[nodiscard]] const_iterator end() const { return const_iterator(m_data, false); } + + /** + * Capacity + */ + size_t size() const { return m_size; } size_t capacity() const { return m_capacity; } diff --git a/tests/unit/pddl/factory.cpp b/tests/unit/pddl/factory.cpp new file mode 100644 index 00000000..f7021bcc --- /dev/null +++ b/tests/unit/pddl/factory.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 Dominik Drexler + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +namespace loki::domain::tests +{ + +TEST(LokiTests, FactoryIteratorTest) +{ + PDDLFactory factory(2); + const auto object_0 = factory.get_or_create("object_0", TypeList()); + const auto object_1 = factory.get_or_create("object_1", TypeList()); + const auto object_2 = factory.get_or_create("object_2", TypeList()); + + auto objects = ObjectList {}; + for (const auto& object : factory) + { + objects.push_back(&object); + } + + EXPECT_EQ(objects.size(), 3); + EXPECT_EQ(objects[0], object_0); + EXPECT_EQ(objects[1], object_1); + EXPECT_EQ(objects[2], object_2); +} + +TEST(LokiTests, FactoryIteratorEmptyTest) +{ + PDDLFactory factory(4); + + auto objects = ObjectList {}; + for (const auto& object : factory) + { + objects.push_back(&object); + } + + EXPECT_EQ(objects.size(), 0); +} + +}