52template <
typename Int>
53constexpr int bits_of = std::numeric_limits<Int>::digits;
57namespace detail_bits {
59 template <
typename Key,
typename Value>
61 std::unique_ptr<std::array<trie_node, 4>> children;
62 unsigned char storage[
sizeof(Value)]{};
65 template <
typename... Args>
66 auto create(Args&&... args)
noexcept(
67 std::is_nothrow_constructible<Value, Args...>::value) -> Value& {
71 auto v = *
new (storage) Value(args...);
76 auto clear()
noexcept ->
void {
85 return *
reinterpret_cast<Value*
>(storage);
89 return *
reinterpret_cast<Value*
>(storage);
114template <
typename Key, Key key_range,
typename Value>
131 template <
typename V>
141 static_assert(std::is_integral<Key>::value,
"Key must be an integral type.");
142 static_assert(std::is_unsigned<Key>::value,
"Key must be unsigned.");
143 static_assert(std::is_nothrow_destructible<mapped_type>::value,
144 "mapped_type must be nothrow destructible.");
149 throw std::out_of_range(
"searched in an empty compact_bit_trie");
151 if (key.bits > bits_of<Key>) {
152 throw std::invalid_argument(
"key prefix longer than key length");
157 while (node and idx < key.bits) {
158 if (
auto val = storage[node].val) {
161 node = storage[node].children[search[idx++]];
164 throw std::out_of_range(
"key not found in compact_bit_trie");
169 throw std::out_of_range(
"searched in an empty compact_bit_trie");
171 if (key.bits > bits_of<Key>) {
172 throw std::invalid_argument(
"key prefix longer than key length");
177 while (node and idx < key.bits) {
178 if (
auto val = storage[node].val) {
181 node = storage[node].children[search[idx++]];
184 throw std::out_of_range(
"key not found in compact_bit_trie");
190 throw std::out_of_range(
"searched in an empty compact_bit_trie");
192 if (key.
bits > bits_of<Key>) {
193 throw std::invalid_argument(
"key prefix longer than key length");
199 while (node and idx < key.
bits) {
200 if (
auto val = storage[node].val) {
206 node = storage[node].children[search[idx++]];
209 return values[found];
211 throw std::out_of_range(
"key not found in compact_bit_trie");
219 throw std::out_of_range(
"searched in an empty compact_bit_trie");
221 if (key.
bits > bits_of<Key>) {
222 throw std::invalid_argument(
"key prefix longer than key length");
228 while (node and idx < key.
bits) {
229 if (
auto val = storage[node].val) {
235 node = storage[node].children[search[idx++]];
238 return values[found];
240 throw std::out_of_range(
"key not found in compact_bit_trie");
245 return values.empty();
248 template <
typename... Ts>
250 size_type node = get_storage_node_for(key);
251 if (
auto& v = storage[node].val; v !=
max) {
254 values.emplace_back(std::forward<Ts>(args)...);
255 v =
static_cast<size_type>(values.size() - 1);
261 return emplace(key, value);
264 return emplace(key, std::move(value));
268 size_type node = get_storage_node_for(key);
269 auto& v = storage[node].val;
271 values.push_back(value);
272 v =
static_cast<size_type>(values.size() - 1);
280 size_type node = get_storage_node_for(key);
281 auto& v = storage[node].val;
283 values.push_back(std::move(value));
284 v =
static_cast<size_type>(values.size() - 1);
286 values[v] = std::move(value);
299 return static_cast<size_type>(values.size());
303 return storage.capacity() *
sizeof(inline_node)
304 + values.size() *
sizeof(Value);
308 storage.shrink_to_fit();
309 values.shrink_to_fit();
314 size_type children[2];
318 std::vector<inline_node> storage;
319 std::vector<Value> values;
321 auto do_init() ->
void {
322 if (storage.size() < 2) {
330 if (key.bits > bits_of<Key>) {
331 throw std::invalid_argument(
"key prefix longer than key length");
333 const bitset_type search = key.prefix;
336 for (std::size_t i : range<std::size_t>(key.bits - 1)) {
337 if (
auto n = storage[node].children[std::as_const(search)[i]]) {
340 storage.push_back({{0, 0}, node,
max});
341 node =
static_cast<size_type
>(storage.size() - 1);
342 storage[node].children[std::as_const(search)[i]] = node;
349 template <
typename V>
360 : tree_ptr{&
range.storage}
361 , values_ptr{&
range.values}
365 return (*values_ptr)[(*tree_ptr)[node].val];
368 return std::addressof((*values_ptr)[(*tree_ptr)[node].val]);
378 const std::vector<inline_node>* tree_ptr{};
379 const std::vector<Value>* values_ptr{};
394constexpr inline auto memswap(
unsigned char* A,
unsigned char* B,
395 std::size_t
size)
noexcept ->
void {
412inline auto memswap(
void* A,
void* B, std::size_t
size)
noexcept ->
void {
413 auto Ab =
static_cast<unsigned char*
>(A);
414 auto Bb =
static_cast<unsigned char*
>(B);
436template <
unsigned offset,
unsigned size,
typename Storage>
439 return (
get() >> offset) & ((1u <<
size) - 1);
443 get() &= ~(((1u <<
size) - 1) << offset);
445 get() |= (val & ((1u <<
size) - 1)) << offset;
448 operator Storage() const noexcept {
return (*
this)(); }
449 auto operator=(Storage val)
noexcept -> Storage {
return (*
this)(val); }
452 Storage&
get() noexcept {
return *
reinterpret_cast<Storage*
>(
this); }
453 const Storage&
get() const noexcept {
454 return *
reinterpret_cast<const Storage*
>(
this);
462namespace detail_bits {
472 template <
typename Parent,
typename ReturnT,
473 ReturnT (Parent::*Set)(ReturnT)
noexcept,
474 ReturnT (Parent::*Get)()
const noexcept>
477 constexpr auto operator=(ReturnT val)
noexcept -> ReturnT {
478 return (p->*Set)(val);
480 constexpr operator ReturnT() const noexcept {
return (p->*Get)(); }
491#define KBLIB_INTERNAL_BITFIELD_MACRO(offset, size, name, raw) \
492 static_assert(offset >= 0 and size > 0, \
493 "BITFIELD cannot have negative offset or size"); \
496 constexpr auto name##_get_impl() const noexcept->decltype(raw) { \
497 return (raw >> kblib::to_unsigned(offset)) \
498 & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u); \
502 KBLIB_NODISCARD constexpr auto name() const noexcept->decltype(raw) { \
503 return name##_get_impl(); \
507 constexpr auto name##_set_impl(const decltype(raw) val) noexcept->decltype( \
510 raw &= ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
511 << kblib::to_unsigned(offset)); \
513 raw |= (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
514 << kblib::to_unsigned(offset); \
519 constexpr auto name(const decltype(raw) val) noexcept->decltype(raw) { \
520 return name##_set_impl(val); \
523 KBLIB_NODISCARD constexpr auto name() noexcept->auto { \
524 using Parent = std::remove_pointer<decltype(this)>::type; \
525 return kblib::detail_bits::bitfield_proxy<Parent, decltype(raw), \
526 &Parent::name##_set_impl, \
527 &Parent::name##_get_impl>{ \
531 template <decltype(raw) val, decltype(raw) basis = 0> \
532 constexpr static decltype(raw) set_##name##_v \
534 & ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
535 << kblib::to_unsigned(offset))) \
536 | (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
537 << kblib::to_unsigned(offset); \
539 template <decltype(raw) basis> \
540 constexpr static decltype(raw) get_##name##_v \
541 = (basis >> kblib::to_unsigned(offset)) \
542 & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u); \
543 constexpr static std::size_t name##_shift_v = offset; \
544 constexpr static std::size_t name##_width_v = size;
546namespace detail_bits {
548 template <
typename Type,
typename Storage>
552 std::memcpy(&base, &val,
sizeof val);
555 operator Type() const noexcept {
557 std::memcpy(&ret, &base,
sizeof ret);
562 template <
typename Type,
typename Storage>
567 operator Type&()
noexcept {
569 std::memcpy(&base, &data,
sizeof data);
574 operator const Type&()
const noexcept {
576 std::memcpy(&base, &data,
sizeof data);
582 std::memcpy(&base, &data,
sizeof data);
591 template <
typename T>
595 template <
typename T, std::
size_t N>
599 template <
typename T>
604 template <
typename T, std::
size_t S>
608 template <
typename T, std::
size_t N, std::
size_t S>
612 template <
typename T, std::
size_t S>
614 using type = std::array<T, S /
sizeof(T)>;
617 template <
typename P,
typename Type, std::size_t S, std::size_t,
619 = is_aliasing_type_v<typename std::remove_extent<Type>::type>>
624 static_assert(std::is_trivially_copyable<type>::value,
625 "Type must be trivially copyable");
628 return pun_proxy<
type,
decltype(P::raw)>{
static_cast<P*
>(
this)->raw};
632 static_cast<const P*
>(
this)->raw};
636 template <
typename P,
typename Type, std::
size_t S, std::
size_t I>
641 return reinterpret_cast<type&
>(
static_cast<P*
>(
this)->raw);
644 return reinterpret_cast<const type&
>(
static_cast<const P*
>(
this)->raw);
648 template <
typename P,
typename Type, std::
size_t S, std::
size_t I>
653 return reinterpret_cast<type&
>(
static_cast<P*
>(
this)->raw);
656 return reinterpret_cast<const type&
>(
static_cast<const P*
>(
this)->raw);
660 template <std::size_t S,
typename I_S,
typename... Types>
663 template <std::size_t S, std::size_t... Is,
typename... Types>
665 :
pun_el<punner_impl<S, std::index_sequence<Is...>, Types...>, Types, S,
668 alignas(
std::max({
alignof(
typename std::remove_extent<
669 Types>::type)...})) unsigned
char raw[S]{};
672 template <
typename... Types>
678template <
typename... Types>
681 std::index_sequence_for<Types...>,
687 std::index_sequence_for<Types...>, Types...>;
688 using tuple_t = std::tuple<Types...>;
689 template <std::
size_t I>
690 using r_element_t =
typename std::tuple_element<I, tuple_t>::type;
692 static_assert(std::is_standard_layout<impl_t>::value,
"");
695 template <std::
size_t I>
697 template <std::
size_t I>
700 template <std::
size_t I>
702 static_assert(std::is_base_of<base_t<I>,
impl_t>::value,
"");
705 template <std::
size_t I>
709 template <std::
size_t I>
713 template <std::
size_t I>
723template <std::size_t I,
typename... Types>
728template <
typename... Types>
730 :
public std::integral_constant<std::size_t, sizeof...(Types)> {};
736template <std::size_t I,
typename... Types>
738 return p.template get<I>();
740template <std::size_t I,
typename... Types>
742 return p.template get<I>();
744template <std::size_t I,
typename... Types>
746 return p.template get<I>();
748template <std::size_t I,
typename... Types>
751 return p.template get<I>();
755template <
typename Type, auto Storage>
758 using sptr_t =
decltype(Storage);
759 using class_t = kblib::class_t<Storage>;
764 static_assert(
sizeof(Type) <=
sizeof(member_t),
765 "Type will not fit in the provided storage.");
766 static_assert(std::is_trivially_copyable_v<Type>,
767 "Type must be trivially copyable.");
769 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
770 "Storage type must be trivially copyable.");
773 return reinterpret_cast<class_t*
>(
this)->*Storage;
776 return reinterpret_cast<const class_t*
>(
this)->*Storage;
784 std::memcpy(&base(), &val,
sizeof val);
787 operator Type() const noexcept {
return (*
this)(); }
791template <
typename Type, std::
size_t N, auto Storage>
794 using class_t = kblib::class_t<Storage>;
795 using member_t = kblib::member_t<class_t, Storage>;
796 using type = std::array<Type, N>;
800 static_assert(
sizeof(type) <=
sizeof(member_t),
801 "Type will not fit in the provided storage.");
802 static_assert(std::is_trivially_copyable_v<type>,
803 "Type must be trivially copyable.");
805 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
806 "Storage type must be trivially copyable.");
809 return reinterpret_cast<class_t*
>(
this)->*Storage;
812 return reinterpret_cast<const class_t*
>(
this)->*Storage;
820 std::memcpy(&base(), &val,
sizeof val);
823 operator type() const noexcept {
return (*
this)(); }
834#if KBLIB_DEF_MACROS and not defined(BITFIELD)
863#define BITFIELD(offset, size, name, raw) \
864 KBLIB_INTERNAL_BITFIELD_MACRO(offset, size, name, raw)
iterator_t(const compact_bit_trie &range)
compact_bit_trie::difference_type difference_type
auto operator->() const noexcept -> pointer
auto operator++() -> iterator_t
auto operator*() const noexcept -> reference
std::bidirectional_iterator_tag iterator_category
auto memory_use() const noexcept -> std::size_t
auto insert(key_type key, const value_type &value) -> bool
const value_type * const_pointer
auto at(key_type key) const noexcept(false) -> const_reference
auto at(key_type key) noexcept(false) -> reference
uint_smallest_t< key_range > size_type
auto emplace(key_type key, Ts &&... args) -> bool
auto empty() const noexcept -> bool
auto insert_or_assign(key_type key, const value_type &value) -> reference
auto insert_or_assign(key_type key, value_type &&value) -> reference
auto size() const noexcept -> size_type
bool prune(key_type prefix)
std::bitset< bits_of< Key > > bitset_type
std::reverse_iterator< iterator > reverse_iterator
auto find_deep(key_type key, size_type depth=-1) const noexcept(false) -> const_reference
int_smallest_t< key_range > difference_type
const value_type & const_reference
auto insert(key_type key, value_type &&value) -> bool
auto find_deep(key_type key, size_type depth=-1) noexcept(false) -> reference
std::reverse_iterator< const_iterator > const_reverse_iterator
auto shrink_to_fit() -> void
auto operator()() const noexcept -> const_proxy_t
auto operator=(const Type(&val)[N]) noexcept -> proxy_t
auto operator()(const Type(&val)[N]) noexcept -> proxy_t
auto operator()(const Type val) noexcept -> proxy_t
auto operator=(const Type val) noexcept -> proxy_t
auto operator()() const noexcept -> const_proxy_t
This header provides some features of C++17 <type_traits> and other headers for C++14,...
constexpr std::size_t max_size
constexpr auto size(const C &c) -> decltype(c.size())
constexpr struct kblib::nums::max_t max
The main namespace in which all entities from kblib are defined.
auto memswap(void *A, void *B, std::size_t size) noexcept -> void
Swaps memory ranges.
typename int_smallest< I >::type int_smallest_t
constexpr auto filg2(const std::bitset< std::numeric_limits< std::uintmax_t >::digits > val) noexcept -> int
Floored integer binary logarithm. Returns floor(lb(val)).
constexpr auto range(Value min, Value max, Delta step=0) -> range_t< Value, Delta >
Constructs a range from beginning, end, and step amount. The range is half-open, that is min is in th...
typename member_of< T >::type member_of_t
auto get(const punner< Types... > &&p) noexcept -> decltype(auto)
typename uint_smallest< I >::type uint_smallest_t
Provides general utilities which do not fit in any more specific header.
Provides numerical and mathematical utilities.
Implements a bitfield abstraction. May be used in a union with other bitfields.
const Storage & get() const noexcept
auto operator&() -> void=delete
auto operator()(const Storage val) noexcept -> Storage
auto operator()() const noexcept -> Storage
auto operator=(Storage val) noexcept -> Storage
std::array< T, S/sizeof(T)> type
array_pun_proxy & operator=(const array_pun_proxy &)=delete
array_pun_proxy(array_pun_proxy &&)=delete
array_pun_proxy & operator=(array_pun_proxy &&)=delete
array_pun_proxy(const array_pun_proxy &)=delete
A proxy reference type for BITFIELD-declared bitfields.
constexpr auto operator=(ReturnT val) noexcept -> ReturnT
auto get() const noexcept -> decltype(auto)
auto get() noexcept -> decltype(auto)
auto get() noexcept -> decltype(auto)
auto get() const noexcept -> decltype(auto)
auto get() const noexcept -> auto
typename array_filter2< Type, S >::type type
auto get() noexcept -> auto
auto operator=(const Type val) noexcept -> pun_proxy &
auto get() &noexcept -> decltype(auto)
auto get() &&noexcept -> decltype(auto)
typename base_t< I >::type element_t
auto get() const &noexcept -> decltype(auto)
auto get() const &&noexcept -> decltype(auto)
typename kblib::punner< Types... >::template element_t< I > type
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Contains some type traits not in the standard library that are useful in the implementation of kblib.