52 template <
typename Int>
53 constexpr
int bits_of = std::numeric_limits<Int>::digits;
57 namespace 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);
114 template <
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);
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();
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");
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{};
394 constexpr
inline auto memswap(
unsigned char* A,
unsigned char* B,
395 std::size_t
size) noexcept ->
void {
412 inline 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);
436 template <
unsigned offset,
unsigned size,
typename Storage>
439 return (
raw >> offset) & ((1u <<
size) - 1);
443 raw &= ~(((1u <<
size) - 1) << offset);
445 raw |= (val & ((1u <<
size) - 1)) << offset;
448 operator Storage() const noexcept {
return (*
this)(); }
449 auto operator=(Storage val) noexcept -> Storage {
return (*
this)(val); }
455 namespace detail_bits {
465 template <
typename Parent,
typename ReturnT,
466 ReturnT (Parent::*Set)(ReturnT) noexcept,
467 ReturnT (Parent::*Get)()
const noexcept>
470 constexpr
auto operator=(ReturnT val) noexcept -> ReturnT {
471 return (p->*Set)(val);
473 constexpr
operator ReturnT() const noexcept {
return (p->*Get)(); }
484 #define KBLIB_INTERNAL_BITFIELD_MACRO(offset, size, name, raw) \
485 static_assert(offset >= 0 and size > 0, \
486 "BITFIELD cannot have negative offset or size"); \
489 constexpr auto name##_get_impl() const noexcept->decltype(raw) { \
490 return (raw >> kblib::to_unsigned(offset)) \
491 & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u); \
495 KBLIB_NODISCARD constexpr auto name() const noexcept->decltype(raw) { \
496 return name##_get_impl(); \
500 constexpr auto name##_set_impl(const decltype(raw) val) noexcept->decltype( \
503 raw &= ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
504 << kblib::to_unsigned(offset)); \
506 raw |= (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
507 << kblib::to_unsigned(offset); \
512 constexpr auto name(const decltype(raw) val) noexcept->decltype(raw) { \
513 return name##_set_impl(val); \
516 KBLIB_NODISCARD constexpr auto name() noexcept->auto { \
517 using Parent = std::remove_pointer<decltype(this)>::type; \
518 return kblib::detail_bits::bitfield_proxy<Parent, decltype(raw), \
519 &Parent::name##_set_impl, \
520 &Parent::name##_get_impl>{ \
524 template <decltype(raw) val, decltype(raw) basis = 0> \
525 constexpr static decltype(raw) set_##name##_v \
527 & ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
528 << kblib::to_unsigned(offset))) \
529 | (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
530 << kblib::to_unsigned(offset); \
532 template <decltype(raw) basis> \
533 constexpr static decltype(raw) get_##name##_v \
534 = (basis >> kblib::to_unsigned(offset)) \
535 & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u); \
536 constexpr static std::size_t name##_shift_v = offset; \
537 constexpr static std::size_t name##_width_v = size;
539 namespace detail_bits {
541 template <
typename Type,
typename Storage>
545 std::memcpy(&base, &val,
sizeof val);
548 operator Type() const noexcept {
550 std::memcpy(&ret, &base,
sizeof ret);
555 template <
typename Type,
typename Storage>
560 operator Type&() noexcept {
562 std::memcpy(&base, &data,
sizeof data);
567 operator const Type&()
const noexcept {
569 std::memcpy(&base, &data,
sizeof data);
575 std::memcpy(&base, &data,
sizeof data);
584 template <
typename T>
588 template <
typename T, std::
size_t N>
592 template <
typename T>
597 template <
typename T, std::
size_t S>
601 template <
typename T, std::
size_t N, std::
size_t S>
605 template <
typename T, std::
size_t S>
607 using type = std::array<T, S /
sizeof(T)>;
610 template <
typename P,
typename Type, std::size_t S, std::size_t,
612 = is_aliasing_type_v<typename std::remove_extent<Type>::type>>
617 static_assert(std::is_trivially_copyable<type>::value,
618 "Type must be trivially copyable");
621 return pun_proxy<
type, decltype(P::raw)>{
static_cast<P*
>(
this)->raw};
625 static_cast<const P*
>(
this)->raw};
629 template <
typename P,
typename Type, std::
size_t S, std::
size_t I>
634 return reinterpret_cast<type&
>(
static_cast<P*
>(
this)->raw);
637 return reinterpret_cast<const type&
>(
static_cast<const P*
>(
this)->raw);
641 template <
typename P,
typename Type, std::
size_t S, std::
size_t I>
646 return reinterpret_cast<type&
>(
static_cast<P*
>(
this)->raw);
649 return reinterpret_cast<const type&
>(
static_cast<const P*
>(
this)->raw);
653 template <std::size_t S,
typename I_S,
typename... Types>
656 template <std::size_t S, std::size_t... Is,
typename... Types>
658 :
pun_el<punner_impl<S, std::index_sequence<Is...>, Types...>, Types, S,
661 alignas(
std::max({
alignof(
typename std::remove_extent<
662 Types>
::type)...})) unsigned
char raw[S]{};
665 template <
typename... Types>
671 template <
typename... Types>
674 std::index_sequence_for<Types...>,
680 std::index_sequence_for<Types...>, Types...>;
681 using tuple_t = std::tuple<Types...>;
682 template <std::
size_t I>
683 using r_element_t =
typename std::tuple_element<I, tuple_t>::type;
685 static_assert(std::is_standard_layout<impl_t>::value,
"");
688 template <std::
size_t I>
690 template <std::
size_t I>
693 template <std::
size_t I>
698 template <std::
size_t I>
702 template <std::
size_t I>
706 template <std::
size_t I>
716 template <std::size_t I,
typename... Types>
721 template <
typename... Types>
723 :
public std::integral_constant<std::size_t, sizeof...(Types)> {};
729 template <std::size_t I,
typename... Types>
731 return p.template get<I>();
733 template <std::size_t I,
typename... Types>
735 return p.template get<I>();
737 template <std::size_t I,
typename... Types>
739 return p.template get<I>();
741 template <std::size_t I,
typename... Types>
744 return p.template get<I>();
748 template <
typename Type, auto Storage>
751 using sptr_t = decltype(Storage);
752 using class_t = kblib::class_t<Storage>;
757 static_assert(
sizeof(Type) <=
sizeof(member_t),
758 "Type will not fit in the provided storage.");
759 static_assert(std::is_trivially_copyable_v<Type>,
760 "Type must be trivially copyable.");
762 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
763 "Storage type must be trivially copyable.");
766 return reinterpret_cast<class_t*
>(
this)->*Storage;
769 return reinterpret_cast<const class_t*
>(
this)->*Storage;
777 std::memcpy(&base(), &val,
sizeof val);
780 operator Type() const noexcept {
return (*
this)(); }
784 template <
typename Type, std::
size_t N, auto Storage>
787 using class_t = kblib::class_t<Storage>;
788 using member_t = kblib::member_t<class_t, Storage>;
789 using type = std::array<Type, N>;
793 static_assert(
sizeof(type) <=
sizeof(member_t),
794 "Type will not fit in the provided storage.");
795 static_assert(std::is_trivially_copyable_v<type>,
796 "Type must be trivially copyable.");
798 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
799 "Storage type must be trivially copyable.");
802 return reinterpret_cast<class_t*
>(
this)->*Storage;
805 return reinterpret_cast<const class_t*
>(
this)->*Storage;
813 std::memcpy(&base(), &val,
sizeof val);
816 operator type() const noexcept {
return (*
this)(); }
827 #if KBLIB_DEF_MACROS and not defined(BITFIELD)
856 #define BITFIELD(offset, size, name, raw) \
857 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 struct kblib::nums::max_t max
The main namespace in which all entities from kblib are defined.
constexpr auto size(const C &c) -> decltype(c.size())
constexpr auto memswap(unsigned char *A, unsigned char *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(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.
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(const array_pun_proxy &)=delete
array_pun_proxy & operator=(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.