Files
libconfig/build-config/reflect-cpp/include/rfl/Object.hpp
Emily Boudreaux ec13264050 feat(reflect-cpp): Switched from glaze -> reflect cpp
A bug was discovered in glaze which prevented valid toml output. We have
switched to toml++ and reflect-cpp. The interface has remained the same
so this should not break any code
2025-12-06 10:55:46 -05:00

249 lines
6.4 KiB
C++

#ifndef RFL_OBJECT_HPP_
#define RFL_OBJECT_HPP_
#include <algorithm>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "Result.hpp"
namespace rfl {
/// Used to embed additional fields for which the names cannot be known in
/// advance and can therefore not be encoded in the struct.
template <class T>
class Object {
public:
using DataType = std::vector<std::pair<std::string, T>>;
using Type = T;
/// We want this to behave as similarly to C++ standard containers as
/// possible.
using key_type = std::string;
using mapped_type = T;
using value_type = std::pair<std::string, T>;
using size_type = typename DataType::size_type;
using difference_type = typename DataType::size_type;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = typename DataType::pointer;
using const_pointer = typename DataType::const_pointer;
using iterator = typename DataType::iterator;
using const_iterator = typename DataType::const_iterator;
using reverse_iterator = typename DataType::reverse_iterator;
using const_reverse_iterator = typename DataType::const_reverse_iterator;
Object() : data_(), i_(0) {}
Object(const Object<T>& _f) = default;
Object(Object<T>&& _f) noexcept = default;
~Object() = default;
/// Iterator to the beginning.
auto begin() { return data_.begin(); }
/// Iterator to the beginning.
auto begin() const { return data_.begin(); }
/// Const iterator to the beginning.
auto cbegin() const { return data_.cbegin(); }
/// Iterator to the end.
auto end() { return data_.end(); }
/// Iterator to the end.
auto end() const { return data_.end(); }
/// Const iterator to the end.
auto cend() const { return data_.cend(); }
/// Reverse iterator.
auto rbegin() { return data_.rbegin(); }
/// Reverse iterator.
auto rbegin() const { return data_.rbegin(); }
/// Const reverse iterator.
auto crbegin() const { return data_.crbegin(); }
/// Reverse iterator.
auto rend() { return data_.rend(); }
/// Reverse iterator.
auto rend() const { return data_.rend(); }
/// Const reverse iterator.
auto crend() const { return data_.crend(); }
Object<T>& operator=(const Object<T>& _f) = default;
Object<T>& operator=(Object<T>&& _f) = default;
/// Whether the object is empty.
auto empty() const { return data_.size() == 0; }
/// The number of elements currently inside the object.
auto size() const { return data_.size(); }
std::size_t count(const key_type& key) const { return std::count_if(cbegin(), cend(), [&](const auto& p) { return p.first == key; }); }
/// The maximum possible size.
auto max_size() const { return data_.max_size(); }
/// Inserts a new element at the end.
template <class... Args>
void insert(const Args&... _values) {
(data_.push_back(_values), ...);
i_ = 0;
}
/// Inserts a new element at the end.
template <class... Args>
void insert(Args&&... _values) {
(data_.emplace_back(std::move(_values)), ...);
i_ = 0;
}
/// Inserts a new element at the end.
void insert(const std::string& _k, const T& _v) {
insert(std::make_pair(_k, _v));
}
/// Inserts a new element at the end.
void insert(const std::string& _k, T&& _v) {
insert(std::make_pair(_k, std::move(_v)));
}
/// Inserts a new element at the end.
void insert(std::string&& _k, T&& _v) {
insert(std::make_pair(std::move(_k), std::move(_v)));
}
/// Inserts a new element at the end.
void insert(const std::string_view& _k, const T& _v) {
insert(std::make_pair(std::string(_k), _v));
}
/// Inserts a new element at the end.
void insert(const std::string_view& _k, T&& _v) {
insert(std::make_pair(std::string(_k), std::move(_v)));
}
/// Alias for insert that primarily exists for compatability with standard
/// containers.
template <class... Args>
void emplace(Args&&... _args) {
insert(std::forward<Args>(_args)...);
}
/// Alias for insert that primarily exists for compatability with standard
/// containers.
template <class... Args>
void emplace(const Args&... _args) {
insert(_args...);
}
/// Inserts several new elements at the end.
template <class InputIt>
void insert_range(InputIt _first, InputIt _last) {
for (auto it = _first; it != _last; ++it) {
insert(*it);
}
}
/// Inserts several new elements at the end.
template <class RangeType>
void insert_range(RangeType _range) {
for (const auto& val : _range) {
insert(val);
}
}
/// Returns the element signified by the key or creates a new one.
T& operator[](const std::string& _key) {
const auto i = find(_key);
if (i != size()) {
return data_[i].second;
}
data_.emplace_back(std::make_pair(_key, T()));
i_ = 0;
return data_.back().second;
}
/// Returns the element signified by the key or creates a new one.
T& operator[](std::string&& _key) {
const auto i = find(_key);
if (i != size()) {
return data_[i].second;
}
data_.emplace_back(std::make_pair(std::move(_key), T()));
i_ = 0;
return data_.back().second;
}
/// Deletes all elements.
void clear() {
data_.clear();
i_ = 0;
}
/// Returns the element signified by the key or throws an exception.
T& at(const std::string& _key) {
const auto i = find(_key);
if (i == size()) {
throw std::runtime_error("Key named '" + _key + "' not found.");
}
return data_[i].second;
}
/// Returns the element signified by the key or throws an exception.
const T& at(const std::string& _key) const {
const auto i = find(_key);
if (i == size()) {
throw std::runtime_error("Key named '" + _key + "' not found.");
}
return data_[i].second;
}
/// Returns a result wrapping the element signified by the key.
Result<T> get(const std::string& _key) const noexcept {
const auto i = find(_key);
if (i == size()) {
return error("Key named '" + _key + "' not found.");
}
return data_[i].second;
}
private:
size_t find(const std::string& _key) const {
for (size_t i = i_; i < size(); ++i) {
if (data_[i].first == _key) {
i_ = i + 1;
return i;
}
}
for (size_t i = 0; i < i_; ++i) {
if (data_[i].first == _key) {
i_ = i + 1;
return i;
}
}
return size();
}
private:
DataType data_;
/// Allows faster access
mutable size_t i_;
};
} // namespace rfl
#endif