kblib 0.2.3
General utilities library for modern C++
bits.h
Go to the documentation of this file.
1/* *****************************************************************************
2 * kblib is a general utility library for C++14 and C++17, intended to provide
3 * performant high-level abstractions and more expressive ways to do simple
4 * things.
5 *
6 * Copyright (c) 2021 killerbee
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * ****************************************************************************/
21
31#ifndef KBLIB_BITS_H
32#define KBLIB_BITS_H
33
34#include <algorithm>
35#include <array>
36#include <bitset>
37#include <limits>
38#include <memory>
39#include <utility>
40#include <vector>
41
42#include "fakestd.h"
43#include "simple.h"
44#include "stats.h"
45#include "tdecl.h"
46#include "traits.h"
47
48namespace KBLIB_NS {
49
50template <typename Int>
51constexpr int bits_of = std::numeric_limits<Int>::digits;
52
53#if KBLIB_USE_CXX17
54
55namespace detail_bits {
56
57 template <typename Key, typename Value>
58 class trie_node {
59 std::unique_ptr<std::array<trie_node, 4>> children;
60 unsigned char storage[sizeof(Value)]{};
61 bool exists = false;
62
63 template <typename... Args>
64 auto create(Args&&... args) noexcept(
65 std::is_nothrow_constructible<Value, Args...>::value) -> Value& {
66 clear();
67 // This variable must exist for exception safety. exists should not be
68 // set to true if an exception is thrown.
69 auto v = *new (storage) Value(args...);
70 exists = true;
71 return *v;
72 }
73
74 auto clear() noexcept -> void {
75 if (exists) {
76 get()->~Value();
77 }
78 return;
79 }
80
81 KBLIB_NODISCARD auto get() noexcept -> Value& {
82 assert(exists);
83 return *reinterpret_cast<Value*>(storage);
84 }
85 KBLIB_NODISCARD auto get() const noexcept -> const Value& {
86 assert(exists);
87 return *reinterpret_cast<Value*>(storage);
88 }
89 };
90
91} // namespace detail_bits
92/*
93template <typename Key, typename Value>
94class bit_trie {
95 public:
96 using value_type = Value;
97 using key_type = Key;
98 using mapped_type = Value;
99
100 static_assert(std::is_integral<key_type>::value,
101 "key_type must be an integral type.");
102 static_assert(std::is_nothrow_destructible<mapped_type>::value,
103 "mapped_type must be nothrow destructible.");
104
105 void insert(key_type, const mapped_type&);
106 void insert(key_type, mapped_type&&);
107
108 private:
109 std::array<detail_bits::trie_node, bits_of<key_type>> roots;
110};//*/
111
112template <typename Key, Key key_range, typename Value>
114 public:
115 struct key_type {
117 std::uint16_t bits : filg2(key_range);
118 };
119
120 using value_type = Value;
121 using mapped_type = Value;
127 using const_pointer = const value_type*;
128
129 template <typename V>
130 class iterator_t;
131
134 using reverse_iterator = std::reverse_iterator<iterator>;
135 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
136
137 using bitset_type = std::bitset<bits_of<Key>>;
138
139 static_assert(std::is_integral<Key>::value, "Key must be an integral type.");
140 static_assert(std::is_unsigned<Key>::value, "Key must be unsigned.");
142 "mapped_type must be nothrow destructible.");
143
145 noexcept(false) -> const_reference {
146 if (empty()) {
147 throw std::out_of_range("searched in an empty compact_bit_trie");
148 }
149 if (key.bits > bits_of<Key>) {
150 throw std::invalid_argument("key prefix longer than key length");
151 }
152 size_type node = 1;
153 const bitset_type search = key.prefix;
154 int idx = 0;
155 while (node and idx < key.bits) {
156 if (auto val = storage[node].val) {
157 return values[val];
158 } else {
159 node = storage[node].children[search[idx++]];
160 }
161 }
162 throw std::out_of_range("key not found in compact_bit_trie");
163 }
164
165 KBLIB_NODISCARD auto at(key_type key) noexcept(false) -> reference {
166 if (empty()) {
167 throw std::out_of_range("searched in an empty compact_bit_trie");
168 }
169 if (key.bits > bits_of<Key>) {
170 throw std::invalid_argument("key prefix longer than key length");
171 }
172 size_type node = 1;
173 const bitset_type search = key.prefix;
174 int idx = 0;
175 while (node and idx < key.bits) {
176 if (auto val = storage[node].val) {
177 return values[val];
178 } else {
179 node = storage[node].children[search[idx++]];
180 }
181 }
182 throw std::out_of_range("key not found in compact_bit_trie");
183 }
184
185 KBLIB_NODISCARD auto find_deep(key_type key, size_type depth = -1) const
186 noexcept(false) -> const_reference {
187 if (empty()) {
188 throw std::out_of_range("searched in an empty compact_bit_trie");
189 }
190 if (key.bits > bits_of<Key>) {
191 throw std::invalid_argument("key prefix longer than key length");
192 }
193 size_type node = 1;
194 size_type found = 0;
195 const bitset_type search = key.prefix;
196 int idx = 0;
197 while (node and idx < key.bits) {
198 if (auto val = storage[node].val) {
199 found = val;
200 if (depth--) {
201 break;
202 }
203 }
204 node = storage[node].children[search[idx++]];
205 }
206 if (found) {
207 return values[found];
208 } else {
209 throw std::out_of_range("key not found in compact_bit_trie");
210 }
211 }
212
214 size_type depth
215 = -1) noexcept(false) -> reference {
216 if (empty()) {
217 throw std::out_of_range("searched in an empty compact_bit_trie");
218 }
219 if (key.bits > bits_of<Key>) {
220 throw std::invalid_argument("key prefix longer than key length");
221 }
222 size_type node = 1;
223 size_type found = 0;
224 const bitset_type search = key.prefix;
225 int idx = 0;
226 while (node and idx < key.bits) {
227 if (auto val = storage[node].val) {
228 found = val;
229 if (depth--) {
230 break;
231 }
232 }
233 node = storage[node].children[search[idx++]];
234 }
235 if (found) {
236 return values[found];
237 } else {
238 throw std::out_of_range("key not found in compact_bit_trie");
239 }
240 }
241
242 KBLIB_NODISCARD auto empty() const noexcept -> bool {
243 return values.empty();
244 }
245
246 template <typename... Ts>
247 auto emplace(key_type key, Ts&&... args) -> bool {
248 size_type node = get_storage_node_for(key);
249 if (auto& v = storage[node].val; v != max) {
250 return false;
251 } else {
252 values.emplace_back(std::forward<Ts>(args)...);
253 v = static_cast<size_type>(values.size() - 1);
254 return true;
255 }
256 }
257
258 auto insert(key_type key, const value_type& value) -> bool {
259 return emplace(key, value);
260 }
261 auto insert(key_type key, value_type&& value) -> bool {
262 return emplace(key, std::move(value));
263 }
264
266 size_type node = get_storage_node_for(key);
267 auto& v = storage[node].val;
268 if (v != -1) {
269 values.push_back(value);
270 v = static_cast<size_type>(values.size() - 1);
271 } else {
272 values[v] = value;
273 }
274 return values[v];
275 }
276
278 size_type node = get_storage_node_for(key);
279 auto& v = storage[node].val;
280 if (v != -1) {
281 values.push_back(std::move(value));
282 v = static_cast<size_type>(values.size() - 1);
283 } else {
284 values[v] = std::move(value);
285 }
286 return values[v];
287 }
288
289 bool erase(key_type key);
290 bool prune(key_type prefix);
291 auto clear() -> void {
292 storage.clear();
293 values.clear();
294 }
295
296 KBLIB_NODISCARD auto size() const noexcept -> size_type {
297 return static_cast<size_type>(values.size());
298 }
299
300 KBLIB_NODISCARD auto memory_use() const noexcept -> std::size_t {
301 return storage.capacity() * sizeof(inline_node)
302 + values.size() * sizeof(Value);
303 }
304
305 auto shrink_to_fit() -> void {
306 storage.shrink_to_fit();
307 values.shrink_to_fit();
308 }
309
310 private:
311 struct inline_node {
312 size_type children[2];
313 size_type parent;
314 size_type val;
315 };
316 std::vector<inline_node> storage;
317 std::vector<Value> values;
318
319 auto do_init() -> void {
320 if (storage.size() < 2) {
321 storage.resize(2);
322 storage[0] = {};
323 storage[1] = {};
324 }
325 }
326
327 KBLIB_NODISCARD auto get_storage_node_for(key_type key) -> size_type {
328 if (key.bits > bits_of<Key>) {
329 throw std::invalid_argument("key prefix longer than key length");
330 }
331 const bitset_type search = key.prefix;
332 size_type node = 1;
333 do_init();
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]]) {
336 node = n;
337 } else {
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;
341 }
342 }
343 return node;
344 }
345
346 public:
347 template <typename V>
349 public:
350 using value_type = V;
351 using pointer = V*;
352 using reference = V&;
354 using iterator_category = std::bidirectional_iterator_tag;
355
356 iterator_t() = default;
358 : tree_ptr{&range.storage}
359 , values_ptr{&range.values}
360 , node{0} {}
361
362 auto operator*() const noexcept -> reference {
363 return (*values_ptr)[(*tree_ptr)[node].val];
364 }
365 auto operator->() const noexcept -> pointer {
366 return std::addressof((*values_ptr)[(*tree_ptr)[node].val]);
367 }
369
370 private:
372 : iterator_t(range) {
373 node = n_;
374 }
375
376 const std::vector<inline_node>* tree_ptr{};
377 const std::vector<Value>* values_ptr{};
378 size_type node{};
379 };
380};
381
392constexpr inline auto memswap(unsigned char* A, unsigned char* B,
393 std::size_t size) noexcept -> void {
394 for (auto i : range(size)) {
395 (swap)(A[i], B[i]);
396 }
397 return;
398}
399
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);
413 memswap(Ab, Bb, size);
414 return;
415}
416
417#endif
418
434template <unsigned offset, unsigned size, typename Storage>
435struct bitfield {
436 auto operator()() const noexcept -> Storage {
437 return (get() >> offset) & ((1u << size) - 1);
438 }
439 auto operator()(const Storage val) noexcept -> Storage {
440 // Clear the bits for this field
441 get() &= ~(((1u << size) - 1) << offset);
442 // Set the field
443 get() |= (val & ((1u << size) - 1)) << offset;
444 return val;
445 }
446 operator Storage() const noexcept { return (*this)(); }
447 auto operator=(Storage val) noexcept -> Storage { return (*this)(val); }
448
449 // allowed by pointer-interconvertibility when placed in a union
450 Storage& get() noexcept { return *reinterpret_cast<Storage*>(this); }
451 const Storage& get() const noexcept {
452 return *reinterpret_cast<const Storage*>(this);
453 }
454 // ensure that there is an object for pointer-interconvertibility to find
455 Storage raw_;
456 // Is this a good idea?
457 auto operator&() -> void = delete;
458};
459
460namespace detail_bits {
461
470 template <typename Parent, typename ReturnT,
471 ReturnT (Parent::*Set)(ReturnT) noexcept,
472 ReturnT (Parent::*Get)() const noexcept>
474 Parent* p;
475 constexpr auto operator=(ReturnT val) noexcept -> ReturnT {
476 return (p->*Set)(val);
477 }
478 constexpr operator ReturnT() const noexcept { return (p->*Get)(); }
479 };
480
481} // namespace detail_bits
482
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"); \
492 \
493 private: \
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); \
497 } \
498 \
499 public: \
500 KBLIB_NODISCARD constexpr auto name() const noexcept -> decltype(raw) { \
501 return name##_get_impl(); \
502 } \
503 \
504 private: \
505 constexpr auto name##_set_impl( \
506 const decltype(raw) val) noexcept -> decltype(raw) { \
507 /* Clear the bits for this field */ \
508 raw &= ~(((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u) \
509 << kblib::to_unsigned(offset)); \
510 /* Set the field */ \
511 raw |= (val & ((decltype(raw)(1) << kblib::to_unsigned(size)) - 1u)) \
512 << kblib::to_unsigned(offset); \
513 return val; \
514 } \
515 \
516 public: \
517 constexpr auto name(const decltype(raw) val) noexcept -> decltype(raw) { \
518 return name##_set_impl(val); \
519 } \
520 \
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>{ \
526 this}; \
527 } \
528 \
529 template <decltype(raw) val, decltype(raw) basis = 0> \
530 constexpr static decltype(raw) set_##name##_v \
531 = (basis \
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); \
536 \
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;
543
544namespace detail_bits {
545
546 template <typename Type, typename Storage>
547 struct pun_proxy {
548 Storage& base;
549 auto operator=(const Type val) noexcept -> pun_proxy& {
550 std::memcpy(&base, &val, sizeof val);
551 return *this;
552 }
553 operator Type() const noexcept {
554 Type ret;
555 std::memcpy(&ret, &base, sizeof ret);
556 return ret;
557 }
558 };
559
560 template <typename Type, typename Storage>
562 Storage& base;
563 Type data;
564 bool dirty = false;
565 operator Type&() noexcept {
566 if (dirty) {
567 std::memcpy(&base, &data, sizeof data);
568 }
569 dirty = true;
570 return data;
571 }
572 operator const Type&() const noexcept {
573 if (dirty) {
574 std::memcpy(&base, &data, sizeof data);
575 }
576 return data;
577 }
579 if (dirty) {
580 std::memcpy(&base, &data, sizeof data);
581 }
582 }
587 };
588
589 template <typename T>
591 using type = T;
592 };
593 template <typename T, std::size_t N>
595 using type = std::array<T, N>;
596 };
597 template <typename T>
599 using type = std::array<T, 0>;
600 };
601
602 template <typename T, std::size_t S>
604 using type = T;
605 };
606 template <typename T, std::size_t N, std::size_t S>
608 using type = std::array<T, N>;
609 };
610 template <typename T, std::size_t S>
612 using type = std::array<T, S / sizeof(T)>;
613 };
614
615 template <typename P, typename Type, std::size_t S, std::size_t,
616 bool aliases
617 = is_aliasing_type_v<typename std::remove_extent<Type>::type>>
618 struct pun_el {
619
621
623 "Type must be trivially copyable");
624
625 KBLIB_NODISCARD auto get() noexcept -> auto {
626 return pun_proxy<type, decltype(P::raw)>{static_cast<P*>(this)->raw};
627 }
628 KBLIB_NODISCARD auto get() const noexcept -> auto {
629 return pun_proxy<const type, const decltype(P::raw)>{
630 static_cast<const P*>(this)->raw};
631 }
632 };
633
634 template <typename P, typename Type, std::size_t S, std::size_t I>
635 struct pun_el<P, Type[S], S, I, true> {
636 using type = Type[S];
637
638 KBLIB_NODISCARD auto get() noexcept -> decltype(auto) {
639 return reinterpret_cast<type&>(static_cast<P*>(this)->raw);
640 }
641 KBLIB_NODISCARD auto get() const noexcept -> decltype(auto) {
642 return reinterpret_cast<const type&>(static_cast<const P*>(this)->raw);
643 }
644 };
645
646 template <typename P, typename Type, std::size_t S, std::size_t I>
647 struct pun_el<P, Type[], S, I, true> {
648 using type = Type[S];
649
650 KBLIB_NODISCARD auto get() noexcept -> decltype(auto) {
651 return reinterpret_cast<type&>(static_cast<P*>(this)->raw);
652 }
653 KBLIB_NODISCARD auto get() const noexcept -> decltype(auto) {
654 return reinterpret_cast<const type&>(static_cast<const P*>(this)->raw);
655 }
656 };
657
658 template <std::size_t S, typename I_S, typename... Types>
660
661 template <std::size_t S, std::size_t... Is, typename... Types>
662 struct punner_impl<S, std::index_sequence<Is...>, Types...>
663 : pun_el<punner_impl<S, std::index_sequence<Is...>, Types...>, Types, S,
664 Is>... {
665
666 alignas(std::max({alignof(typename std::remove_extent<
667 Types>::type)...})) unsigned char raw[S]{};
668 };
669
670 template <typename... Types>
671 constexpr std::size_t max_size
672 = std::max({sizeof(typename array_filter<Types>::type)...});
673
674} // namespace detail_bits
675
676template <typename... Types>
677struct punner
678 : private detail_bits::punner_impl<detail_bits::max_size<Types...>,
679 std::index_sequence_for<Types...>,
680 Types...> {
681 private:
682 constexpr static std::size_t storage_size = detail_bits::max_size<Types...>;
683 using impl_t
684 = detail_bits::punner_impl<storage_size,
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;
689
691
692 public:
693 template <std::size_t I>
695 template <std::size_t I>
696 using element_t = typename base_t<I>::type;
697
698 template <std::size_t I>
699 KBLIB_NODISCARD auto get() & noexcept -> decltype(auto) {
700 static_assert(std::is_base_of<base_t<I>, impl_t>::value, "");
701 return static_cast<base_t<I>&>(*this).get();
702 }
703 template <std::size_t I>
704 KBLIB_NODISCARD auto get() const& noexcept -> decltype(auto) {
705 return static_cast<const base_t<I>&>(*this).get();
706 }
707 template <std::size_t I>
708 KBLIB_NODISCARD auto get() && noexcept -> decltype(auto) {
709 return static_cast<base_t<I>&&>(*this).get();
710 }
711 template <std::size_t I>
712 KBLIB_NODISCARD auto get() const&& noexcept -> decltype(auto) {
713 return static_cast<const base_t<I>&&>(*this).get();
714 }
715};
716
717} // namespace KBLIB_NS
718
719namespace std {
720
721template <std::size_t I, typename... Types>
722struct tuple_element<I, kblib::punner<Types...>> {
723 using type = typename kblib::punner<Types...>::template element_t<I>;
724};
725
726template <typename... Types>
727struct tuple_size<kblib::punner<Types...>>
728 : public std::integral_constant<std::size_t, sizeof...(Types)> {};
729
730} // namespace std
731
732namespace KBLIB_NS {
733
734template <std::size_t I, typename... Types>
735KBLIB_NODISCARD auto get(punner<Types...>& p) noexcept -> decltype(auto) {
736 return p.template get<I>();
737}
738template <std::size_t I, typename... Types>
739KBLIB_NODISCARD auto get(const punner<Types...>& p) noexcept -> decltype(auto) {
740 return p.template get<I>();
741}
742template <std::size_t I, typename... Types>
743KBLIB_NODISCARD auto get(punner<Types...>&& p) noexcept -> decltype(auto) {
744 return p.template get<I>();
745}
746template <std::size_t I, typename... Types>
747KBLIB_NODISCARD auto get(const punner<Types...>&& p) noexcept
748 -> decltype(auto) {
749 return p.template get<I>();
750}
751
752#if KBLIB_USE_CXX17
753template <typename Type, auto Storage>
755 private:
756 using sptr_t = decltype(Storage);
757 using class_t = kblib::class_t<Storage>;
758 using member_t = kblib::member_of_t<sptr_t>;
761
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.");
766 static_assert(
767 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
768 "Storage type must be trivially copyable.");
769
770 KBLIB_NODISCARD auto base() noexcept -> member_t& {
771 return reinterpret_cast<class_t*>(this)->*Storage;
772 }
773 KBLIB_NODISCARD auto base() const noexcept -> const member_t& {
774 return reinterpret_cast<const class_t*>(this)->*Storage;
775 }
776
777 public:
778 KBLIB_NODISCARD auto operator()() const noexcept -> const_proxy_t {
779 return {base()};
780 }
781 auto operator()(const Type val) noexcept -> proxy_t {
782 std::memcpy(&base(), &val, sizeof val);
783 return {base()};
784 }
785 operator Type() const noexcept { return (*this)(); }
786 auto operator=(const Type val) noexcept -> proxy_t { return (*this)(val); }
787};
788
789template <typename Type, std::size_t N, auto Storage>
790class union_pun<Type[N], Storage> {
791 private:
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>;
797
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.");
802 static_assert(
803 std::is_trivially_copyable_v<std::remove_all_extents_t<member_t>>,
804 "Storage type must be trivially copyable.");
805
806 KBLIB_NODISCARD auto base() noexcept -> member_t& {
807 return reinterpret_cast<class_t*>(this)->*Storage;
808 }
809 KBLIB_NODISCARD auto base() const noexcept -> const member_t& {
810 return reinterpret_cast<const class_t*>(this)->*Storage;
811 }
812
813 public:
814 KBLIB_NODISCARD auto operator()() const noexcept -> const_proxy_t {
815 return {base()};
816 }
817 auto operator()(const Type (&val)[N]) noexcept -> proxy_t {
818 std::memcpy(&base(), &val, sizeof val);
819 return {base()};
820 }
821 operator type() const noexcept { return (*this)(); }
822 auto operator=(const Type (&val)[N]) noexcept -> proxy_t {
823 return (*this)(val);
824 }
825};
826#endif
827
828} // namespace KBLIB_NS
829
830#endif // KBLIB_BITS_H
831
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)
863#endif // KBLIB_DEF_MACROS and not defined(BITFIELD)
iterator_t(const compact_bit_trie &range)
Definition: bits.h:357
compact_bit_trie::difference_type difference_type
Definition: bits.h:353
auto operator->() const noexcept -> pointer
Definition: bits.h:365
auto operator++() -> iterator_t
Definition: bits.h:368
auto operator*() const noexcept -> reference
Definition: bits.h:362
std::bidirectional_iterator_tag iterator_category
Definition: bits.h:354
auto clear() -> void
Definition: bits.h:291
auto memory_use() const noexcept -> std::size_t
Definition: bits.h:300
auto insert(key_type key, const value_type &value) -> bool
Definition: bits.h:258
const value_type * const_pointer
Definition: bits.h:127
value_type * pointer
Definition: bits.h:126
auto at(key_type key) const noexcept(false) -> const_reference
Definition: bits.h:144
value_type & reference
Definition: bits.h:124
auto at(key_type key) noexcept(false) -> reference
Definition: bits.h:165
uint_smallest_t< key_range > size_type
Definition: bits.h:122
auto emplace(key_type key, Ts &&... args) -> bool
Definition: bits.h:247
auto empty() const noexcept -> bool
Definition: bits.h:242
auto insert_or_assign(key_type key, const value_type &value) -> reference
Definition: bits.h:265
auto insert_or_assign(key_type key, value_type &&value) -> reference
Definition: bits.h:277
auto size() const noexcept -> size_type
Definition: bits.h:296
bool prune(key_type prefix)
std::bitset< bits_of< Key > > bitset_type
Definition: bits.h:137
std::reverse_iterator< iterator > reverse_iterator
Definition: bits.h:134
auto find_deep(key_type key, size_type depth=-1) const noexcept(false) -> const_reference
Definition: bits.h:185
int_smallest_t< key_range > difference_type
Definition: bits.h:123
bool erase(key_type key)
const value_type & const_reference
Definition: bits.h:125
auto insert(key_type key, value_type &&value) -> bool
Definition: bits.h:261
auto find_deep(key_type key, size_type depth=-1) noexcept(false) -> reference
Definition: bits.h:213
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: bits.h:135
auto shrink_to_fit() -> void
Definition: bits.h:305
auto operator()() const noexcept -> const_proxy_t
Definition: bits.h:814
auto operator=(const Type(&val)[N]) noexcept -> proxy_t
Definition: bits.h:822
auto operator()(const Type(&val)[N]) noexcept -> proxy_t
Definition: bits.h:817
auto operator()(const Type val) noexcept -> proxy_t
Definition: bits.h:781
auto operator=(const Type val) noexcept -> proxy_t
Definition: bits.h:786
auto operator()() const noexcept -> const_proxy_t
Definition: bits.h:778
This header provides some features of C++17 <type_traits> and other headers for C++14,...
GeneratorWrapper< T > value(T &&value)
Definition: catch.hpp:4001
GeneratorWrapper< T > values(std::initializer_list< T > values)
Definition: catch.hpp:4005
constexpr std::size_t max_size
Definition: bits.h:672
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:383
constexpr struct kblib::nums::max_t max
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
auto memswap(void *A, void *B, std::size_t size) noexcept -> void
Swaps memory ranges.
Definition: bits.h:410
struct kblib::@0 swap
typename int_smallest< I >::type int_smallest_t
Definition: simple.h:202
constexpr auto filg2(const std::bitset< std::numeric_limits< std::uintmax_t >::digits > val) noexcept -> int
Floored integer binary logarithm. Returns floor(lb(val)).
Definition: simple.h:166
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...
Definition: iterators.h:621
typename member_of< T >::type member_of_t
Definition: traits.h:297
constexpr int bits_of
Definition: bits.h:51
auto get(const punner< Types... > &&p) noexcept -> decltype(auto)
Definition: bits.h:747
typename uint_smallest< I >::type uint_smallest_t
Definition: simple.h:199
Definition: bits.h:719
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.
Definition: bits.h:435
const Storage & get() const noexcept
Definition: bits.h:451
Storage raw_
Definition: bits.h:455
auto operator&() -> void=delete
auto operator()(const Storage val) noexcept -> Storage
Definition: bits.h:439
Storage & get() noexcept
Definition: bits.h:450
auto operator()() const noexcept -> Storage
Definition: bits.h:436
auto operator=(Storage val) noexcept -> Storage
Definition: bits.h:447
std::array< T, S/sizeof(T)> type
Definition: bits.h:612
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.
Definition: bits.h:473
constexpr auto operator=(ReturnT val) noexcept -> ReturnT
Definition: bits.h:475
auto get() const noexcept -> decltype(auto)
Definition: bits.h:653
auto get() noexcept -> decltype(auto)
Definition: bits.h:650
auto get() noexcept -> decltype(auto)
Definition: bits.h:638
auto get() const noexcept -> decltype(auto)
Definition: bits.h:641
auto get() const noexcept -> auto
Definition: bits.h:628
typename array_filter2< Type, S >::type type
Definition: bits.h:620
auto get() noexcept -> auto
Definition: bits.h:625
auto operator=(const Type val) noexcept -> pun_proxy &
Definition: bits.h:549
auto get() &noexcept -> decltype(auto)
Definition: bits.h:699
auto get() &&noexcept -> decltype(auto)
Definition: bits.h:708
typename base_t< I >::type element_t
Definition: bits.h:696
auto get() const &noexcept -> decltype(auto)
Definition: bits.h:704
auto get() const &&noexcept -> decltype(auto)
Definition: bits.h:712
typename kblib::punner< Types... >::template element_t< I > type
Definition: bits.h:723
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NS
Definition: tdecl.h:130
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:146
Contains some type traits not in the standard library that are useful in the implementation of kblib.
Definition: bits.cpp:172