Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ target_sources(simfil PUBLIC
include/simfil/exception-handler.h

include/simfil/model/arena.h
include/simfil/model/string-handle.h
include/simfil/model/string-pool.h
include/simfil/model/model.h
include/simfil/model/nodes.h
Expand Down
4 changes: 2 additions & 2 deletions include/simfil/model/bitsery-traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ void serialize(S& s, double& v)
}

template <typename S>
void serialize(S& s, simfil::StringId& v)
void serialize(S& s, simfil::StringHandle& v)
{
s.value2b(v);
s.value2b(v.value);
}

namespace ext
Expand Down
6 changes: 3 additions & 3 deletions include/simfil/model/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Model : public std::enable_shared_from_this<Model>
* which contains the `strings()` function. The base
* implementation returns an unset optional.
*/
virtual std::optional<std::string_view> lookupStringId(StringId id) const;
virtual std::optional<std::string_view> lookupStringId(const StringHandle& id) const;
};

/**
Expand Down Expand Up @@ -149,7 +149,7 @@ class ModelPool : public Model
ModelNode::Ptr newValue(int64_t const& value);
ModelNode::Ptr newValue(double const& value);
ModelNode::Ptr newValue(std::string_view const& value);
ModelNode::Ptr newValue(StringId handle);
ModelNode::Ptr newValue(StringHandle const& handle);

/** Node-type-specific resolve-functions */
[[nodiscard]]
Expand All @@ -168,7 +168,7 @@ class ModelPool : public Model
*/
virtual void setStrings(std::shared_ptr<simfil::StringPool> const& strings);

std::optional<std::string_view> lookupStringId(StringId id) const override;
std::optional<std::string_view> lookupStringId(const StringHandle& id) const override;

/** Serialization */
virtual void write(std::ostream& outputStream);
Expand Down
61 changes: 31 additions & 30 deletions include/simfil/model/nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,13 +210,13 @@ struct ModelNode
[[nodiscard]] virtual ValueType type() const;

/// Get a child by name
[[nodiscard]] virtual Ptr get(StringId const& f) const;
[[nodiscard]] virtual Ptr get(StringHandle const& f) const;

/// Get a child by index
[[nodiscard]] virtual Ptr at(int64_t i) const;

/// Get an Object model's field names
[[nodiscard]] virtual StringId keyAt(int64_t i) const;
[[nodiscard]] virtual StringHandle keyAt(int64_t i) const;

/// Get the number of children
[[nodiscard]] virtual uint32_t size() const;
Expand All @@ -243,37 +243,37 @@ struct ModelNode
virtual bool iterate(IterCallback const& cb) const; // NOLINT (allow discard)

/// Iterator Support
/// * `fieldNames()`: Returns range object which supports `for(StringId const& f: node.fieldNames())`
/// * `fieldNames()`: Returns range object which supports `for(StringHandle const& f: node.fieldNames())`
/// * `fields()`: Returns range object which supports `for(auto const& [fieldId, value] : node.fields())`
/// * Normal `begin()`/`end()`: Supports `for(ModelNode::Ptr child : node)`

// Implement fieldNames() by creating an iterator for StringId
class StringIdIterator
// Implement fieldNames() by creating an iterator for StringHandle
class StringHandleIterator
{
int64_t index;
ModelNode const* parent;
public:
using iterator_category = std::input_iterator_tag;
using value_type = StringId;
using value_type = StringHandle;
using difference_type = std::ptrdiff_t;
using pointer = StringId*;
using reference = StringId&;
StringIdIterator(int64_t idx, ModelNode const* p) : index(idx), parent(p) {}
StringIdIterator& operator++() { ++index; return *this; }
bool operator==(const StringIdIterator& other) const { return index == other.index; }
bool operator!=(const StringIdIterator& other) const { return index != other.index; }
StringId operator*() const { return parent->keyAt(index); }
using pointer = StringHandle*;
using reference = StringHandle&;
StringHandleIterator(int64_t idx, ModelNode const* p) : index(idx), parent(p) {}
StringHandleIterator& operator++() { ++index; return *this; }
bool operator==(const StringHandleIterator& other) const { return index == other.index; }
bool operator!=(const StringHandleIterator& other) const { return index != other.index; }
StringHandle operator*() const { return parent->keyAt(index); }
};
class StringIdRange
{
ModelNode const* node;
public:
explicit StringIdRange(ModelNode const* const n) : node(n) {}
[[nodiscard]] StringIdIterator begin() const { return node->fieldNamesBegin(); }
[[nodiscard]] StringIdIterator end() const { return node->fieldNamesEnd(); }
[[nodiscard]] StringHandleIterator begin() const { return node->fieldNamesBegin(); }
[[nodiscard]] StringHandleIterator end() const { return node->fieldNamesEnd(); }
};
[[nodiscard]] StringIdIterator fieldNamesBegin() const { return {0, this}; }
[[nodiscard]] StringIdIterator fieldNamesEnd() const { return {size(), this}; }
[[nodiscard]] StringHandleIterator fieldNamesBegin() const { return {0, this}; }
[[nodiscard]] StringHandleIterator fieldNamesEnd() const { return {size(), this}; }
[[nodiscard]] auto fieldNames() const { return StringIdRange{this}; }

