Program Listing for File NodeBackendID.hpp¶
↰ Return to documentation for file (src/rdf4cpp/storage/identifier/NodeBackendID.hpp)
#ifndef RDF4CPP_NODEBACKENDID_HPP
#define RDF4CPP_NODEBACKENDID_HPP
#include <rdf4cpp/storage/identifier/NodeID.hpp>
#include <rdf4cpp/storage/identifier/RDFNodeType.hpp>
namespace rdf4cpp::storage::identifier {
struct alignas(uint64_t) NodeBackendID {
using underlying_type = uint64_t;
static constexpr size_t width = 64;
static constexpr size_t tagging_bits_width = 13;
static std::pair<NodeBackendID, std::string_view> const default_graph_iri;
static std::pair<NodeBackendID, std::string_view> const xsd_string_iri;
static std::pair<NodeBackendID, std::string_view> const rdf_langstring_iri;
private:
struct __attribute__((__packed__)) id_parts {
NodeID node_id_;
RDFNodeType node_type_: 2;
uint8_t inlined_: 1;
uint16_t free_tagging_bits_: tagging_bits_width;
static_assert(NodeID::width + 2 + 1 + tagging_bits_width == width);
};
union __attribute__((packed)) {
underlying_type underlying_: width;
id_parts parts_;
};
public:
constexpr NodeBackendID() noexcept = default;
explicit constexpr NodeBackendID(underlying_type const underlying_id) noexcept : underlying_{underlying_id} {
}
constexpr NodeBackendID(NodeID const node_id,
RDFNodeType const node_type,
bool const inlined = false,
uint16_t const tagging_bits = 0) noexcept : parts_{node_id, node_type, inlined, tagging_bits} {
RDF4CPP_ASSERT(tagging_bits < (1 << tagging_bits_width));
}
[[nodiscard]] constexpr RDFNodeType type() const noexcept {
return parts_.node_type_;
}
[[nodiscard]] constexpr bool is_iri() const noexcept {
return parts_.node_type_ == RDFNodeType::IRI;
}
[[nodiscard]] constexpr bool is_literal() const noexcept {
return parts_.node_type_ == RDFNodeType::Literal;
}
[[nodiscard]] constexpr bool is_blank_node() const noexcept {
return parts_.node_type_ == RDFNodeType::BNode;
}
[[nodiscard]] constexpr bool is_variable() const noexcept {
return parts_.node_type_ == RDFNodeType::Variable;
}
[[nodiscard]] constexpr bool null() const noexcept {
return node_id().null();
}
[[nodiscard]] constexpr NodeID node_id() const noexcept {
return parts_.node_id_;
}
[[nodiscard]] constexpr bool is_inlined() const noexcept {
return parts_.inlined_;
}
[[nodiscard]] constexpr uint16_t free_tagging_bits() const noexcept {
return parts_.free_tagging_bits_;
}
constexpr void set_free_tagging_bits(uint16_t new_value) noexcept {
RDF4CPP_ASSERT(new_value < (1 << tagging_bits_width));
parts_.free_tagging_bits_ = new_value;
}
[[nodiscard]] underlying_type to_underlying() const noexcept {
return underlying_;
}
template<std::unsigned_integral I> requires (sizeof(I) >= sizeof(underlying_type))
explicit constexpr operator I() const noexcept {
return static_cast<I>(underlying_);
}
constexpr std::strong_ordering operator<=>(NodeBackendID const &other) const noexcept {
return underlying_ <=> other.underlying_;
}
constexpr bool operator==(NodeBackendID const &other) const noexcept {
return underlying_ == other.underlying_;
}
};
static_assert(sizeof(NodeBackendID) == sizeof(uint64_t));
static_assert(alignof(NodeBackendID) == alignof(uint64_t));
static_assert(std::is_same_v<decltype(static_cast<uintptr_t>(NodeBackendID{})), uintptr_t>, "NodeBackendID must be convertible to uintptr_t");
static_assert(std::is_same_v<decltype(static_cast<uint64_t>(NodeBackendID{})), uint64_t>, "NodeBackendID must be convertible to uint64_t");
inline std::ostream &operator<<(std::ostream &os, NodeBackendID id) {
if (id.is_literal()) {
os << "{ .node_id = { .literal_id = " << id.node_id().literal_id() << ", .literal_type = " << id.node_id().literal_type()
<< " }, .type = " << id.type() << ", .is_inlined = " << std::boolalpha << id.is_inlined() << ", .free_tagging_bits = " << id.free_tagging_bits() << " }";
} else {
os << "{ .node_id = " << id.node_id() << ", .type = " << id.type() << ", .is_inlined = " << std::boolalpha << id.is_inlined() << ", .free_tagging_bits = " << id.free_tagging_bits() << " }";
}
return os;
}
constexpr LiteralType iri_node_id_to_literal_type(NodeBackendID const id) noexcept {
RDF4CPP_ASSERT(id.is_iri());
auto const value = id.node_id().to_underlying();
// all ids values below min_dynamic_datatype_id (except for the null id) are reserved for fixed datatype IRIs
return value < datatypes::registry::min_dynamic_datatype_id && value != 0
? static_cast<LiteralType>(value)
: LiteralType::other();
}
constexpr NodeBackendID literal_type_to_iri_node_id(LiteralType const datatype) {
RDF4CPP_ASSERT(datatype.is_fixed());
return NodeBackendID{NodeID{datatype.to_underlying()}, RDFNodeType::IRI};
}
inline constexpr std::pair<NodeBackendID, std::string_view> NodeBackendID::default_graph_iri{literal_type_to_iri_node_id(datatypes::registry::reserved_datatype_ids[datatypes::registry::default_graph_iri]),
datatypes::registry::default_graph_iri};
inline constexpr std::pair<NodeBackendID, std::string_view> NodeBackendID::xsd_string_iri{literal_type_to_iri_node_id(datatypes::xsd::String::fixed_id),
datatypes::xsd::String::identifier};
inline constexpr std::pair<NodeBackendID, std::string_view> NodeBackendID::rdf_langstring_iri{literal_type_to_iri_node_id(datatypes::rdf::LangString::fixed_id),
datatypes::rdf::LangString::identifier};
} // namespace rdf4cpp::storage::identifier
template<typename Policy>
struct dice::hash::dice_hash_overload<Policy, rdf4cpp::storage::identifier::NodeBackendID> {
static inline size_t dice_hash(rdf4cpp::storage::identifier::NodeBackendID const &x) noexcept {
return dice::hash::dice_hash_templates<Policy>::dice_hash(x.to_underlying());
}
};
template<>
struct std::hash<rdf4cpp::storage::identifier::NodeBackendID> {
inline size_t operator()(rdf4cpp::storage::identifier::NodeBackendID const &v) const noexcept {
return ::dice::hash::dice_hash_templates<::dice::hash::Policies::wyhash>::dice_hash(v);
}
};
#endif // RDF4CPP_NODEBACKENDID_HPP