-
Notifications
You must be signed in to change notification settings - Fork 0
Tags
Library offers following choice of tag types:
- Static tags -
frq::stagclass template, taking number of elements the tag has, its size, and their types - Dynamic tag -
frq::dtagclass template, taking only allocator type
All tag types have to satisfy taglike concept which is defined as:
template<typename Ty>
concept taglike = requires(Ty t) {
typename Ty::size_type;
typename Ty::storage_type;
{std::size_t{typename Ty::size_type{}}};
{ t.values() } noexcept -> std::convertible_to<typename Ty::storage_type>;
{ t.size() } noexcept -> std::same_as<typename Ty::size_type>;
};
where:
-
size_typeis type that can store number of values in the tag and it can be converted tostd::size_twithout narrowing, -
storage_typeis the type can store all values in the tag, -
sizeis a member function that returns number of values in the tag and -
valuesis a member function returning all the values currently stored in tag
Static tag has its structure, size and type of values at each level, defined at the compile time. Static tag owns values stored in them which means that copying/destroying tag will also copy/destroy stored values.
frq::stag class template represent static tag.
template<std::uint8_t Size, typename... Tys>
class stag;
Size template parameter specifies how many values from the Tys type list will be populated, so it defines "level" of the tag. List of types have to be the same for all tags used by the same queue, no matter the tag level:
| Level: | 0 | 1 | 2 |
|---|---|---|---|
stag<3, int, string, float> |
77 |
"x" |
12.3 |
stag<2, int, string, float> |
8 |
"y" |
|
stag<1, int, string, float> |
10 |
frq::stag can be constructed from tuple of fitting size containing defined types, or providing the list of arguments to the constructor which will be used to initialize corresponding values in tag:
template<typename... Txs>
constexpr inline stag(construct_tag_default_t, Txs&&... args);
constexpr inline stag(storage_type const& values);
constexpr inline stag(storage_type&& values);
Size of the tag can be obtained by calling size:size(); tuple containing all values in the tag is returned by values(); and value at the highest available level is returned by key().
storage_type const& values() const noexcept;
size_type size() const noexcept;
auto key() const noexcept;
frq::stag_t type alias provides way to defined stag type at the highest level for specified list of type:
template<typename... Tys>
using stag_t = /* ... */;
Dynamic tags have no restriction on size or type of values at each level. Tag size can increase in run-time and types of values can differ for each level and even for the children of the same parent:
| Level: | 0 | 1 | 1 |
|---|---|---|---|
| Dynamic Tag #1 | 8 |
"x" |
12.3 |
| Dynamic Tag #2 | 8 |
7.9 |
|
| Dynamic Tag #3 | "y" |
8 |
This is achieved through type erasure. Types that are stored in dynamic tag have to support hashing and equality comparison. Values are shared by the dynamic tags, so tags store only references to the values unlike the static tags.
frq::dtag class template is only parameterized by allocator used for type erasure purposes:
template<typename Alloc = std::allocator<dtag_node>>
class dtag;
Values stored in dynamic tags are wrapped by frq::dtag_node abstract type that does type erasure. frq::dtag_node provides interface for hashing, equality comparison and string formatting of stored values.
class dtag_node {
public:
virtual ~dtag_node() {
}
virtual std::size_t hash() const noexcept = 0;
virtual bool equal(dtag_node const& other) const noexcept = 0;
virtual std::string get_string() const = 0;
};
User can interact with values through frq::dtag_value type, which is a regular type providing access to underlying node storing actual value.
class dtag_value {
public:
dtag_node_ptr::element_type const& node() const;
std::size_t hash() const noexcept;
std::string get_string();
bool operator==(dtag_value const& rhs) const noexcept;
bool operator!=(dtag_value const& rhs) const noexcept;
};
frq::dtag can be constructed from sequence of dtag_values or by providing list of arguments to the constructor which will initialize corresponding values in the tag. Hashing operation and equality comparison can be provided which is going to be used by constructed dtag_node.
template<tag_iterator Iter>
dtag(allocator_type const& alloc, Iter first, Iter last);
template<tag_iterator Iter>
dtag(Iter first, Iter last);
template<typename HashCmp, typename... Tys>
dtag(allocator_type const& alloc, HashCmp const& hash_cmp, Tys&&... args);
template<typename... Tys>
dtag(construct_tag_alloc_t, allocator_type const& alloc, Tys&&... args);
template<typename HashCmp, typename... Tys>
dtag(construct_tag_hash_cmp_t, HashCmp const& hash_cmp, Tys&&... args);
template<typename... Tys>
dtag(construct_tag_default_t /*unused*/, Tys&&... args);
Dynamic tags offer the similar interface as static tags. They can provide: size(); vector of tag_values containing references to values in the tag: values(); and tag_value at the highest available level: key(). Additional accessor is provided that allows user to get tuple of values stored in tag: pack(). Number and types of template arguments provided to pack function template must match number and types of values stored in the tag, otherwise behavior is undefined.
storage_type const& values() const noexcept;
size_type size() const noexcept;
template<typename... Tys>
auto pack() const;
auto key() const noexcept;
frq::default_hash_compare type, that is used in case user type is not provided during tag construction, forwards hash computation to std::hash<T> and equality comparison to std::equal_to<T>.
struct default_hash_compare {
template<typename Ty>
std::size_t hash(Ty const& value) const noexcept;
template<typename Ty>
bool equal_to(Ty const& left, Ty const& right) const noexcept;
};