// Implement fields() by creating an iterator for field-value pairs
Expand All @@ -283,15 +283,15 @@ struct ModelNode
ModelNode const* parent;
public:
using iterator_category = std::input_iterator_tag;
using value_type = std::pair<StringId, Ptr>;
using value_type = std::pair<StringHandle, Ptr>;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
FieldIterator(int64_t const idx, ModelNode const* const p) : index(idx), parent(p) {}
FieldIterator& operator++() { ++index; return *this; }
bool operator==(const FieldIterator& other) const { return index == other.index; }
bool operator!=(const FieldIterator& other) const { return index != other.index; }
std::pair<StringId, Ptr> operator*() const { return std::make_pair(parent->keyAt(index), parent->at(index)); }
value_type operator*() const { return std::make_pair(parent->keyAt(index), parent->at(index)); }
};
class FieldRange
{
Expand Down Expand Up @@ -360,9 +360,9 @@ struct ModelNodeBase : public ModelNode

[[nodiscard]] ScalarValueType value() const override;
[[nodiscard]] ValueType type() const override;
[[nodiscard]] ModelNode::Ptr get(const StringId&) const override;
[[nodiscard]] ModelNode::Ptr get(const StringHandle&) const override;
[[nodiscard]] ModelNode::Ptr at(int64_t) const override;
[[nodiscard]] StringId keyAt(int64_t) const override;
[[nodiscard]] StringHandle keyAt(int64_t) const override;
[[nodiscard]] uint32_t size() const override;
bool iterate(IterCallback const&) const override {return true;} // NOLINT (allow discard)

Expand Down Expand Up @@ -525,8 +525,8 @@ struct BaseObject : public MandatoryDerivedModelNodeBase<ModelType>
[[nodiscard]] ValueType type() const override;
[[nodiscard]] ModelNode::Ptr at(int64_t) const override;
[[nodiscard]] uint32_t size() const override;
[[nodiscard]] ModelNode::Ptr get(const StringId &) const override;
[[nodiscard]] StringId keyAt(int64_t) const override;
[[nodiscard]] ModelNode::Ptr get(const StringHandle&) const override;
[[nodiscard]] StringHandle keyAt(int64_t) const override;
bool iterate(ModelNode::IterCallback const& cb) const override; // NOLINT (allow discard)

protected:
Expand All @@ -537,13 +537,13 @@ struct BaseObject : public MandatoryDerivedModelNodeBase<ModelType>
struct Field
{
Field() = default;
Field(StringId name, ModelNodeAddress a) : name_(name), node_(a) {}
StringId name_ = StringPool::Empty;
Field(StringHandle name, ModelNodeAddress a) : name_(name), node_(a) {}
StringHandle name_ = StringPool::Empty;
ModelNodeAddress node_;

template<typename S>
void serialize(S& s) {
s.value2b(name_);
s.object(name_);
s.object(node_);
}
};
Expand Down Expand Up @@ -579,6 +579,7 @@ struct Object : public BaseObject<ModelPool, ModelNode>
Object& addField(std::string_view const& name, int64_t const& value);
Object& addField(std::string_view const& name, double const& value);
Object& addField(std::string_view const& name, std::string_view const& value);
Object& addField(std::string_view const& name, StringHandle const& value);

[[nodiscard]] ModelNode::Ptr get(std::string_view const& fieldName) const;

Expand Down Expand Up @@ -610,16 +611,16 @@ class ProceduralObject : public Object
return fields_.size() + (members_ != InvalidArrayIndex ? Object::size() : 0);
}

