// 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 namespace ircd { namespace json { template struct keys; } // namespace json } // namespace ircd /// 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; operator vector_view() const; explicit keys(const selection &); keys(); }; /// 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 :std::bitset { template bool until(closure &&function) const; template void for_each(closure &&function) const; template it_a transform(it_a it, const it_b end) const; }; /// 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 &list) { for(const auto &key : list) this->set(indexof(key), true); } include(const std::initializer_list &list) :include(vector_view(list)) {} }; /// 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 &list) { this->set(); for(const auto &key : list) this->set(indexof(key), false); } exclude(const std::initializer_list &list) :exclude(vector_view(list)) {} }; // // selection // template template it_a ircd::json::keys::selection::transform(it_a it, const it_b end) const { this->until([&it, &end](auto&& key) { if(it == end) return false; *it = key; ++it; return true; }); return it; } template template void ircd::json::keys::selection::for_each(closure &&function) const { this->until([&function](auto&& key) { function(key); return true; }); } template template bool ircd::json::keys::selection::until(closure &&function) const { for(size_t i(0); i < tuple::size(); ++i) if(this->test(i)) if(!function(key(i))) return false; return true; } // // keys // template ircd::json::keys::keys() { _key_transform(this->begin(), this->end()); } template ircd::json::keys::keys(const selection &selection) { selection.transform(this->begin(), this->end()); } template ircd::json::keys::operator vector_view() const { return { this->data(), this->count() }; } template size_t ircd::json::keys::count() const { size_t i(0); for(; i < this->size(); ++i) if(!(*this)[i]) break; return i; }