// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_JSON_TUPLE_KEYS_H /// Array of string literals (in string_views) representing just the keys of a /// tuple. By default construction all keys are included in the array. A /// selection construction will only include keys that are selected. Note that /// the selection construction packs all the chosen keys at the front of the /// array so you cannot rely on this for a key's index into the tuple. template struct ircd::json::keys :std::array { struct selection; struct include; struct exclude; size_t count() const; bool has(const string_view &) const; operator vector_view() const; keys(const selection & = {}); }; /// Selection of keys in a tuple represented by a bitset. Users generally /// do not construct this class directly. Instead, construct one of the /// `include` or `exclude` classes which will set these bits appropriately. template struct ircd::json::keys::selection :util::bitset { template constexpr bool for_each(closure&&) const; template constexpr it transform(it, const it end) const; constexpr bool has(const string_view &) const; constexpr void set(const string_view &, const bool = true); constexpr void set(const size_t &, const bool = true); // Note the default all-bits set. constexpr selection(const uint128_t val = -1) :util::bitset{val} {} static_assert(T::size() <= sizeof(uint64_t) * 8); }; /// Construct this class with a list of keys you want to select for a given /// tuple. This constructs a bitset representing the keys of the tuple and /// lights the bits for your selections. template struct ircd::json::keys::include :selection { include(const vector_view &keys) :selection{0} { for(const auto &key : keys) selection::set(key, true); } template consteval include(list&&... keys) :selection{0} { for(auto&& key : {keys...}) selection::set(key, true); } constexpr include() :selection{0} {} }; /// Construct this class with a list of keys you want to deselect for a given /// tuple. This constructs a bitset representing the keys of the tuple and /// lights the bits which are not in the list. template struct ircd::json::keys::exclude :selection { exclude(const vector_view &keys) :selection{} { for(const auto &key : keys) selection::set(key, false); } template consteval exclude(list&&... keys) :selection{} { for(auto&& key : {keys...}) selection::set(key, false); } constexpr exclude() :selection{} {} }; // // selection // template inline constexpr void ircd::json::keys::selection::set(const string_view &key, const bool val) { selection::set(json::indexof(key), val); } template inline constexpr void ircd::json::keys::selection::set(const size_t &pos, const bool val) { util::bitset::set(pos, val); } template inline constexpr bool ircd::json::keys::selection::has(const string_view &key) const { return util::bitset::test(json::indexof(key)); } template template inline constexpr it ircd::json::keys::selection::transform(it i, const it end) const { for_each([&i, &end](auto&& key) { if(i == end) return false; *i = key; ++i; return true; }); return i; } template template inline constexpr bool ircd::json::keys::selection::for_each(closure&& function) const { for(size_t i(0); i < T::size(); ++i) if(util::bitset::test(i)) if(!function(key(i))) return false; return true; } // // keys // template inline ircd::json::keys::keys(const selection &selection) { selection.transform(this->begin(), this->end()); } template inline ircd::json::keys::operator vector_view() const { return { this->data(), this->count() }; } template inline bool ircd::json::keys::has(const string_view &key) const { const auto &start { this->begin() }; const auto &stop { start + this->count() }; assert(!empty(key)); return stop != std::find(start, stop, key); } template inline size_t ircd::json::keys::count() const { size_t i(0); #pragma clang loop unroll (disable) for(; i < this->size(); ++i) if(!(*this)[i]) break; return i; }