[[nodiscard]] ModelNode::Ptr get(const StringId & field) const override {
[[nodiscard]] ModelNode::Ptr get(const StringHandle& field) const override {
for (auto const& [k, v] : fields_)
if (k == field)
if (field == k)
return v(static_cast<LambdaThisType const&>(*this));
if (members_ != InvalidArrayIndex)
return Object::get(field);
return {};
}

[[nodiscard]] StringId keyAt(int64_t i) const override {
[[nodiscard]] StringHandle keyAt(int64_t i) const override {
if (i < fields_.size())
return fields_[i].first;
if (members_ != InvalidArrayIndex)
Expand Down Expand Up @@ -648,7 +649,7 @@ class ProceduralObject : public Object
: Object(InvalidArrayIndex, pool, a) {}

sfl::small_vector<
std::pair<StringId, std::function<ModelNode::Ptr(LambdaThisType const&)>>,
std::pair<StringHandle, std::function<ModelNode::Ptr(LambdaThisType const&)>>,
MaxProceduralFields> fields_;
};

Expand Down
8 changes: 4 additions & 4 deletions include/simfil/model/nodes.impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ModelNode::Ptr BaseObject<ModelType, ModelNodeType>::at(int64_t i) const
}

template <class ModelType, class ModelNodeType>
StringId BaseObject<ModelType, ModelNodeType>::keyAt(int64_t i) const
StringHandle BaseObject<ModelType, ModelNodeType>::keyAt(int64_t i) const
{
if (i < 0 || i >= (int64_t)storage_->size(members_))
return {};
Expand All @@ -114,14 +114,14 @@ uint32_t BaseObject<ModelType, ModelNodeType>::size() const
}

template <class ModelType, class ModelNodeType>
ModelNode::Ptr BaseObject<ModelType, ModelNodeType>::get(const StringId& field) const
ModelNode::Ptr BaseObject<ModelType, ModelNodeType>::get(const StringHandle& field) const
{
ModelNode::Ptr result;
storage_->iterate(
members_,
[&field, &result, this](auto&& member)
{
if (member.name_ == field) {
if (field == member.name_) {
result = ModelNode::Ptr::make(model_, member.node_);
return false;
}
Expand Down Expand Up @@ -155,4 +155,4 @@ BaseObject<ModelType, ModelNodeType>& BaseObject<ModelType, ModelNodeType>::addF
return *this;
}

} // namespace simfil
} // namespace simfil
136 changes: 136 additions & 0 deletions include/simfil/model/string-handle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#pragma once

#include <cassert>
#include <cstdint>
#include <limits>
#include <type_traits>

namespace simfil
{

namespace detail
{

template <class Type_, class Enable_ = void>
struct UnderlyingIntegralType
{
using Type = Type_;
};

template <class Type_>
struct UnderlyingIntegralType<Type_, std::enable_if_t<std::is_enum_v<Type_>>>
{
using Type = std::underlying_type_t<Type_>;
};

template <class T>
using UnderlyingIntegralTypeT = typename UnderlyingIntegralType<T>::Type;

template <class From, class To>
using IsSafeIntegerConversion =
std::integral_constant<
bool,
std::is_integral_v<UnderlyingIntegralTypeT<From>> &&
std::is_signed_v<UnderlyingIntegralTypeT<From>> == std::is_signed_v<To> &&
sizeof(UnderlyingIntegralTypeT<From>) <= sizeof(To)>;

template <class From, class To>
using EnableSafeIntegerConversion = std::enable_if_t<IsSafeIntegerConversion<From, To>::value>;

} // namespace detail


/// Type safe wrapper around an integer type for
/// usa as a StringHandle.
struct StringHandle
{
using Type = std::uint16_t;

Type value;

StringHandle() : value(0u) {}
StringHandle(const StringHandle& id) = default;

template <typename T, typename = detail::EnableSafeIntegerConversion<T, Type>>
constexpr StringHandle(const T& value) : value(static_cast<Type>(value)) {}

auto next() const -> StringHandle {
return StringHandle{static_cast<Type>(value + 1u)};
}

auto previous() const -> StringHandle {
return StringHandle{static_cast<Type>(value - 1u)};
}

explicit operator bool() const {
return value != (Type)0;
}

explicit operator Type() const {
return value;
}

auto operator==(const StringHandle& id) const -> bool {
return value == id.value;
}

auto operator<(const StringHandle& id) const -> bool {
return value < id.value;
}

auto operator<=(const StringHandle& id) const -> bool {
return value <= id.value;
}

template <class T, class = detail::EnableSafeIntegerConversion<T, Type>>
auto operator==(const T& v) const -> bool {
return value == v;
}

template <class T, class = detail::EnableSafeIntegerConversion<T, Type>>
auto operator<(const T& v) const -> bool {
return value < v;
}

template <class T, class = detail::EnableSafeIntegerConversion<T, Type>>
auto operator<=(const T& v) const -> bool {
return value <= v;
}

/// StringHandle is used as an index type
auto operator++(int) -> StringHandle {
auto old = *this;
++value;
return old;
}

auto operator++() -> StringHandle& {
++value;
return *this;
}

auto operator--(int) -> StringHandle {
auto old = *this;
--value;
return old;
}

auto operator--() -> StringHandle& {
--value;
return *this;
}
};

}

namespace std
{

template <>
struct hash<simfil::StringHandle> {
auto operator()(const simfil::StringHandle &id) const noexcept -> std::size_t {
return std::hash<simfil::StringHandle::Type>()(id.value);
}
};

} // namespace std
Loading
Loading