50template <
typename Int>
51constexpr int bits_of = std::numeric_limits<Int>::digits;
55namespace detail_bits {
57 template <
typename Key,
typename Value>
59 std::unique_ptr<std::array<trie_node, 4>> children;
60 unsigned char storage[
sizeof(Value)]{};
63 template <
typename... Args>
64 auto create(Args&&... args)
noexcept(
65 std::is_nothrow_constructible<Value, Args...>
::value) -> Value& {
69 auto v = *
new (storage) Value(args...);
74 auto clear()
noexcept ->
void {
83 return *
reinterpret_cast<Value*
>(storage);
87 return *
reinterpret_cast<Value*
>(storage);
112template <
typename Key, Key key_range,
typename Value>
129 template <
typename V>
142 "mapped_type must be nothrow destructible.");
147 throw std::out_of_range(
"searched in an empty compact_bit_trie");
149 if (key.bits > bits_of<Key>) {
150 throw std::invalid_argument(
"key prefix longer than key length");
155 while (node and idx < key.bits) {
156 if (
auto val = storage[node].val) {
159 node = storage[node].children[search[idx++]];
162 throw std::out_of_range(
"key not found in compact_bit_trie");
167 throw std::out_of_range(
"searched in an empty compact_bit_trie");
169 if (key.bits > bits_of<Key>) {
170 throw std::invalid_argument(
"key prefix longer than key length");
175 while (node and idx < key.bits) {
176 if (
auto val = storage[node].val) {
179 node = storage[node].children[search[idx++]];
182 throw std::out_of_range(
"key not found in compact_bit_trie");
188 throw std::out_of_range(
"searched in an empty compact_bit_trie");
190 if (key.
bits > bits_of<Key>) {
191 throw std::invalid_argument(
"key prefix longer than key length");
197 while (node and idx < key.
bits) {
198 if (
auto val = storage[node].val) {
204 node = storage[node].children[search[idx++]];
209 throw std::out_of_range(
"key not found in compact_bit_trie");
217 throw std::out_of_range(
"searched in an empty compact_bit_trie");
219 if (key.
bits > bits_of<Key>) {
220 throw std::invalid_argument(
"key prefix longer than key length");
226 while (node and idx < key.
bits) {
227 if (
auto val = storage[node].val) {
233 node = storage[node].children[search[idx++]];
238 throw std::out_of_range(
"key not found in compact_bit_trie");
246 template <
typename... Ts>
248 size_type node = get_storage_node_for(key);
249 if (
auto& v = storage[node].val; v !=
max) {
252 values.emplace_back(std::forward<Ts>(args)...);
259 return emplace(key,
value);
262 return emplace(key, std::move(
value));
266 size_type node = get_storage_node_for(key);
267 auto& v = storage[node].val;
278 size_type node = get_storage_node_for(key);
279 auto& v = storage[node].val;
301 return storage.capacity() *
sizeof(inline_node)
302 +
values.size() *
sizeof(Value);
306 storage.shrink_to_fit();
312 size_type children[2];
316 std::vector<inline_node> storage;
317 std::vector<Value>
values;
319 auto do_init() ->
void {
320 if (storage.size() < 2) {
328 if (key.bits > bits_of<Key>) {
329 throw std::invalid_argument(
"key prefix longer than key length");
331 const bitset_type search = key.prefix;
334 for (std::size_t i : range<std::size_t>(key.bits - 1)) {
335 if (
auto n = storage[node].children[std::as_const(search)[i]]) {
338 storage.push_back({{0, 0}, node,
max});
339 node =
static_cast<size_type
>(storage.size() - 1);
340 storage[node].children[std::as_const(search)[i]] = node;
347 template <
typename V>
358 : tree_ptr{&
range.storage}
363 return (*values_ptr)[(*tree_ptr)[node].val];
366 return std::addressof((*values_ptr)[(*tree_ptr)[node].val]);
376 const std::vector<inline_node>* tree_ptr{};
377 const std::vector<Value>* values_ptr{};
392constexpr inline auto memswap(
unsigned char* A,
unsigned char* B,
393 std::size_t
size)
noexcept ->
void {
410inline auto memswap(
void* A,
void* B, std::size_t
size)
noexcept ->
void {
411 auto Ab =
static_cast<unsigned char*
>(A);
412 auto Bb =
static_cast<unsigned char*
>(B);
434template <
unsigned offset,
unsigned size,
typename Storage>
437 return (
get() >> offset) & ((1u <<
size) - 1);
441 get() &= ~(((1u <<
size) - 1) << offset);
443 get() |= (val & ((1u <<
size) - 1)) << offset;
446 operator Storage() const noexcept {
return (*
this)(); }
447 auto operator=(Storage val)
noexcept -> Storage {
return (*
this)(val); }
450 Storage&
get() noexcept {
return *
reinterpret_cast<Storage*
>(
this); }
451 const Storage&
get() const noexcept {
452 return *
reinterpret_cast<const Storage*
>(
this);
460namespace detail_bits {
470 template <
typename Parent,
typename ReturnT,
471 ReturnT (Parent::*Set)(ReturnT)
noexcept,
472 ReturnT (Parent::*Get)()
const noexcept>
475 constexpr auto operator=(ReturnT val)
noexcept -> ReturnT {
476 return (p->*Set)(val);
478 constexpr operator ReturnT() const noexcept {
return (p->*Get)(); }
489#define KBLIB_INTERNAL_BITFIELD_MACRO(offset, size, name, raw) \
490 static_assert(offset >= 0 and size > 0, \
491 "BITFIELD cannot have negative offset or size"); \
494 constexpr auto name##_get_impl() const noexcept -> decltype(raw) { \
495 return (raw >> kblib::to_unsigned(offset)) \
496 & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u); \
500 KBLIB_NODISCARD constexpr auto name() const noexcept -> decltype(raw) { \
501 return name##_get_impl(); \
505 constexpr auto name##_set_impl( \
506 const decltype(raw) val) noexcept -> decltype(raw) { \
508 raw &= ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
509 << kblib::to_unsigned(offset)); \
511 raw |= (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
512 << kblib::to_unsigned(offset); \
517 constexpr auto name(const decltype(raw) val) noexcept -> decltype(raw) { \
518 return name##_set_impl(val); \
521 KBLIB_NODISCARD constexpr auto name() noexcept -> auto { \
522 using Parent = std::remove_pointer<decltype(this)>::type; \
523 return kblib::detail_bits::bitfield_proxy<Parent, decltype(raw), \
524 &Parent::name##_set_impl, \
525 &Parent::name##_get_impl>{ \
529 template <decltype(raw) val, decltype(raw) basis = 0> \
530 constexpr static decltype(raw) set_##name##_v \
532 & ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
533 << kblib::to_unsigned(offset))) \
534 | (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
535 << kblib::to_unsigned(offset); \
537 template <decltype(raw) basis> \
538 constexpr static decltype(raw) get_##name##_v \
539 = (basis >> kblib::to_unsigned(offset)) \
540 & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u); \
541 constexpr static std::size_t name##_shift_v = offset; \
542 constexpr static std::size_t name##_width_v = size;
544namespace detail_bits {
546 template <
typename Type,
typename Storage>
550 std::memcpy(&base, &val,
sizeof val);
553 operator Type() const noexcept {
555 std::memcpy(&ret, &base,
sizeof ret);
560 template <
typename Type,
typename Storage>
565 operator Type&()
noexcept {
567 std::memcpy(&base, &data,
sizeof data);
572 operator const Type&()
const noexcept {
574 std::memcpy(&base, &data,
sizeof data);
580 std::memcpy(&base, &data,
sizeof data);
589 template <
typename T>
593 template <
typename T, std::
size_t N>
597 template <
typename T>
602 template <
typename T, std::
size_t S>
606 template <
typename T, std::
size_t N, std::
size_t S>
610 template <
typename T, std::
size_t S>
612 using type = std::array<T, S /
sizeof(T)>;
615 template <
typename P,
typename Type, std::size_t S, std::size_t,
617 = is_aliasing_type_v<typename std::remove_extent<Type>::type>>
623 "Type must be trivially copyable");
626 return pun_proxy<
type,
decltype(P::raw)>{
static_cast<P*
>(
this)->raw};
630 static_cast<const P*
>(
this)->raw};
634 template <
typename P,
typename Type, std::
size_t S, std::
size_t I>
639 return reinterpret_cast<type&
>(
static_cast<P*
>(
this)->raw);
642 return reinterpret_cast<const type&
>(
static_cast<const P*
>(
this)->raw);
646 template <
typename P,
typename Type, std::
size_t S, std::
size_t I>
651 return reinterpret_cast<type&
>(
static_cast<P*
>(
this)->raw);
654 return reinterpret_cast<const type&
>(
static_cast<const P*
>(
this)->raw);
658 template <std::size_t S,
typename I_S,
typename... Types>
661 template <std::size_t S, std::size_t... Is,
typename... Types>
663 :
pun_el<punner_impl<S, std::index_sequence<Is...>, Types...>, Types, S,
666 alignas(
std::max({
alignof(
typename std::remove_extent<
667 Types>::type)...})) unsigned
char raw[S]{};
670 template <
typename... Types>
676template <
typename... Types>
679 std::index_sequence_for<Types...>,
685 std::index_sequence_for<Types...>, Types...>;
686 using tuple_t = std::tuple<Types...>;
687 template <std::
size_t I>
688 using r_element_t =
typename std::tuple_element<I, tuple_t>::type;
693 template <std::
size_t I>
695 template <std::
size_t I>
698 template <std::
size_t I>
700 static_assert(std::is_base_of<base_t<I>,
impl_t>
::value,
"");
703 template <std::
size_t I>
707 template <std::
size_t I>
711 template <std::
size_t I>
721template <std::size_t I,
typename... Types>
726template <
typename... Types>
728 :
public std::integral_constant<std::size_t, sizeof...(Types)> {};
734template <std::size_t I,
typename... Types>
736 return p.template get<I>();
738template <std::size_t I,
typename... Types>
740 return p.template get<I>();
742template <std::size_t I,
typename... Types>
744 return p.template get<I>();
746template <std::size_t I,
typename... Types>
749 return p.template get<I>();
753template <
typename Type, auto Storage>
756 using sptr_t =
decltype(Storage);
757 using class_t = kblib::class_t<Storage>;
762 static_assert(
sizeof(Type) <=
sizeof(member_t),
763 "Type will not fit in the provided storage.");
764 static_assert(std::is_trivially_copyable_v<Type>,
765 "Type must be trivially copyable.");
767 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
768 "Storage type must be trivially copyable.");
771 return reinterpret_cast<class_t*
>(
this)->*Storage;
774 return reinterpret_cast<const class_t*
>(
this)->*Storage;
782 std::memcpy(&base(), &val,
sizeof val);
785 operator Type() const noexcept {
return (*
this)(); }
789template <
typename Type, std::
size_t N, auto Storage>
792 using class_t = kblib::class_t<Storage>;
793 using member_t = kblib::member_t<class_t, Storage>;
794 using type = std::array<Type, N>;
798 static_assert(
sizeof(type) <=
sizeof(member_t),
799 "Type will not fit in the provided storage.");
800 static_assert(std::is_trivially_copyable_v<type>,
801 "Type must be trivially copyable.");
803 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
804 "Storage type must be trivially copyable.");
807 return reinterpret_cast<class_t*
>(
this)->*Storage;
810 return reinterpret_cast<const class_t*
>(
this)->*Storage;
818 std::memcpy(&base(), &val,
sizeof val);
821 operator type() const noexcept {
return (*
this)(); }
832#if KBLIB_DEF_MACROS and not defined(BITFIELD)
861#define BITFIELD(offset, size, name, raw) \
862 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,...
GeneratorWrapper< T > value(T &&value)
GeneratorWrapper< T > values(std::initializer_list< T > values)
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.