Skip to content

Commit

Permalink
added iterators for factory and segmented vector
Browse files Browse the repository at this point in the history
  • Loading branch information
drexlerd committed Apr 19, 2024
1 parent e0f714e commit c224cb2
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 4 deletions.
55 changes: 51 additions & 4 deletions include/loki/details/pddl/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "loki/details/utils/segmented_vector.hpp"

#include <memory>
#include <mutex>
#include <tuple>
#include <type_traits>
#include <unordered_set>
Expand All @@ -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<HolderType>(elements_per_segment)) {}

Expand All @@ -59,7 +56,6 @@ class PDDLFactory
template<typename SubType, typename... Args>
[[nodiscard]] HolderType const* get_or_create(Args&&... args)
{
std::lock_guard<std::mutex> 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.
Expand Down Expand Up @@ -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
{
Expand All @@ -101,6 +101,53 @@ class PDDLFactory
throw std::invalid_argument("invalid identifier");
}

/**
* Iterators
*/
class const_iterator
{
private:
typename SegmentedVector<HolderType>::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<HolderType>& 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; }
};

Expand Down
70 changes: 70 additions & 0 deletions include/loki/details/utils/segmented_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -75,6 +78,10 @@ class SegmentedVector
return segment.back();
}

/**
* Accessors
*/

T& operator[](size_t pos)
{
assert(pos < size());
Expand All @@ -87,6 +94,69 @@ class SegmentedVector
return m_data[segment_index(pos)][element_index(pos)];
}

/**
* Iterators
*/
class const_iterator
{
private:
typename std::vector<std::vector<T>>::const_iterator m_outer_iter;
typename std::vector<std::vector<T>>::const_iterator m_outer_end;
typename std::vector<T>::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<std::vector<T>>& 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; }
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/pddl/factory.cpp
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

#include <gtest/gtest.h>
#include <loki/details/pddl/factory.hpp>
#include <loki/details/pddl/object.hpp>

namespace loki::domain::tests
{

TEST(LokiTests, FactoryIteratorTest)
{
PDDLFactory<ObjectImpl> factory(2);
const auto object_0 = factory.get_or_create<ObjectImpl>("object_0", TypeList());
const auto object_1 = factory.get_or_create<ObjectImpl>("object_1", TypeList());
const auto object_2 = factory.get_or_create<ObjectImpl>("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<ObjectImpl> factory(4);

auto objects = ObjectList {};
for (const auto& object : factory)
{
objects.push_back(&object);
}

EXPECT_EQ(objects.size(), 0);
}

}

0 comments on commit c224cb2

Please sign in to comment.