/src/immer/immer/detail/util.hpp
Line | Count | Source |
1 | | // |
2 | | // immer: immutable data structures for C++ |
3 | | // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente |
4 | | // |
5 | | // This software is distributed under the Boost Software License, Version 1.0. |
6 | | // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt |
7 | | // |
8 | | |
9 | | #pragma once |
10 | | |
11 | | #include <immer/config.hpp> |
12 | | |
13 | | #include <cstddef> |
14 | | #include <memory> |
15 | | #include <new> |
16 | | #include <type_traits> |
17 | | |
18 | | #include <immer/detail/type_traits.hpp> |
19 | | |
20 | | #if defined(_MSC_VER) |
21 | | #include <intrin.h> // for __lzcnt* |
22 | | #endif |
23 | | |
24 | | namespace immer { |
25 | | namespace detail { |
26 | | |
27 | | template <typename T> |
28 | | const T* as_const(T* x) |
29 | | { |
30 | | return x; |
31 | | } |
32 | | |
33 | | template <typename T> |
34 | | const T& as_const(T& x) |
35 | 121k | { |
36 | 121k | return x; |
37 | 121k | } |
38 | | |
39 | | template <std::size_t Size, std::size_t Align> |
40 | | struct aligned_storage |
41 | | { |
42 | | struct type |
43 | | { |
44 | | alignas(Align) unsigned char data[Size]; |
45 | | }; |
46 | | }; |
47 | | |
48 | | template <std::size_t Size, std::size_t Align> |
49 | | using aligned_storage_t = typename aligned_storage<Size, Align>::type; |
50 | | |
51 | | template <typename T> |
52 | | using aligned_storage_for = |
53 | | typename aligned_storage<sizeof(T), alignof(T)>::type; |
54 | | |
55 | | /*! |
56 | | * CRTP class that allows using the storage immediately following an instance of |
57 | | * the derived class to store objects of type `T` (i.e. "trailing storage"). |
58 | | * |
59 | | * The class is guaranteed to be standard layout if the derived class is also |
60 | | * standard_layout. |
61 | | * |
62 | | * `EmptyStruct` should be set to `true` if the derived class is empty, this |
63 | | * allows the optimization of using the storage of the derived class as trailing |
64 | | * storage. |
65 | | */ |
66 | | template <typename Derived, typename T, bool EmptyStruct = false> |
67 | | struct with_trailing_storage; |
68 | | |
69 | | template <typename Derived, typename T> |
70 | | struct alignas(alignof(T)) with_trailing_storage<Derived, T, true> |
71 | | { |
72 | | using storage_type = T; |
73 | | |
74 | | T* get_storage_ptr() |
75 | 9.63M | { |
76 | 9.63M | check_base(); |
77 | 9.63M | return reinterpret_cast<T*>(this); |
78 | 9.63M | } |
79 | | |
80 | | const T* get_storage_ptr() const |
81 | | { |
82 | | check_base(); |
83 | | return reinterpret_cast<const T*>(this); |
84 | | } |
85 | | |
86 | | static constexpr size_t get_storage_offset() |
87 | 689k | { |
88 | 689k | check_base(); |
89 | 689k | return 0; |
90 | 689k | } |
91 | | |
92 | | private: |
93 | | static constexpr void check_base() |
94 | 10.3M | { |
95 | | // is_standard_layout requires that only one class in the hierarchy |
96 | | // contains non-static data members. Since this class contains one |
97 | | // member, the static_assert will only hold when the derived class is |
98 | | // empty. |
99 | 10.3M | static_assert(std::is_standard_layout<Derived>::value, |
100 | 10.3M | "Please remove 'true' if the derived class is non emtpy"); |
101 | 10.3M | } |
102 | | |
103 | | // Dummy field to make the base class non-empty. |
104 | | char _; |
105 | | }; |
106 | | |
107 | | template <typename Derived, typename T> |
108 | | struct alignas(alignof(T)) with_trailing_storage<Derived, T, false> |
109 | | { |
110 | | using storage_type = T; |
111 | | |
112 | | T* get_storage_ptr() |
113 | 48.8M | { |
114 | 48.8M | check_base(); |
115 | 48.8M | auto* base = static_cast<Derived*>(this); |
116 | 48.8M | return reinterpret_cast<T*>(base + 1); |
117 | 48.8M | } immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::collision_t, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, false>::get_storage_ptr() Line | Count | Source | 113 | 194k | { | 114 | 194k | check_base(); | 115 | 194k | auto* base = static_cast<Derived*>(this); | 116 | 194k | return reinterpret_cast<T*>(base + 1); | 117 | 194k | } |
immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::inner_t, immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>*, false>::get_storage_ptr() Line | Count | Source | 113 | 48.6M | { | 114 | 48.6M | check_base(); | 115 | 48.6M | auto* base = static_cast<Derived*>(this); | 116 | 48.6M | return reinterpret_cast<T*>(base + 1); | 117 | 48.6M | } |
|
118 | | |
119 | | const T* get_storage_ptr() const |
120 | 1.33M | { |
121 | 1.33M | check_base(); |
122 | 1.33M | auto* base = static_cast<const Derived*>(this); |
123 | 1.33M | return reinterpret_cast<const T*>(base + 1); |
124 | 1.33M | } immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::inner_t, immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>*, false>::get_storage_ptr() const Line | Count | Source | 120 | 1.30M | { | 121 | 1.30M | check_base(); | 122 | 1.30M | auto* base = static_cast<const Derived*>(this); | 123 | 1.30M | return reinterpret_cast<const T*>(base + 1); | 124 | 1.30M | } |
immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::collision_t, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, false>::get_storage_ptr() const Line | Count | Source | 120 | 28.3k | { | 121 | 28.3k | check_base(); | 122 | 28.3k | auto* base = static_cast<const Derived*>(this); | 123 | 28.3k | return reinterpret_cast<const T*>(base + 1); | 124 | 28.3k | } |
|
125 | | |
126 | | static constexpr size_t get_storage_offset() |
127 | 24.0M | { |
128 | 24.0M | check_base(); |
129 | 24.0M | return sizeof(Derived); |
130 | 24.0M | } immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::inner_t, immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>*, false>::get_storage_offset() Line | Count | Source | 127 | 24.0M | { | 128 | 24.0M | check_base(); | 129 | 24.0M | return sizeof(Derived); | 130 | 24.0M | } |
immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::collision_t, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, false>::get_storage_offset() Line | Count | Source | 127 | 42.8k | { | 128 | 42.8k | check_base(); | 129 | 42.8k | return sizeof(Derived); | 130 | 42.8k | } |
|
131 | | |
132 | | private: |
133 | | static constexpr void check_base() |
134 | 74.2M | { |
135 | 74.2M | static_assert(std::is_standard_layout<Derived>::value && |
136 | 74.2M | !std::is_empty<Derived>::value, |
137 | 74.2M | "Please add 'true' if the derived class is emtpy"); |
138 | 74.2M | } immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::inner_t, immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>*, false>::check_base() Line | Count | Source | 134 | 73.9M | { | 135 | 73.9M | static_assert(std::is_standard_layout<Derived>::value && | 136 | 73.9M | !std::is_empty<Derived>::value, | 137 | 73.9M | "Please add 'true' if the derived class is emtpy"); | 138 | 73.9M | } |
immer::detail::with_trailing_storage<immer::detail::hamts::node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::hash_key, immer::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >, colliding_hash_t, std::__1::equal_to<void>, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::equal_key, immer::memory_policy<immer::heap_policy<immer::cpp_heap>, immer::unsafe_refcount_policy, immer::no_lock_policy, immer::no_transience_policy, false, true>, 3u>::collision_t, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >, false>::check_base() Line | Count | Source | 134 | 265k | { | 135 | 265k | static_assert(std::is_standard_layout<Derived>::value && | 136 | 265k | !std::is_empty<Derived>::value, | 137 | 265k | "Please add 'true' if the derived class is emtpy"); | 138 | 265k | } |
|
139 | | }; |
140 | | |
141 | | template <typename T> |
142 | | T& auto_const_cast(const T& x) |
143 | 15.3M | { |
144 | 15.3M | return const_cast<T&>(x); |
145 | 15.3M | } |
146 | | template <typename T> |
147 | | T&& auto_const_cast(const T&& x) |
148 | | { |
149 | | return const_cast<T&&>(std::move(x)); |
150 | | } |
151 | | |
152 | | template <class T> |
153 | | inline auto destroy_at(T* p) noexcept |
154 | | -> std::enable_if_t<std::is_trivially_destructible<T>::value> |
155 | | { |
156 | | p->~T(); |
157 | | } |
158 | | |
159 | | template <class T> |
160 | | inline auto destroy_at(T* p) noexcept |
161 | | -> std::enable_if_t<!std::is_trivially_destructible<T>::value> |
162 | 924k | { |
163 | 924k | p->~T(); |
164 | 924k | } |
165 | | |
166 | | template <typename Iter1> |
167 | | constexpr bool can_trivially_detroy = std::is_trivially_destructible< |
168 | | typename std::iterator_traits<Iter1>::value_type>::value; |
169 | | |
170 | | template <class Iter> |
171 | | auto destroy(Iter, Iter last) noexcept |
172 | | -> std::enable_if_t<can_trivially_detroy<Iter>, Iter> |
173 | | { |
174 | | return last; |
175 | | } |
176 | | template <class Iter> |
177 | | auto destroy(Iter first, Iter last) noexcept |
178 | | -> std::enable_if_t<!can_trivially_detroy<Iter>, Iter> |
179 | 0 | { |
180 | 0 | for (; first != last; ++first) |
181 | 0 | detail::destroy_at(std::addressof(*first)); |
182 | 0 | return first; |
183 | 0 | } |
184 | | |
185 | | template <class Iter, class Size> |
186 | | auto destroy_n(Iter first, Size n) noexcept |
187 | | -> std::enable_if_t<can_trivially_detroy<Iter>, Iter> |
188 | | { |
189 | | return first + n; |
190 | | } |
191 | | template <class Iter, class Size> |
192 | | auto destroy_n(Iter first, Size n) noexcept |
193 | | -> std::enable_if_t<!can_trivially_detroy<Iter>, Iter> |
194 | 366k | { |
195 | 1.28M | for (; n > 0; (void) ++first, --n) |
196 | 922k | detail::destroy_at(std::addressof(*first)); |
197 | 366k | return first; |
198 | 366k | } |
199 | | |
200 | | template <typename Iter1, typename Iter2> |
201 | | constexpr bool can_trivially_copy = |
202 | | std::is_same<typename std::iterator_traits<Iter1>::value_type, |
203 | | typename std::iterator_traits<Iter2>::value_type>::value && |
204 | | std::is_trivially_copyable< |
205 | | typename std::iterator_traits<Iter1>::value_type>::value; |
206 | | |
207 | | template <typename Iter1, typename Iter2> |
208 | | auto uninitialized_move(Iter1 first, Iter1 last, Iter2 out) noexcept |
209 | | -> std::enable_if_t<can_trivially_copy<Iter1, Iter2>, Iter2> |
210 | | { |
211 | | return std::copy(first, last, out); |
212 | | } |
213 | | template <typename Iter1, typename Iter2> |
214 | | auto uninitialized_move(Iter1 first, Iter1 last, Iter2 out) |
215 | | -> std::enable_if_t<!can_trivially_copy<Iter1, Iter2>, Iter2> |
216 | | |
217 | 21.6k | { |
218 | 21.6k | using value_t = typename std::iterator_traits<Iter2>::value_type; |
219 | 21.6k | auto current = out; |
220 | 21.6k | IMMER_TRY { |
221 | 49.3k | for (; first != last; ++first, (void) ++current) { |
222 | 27.7k | ::new (const_cast<void*>(static_cast<const volatile void*>( |
223 | 27.7k | std::addressof(*current)))) value_t(std::move(*first)); |
224 | 27.7k | } |
225 | 21.6k | return current; |
226 | 21.6k | } |
227 | 21.6k | IMMER_CATCH (...) { |
228 | 0 | detail::destroy(out, current); |
229 | 0 | IMMER_RETHROW; |
230 | 0 | } |
231 | 21.6k | } |
232 | | |
233 | | template <typename SourceIter, typename Sent, typename SinkIter> |
234 | | auto uninitialized_copy(SourceIter first, Sent last, SinkIter out) noexcept |
235 | | -> std::enable_if_t<can_trivially_copy<SourceIter, SinkIter>, SinkIter> |
236 | | { |
237 | | return std::copy(first, last, out); |
238 | | } |
239 | | template <typename SourceIter, typename Sent, typename SinkIter> |
240 | | auto uninitialized_copy(SourceIter first, Sent last, SinkIter out) |
241 | | -> std::enable_if_t<!can_trivially_copy<SourceIter, SinkIter>, SinkIter> |
242 | 358k | { |
243 | 358k | using value_t = typename std::iterator_traits<SinkIter>::value_type; |
244 | 358k | auto current = out; |
245 | 358k | IMMER_TRY { |
246 | 1.14M | for (; first != last; ++first, (void) ++current) { |
247 | 789k | ::new (const_cast<void*>(static_cast<const volatile void*>( |
248 | 789k | std::addressof(*current)))) value_t(*first); |
249 | 789k | } |
250 | 358k | return current; |
251 | 358k | } |
252 | 358k | IMMER_CATCH (...) { |
253 | 0 | detail::destroy(out, current); |
254 | 0 | IMMER_RETHROW; |
255 | 0 | } |
256 | 358k | } |
257 | | |
258 | | template <typename Heap, typename T, typename... Args> |
259 | | T* make(Args&&... args) |
260 | 317k | { |
261 | 317k | auto ptr = Heap::allocate(sizeof(T)); |
262 | 317k | IMMER_TRY { |
263 | 317k | return new (ptr) T(std::forward<Args>(args)...); |
264 | 317k | } |
265 | 317k | IMMER_CATCH (...) { |
266 | 0 | Heap::deallocate(sizeof(T), ptr); |
267 | 0 | IMMER_RETHROW; |
268 | 0 | } |
269 | 317k | } immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >::holder* immer::detail::make<immer::debug_size_heap<immer::cpp_heap>, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >::holder, char const (&) [4]>(char const (&) [4]) Line | Count | Source | 260 | 41.3k | { | 261 | 41.3k | auto ptr = Heap::allocate(sizeof(T)); | 262 | 41.3k | IMMER_TRY { | 263 | 41.3k | return new (ptr) T(std::forward<Args>(args)...); | 264 | 41.3k | } | 265 | 41.3k | IMMER_CATCH (...) { | 266 | 0 | Heap::deallocate(sizeof(T), ptr); | 267 | 0 | IMMER_RETHROW; | 268 | 0 | } | 269 | 41.3k | } |
immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >::holder* immer::detail::make<immer::debug_size_heap<immer::cpp_heap>, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >::holder, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Line | Count | Source | 260 | 276k | { | 261 | 276k | auto ptr = Heap::allocate(sizeof(T)); | 262 | 276k | IMMER_TRY { | 263 | 276k | return new (ptr) T(std::forward<Args>(args)...); | 264 | 276k | } | 265 | 276k | IMMER_CATCH (...) { | 266 | 0 | Heap::deallocate(sizeof(T), ptr); | 267 | 0 | IMMER_RETHROW; | 268 | 0 | } | 269 | 276k | } |
immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >::holder* immer::detail::make<immer::debug_size_heap<immer::cpp_heap>, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> >::holder>() Line | Count | Source | 260 | 1 | { | 261 | 1 | auto ptr = Heap::allocate(sizeof(T)); | 262 | 1 | IMMER_TRY { | 263 | 1 | return new (ptr) T(std::forward<Args>(args)...); | 264 | 1 | } | 265 | 1 | IMMER_CATCH (...) { | 266 | 0 | Heap::deallocate(sizeof(T), ptr); | 267 | 0 | IMMER_RETHROW; | 268 | 0 | } | 269 | 1 | } |
|
270 | | |
271 | | struct not_supported_t |
272 | | {}; |
273 | | struct empty_t |
274 | | {}; |
275 | | |
276 | | template <typename T> |
277 | | struct exact_t |
278 | | { |
279 | | T value; |
280 | | exact_t(T v) |
281 | | : value{v} {}; |
282 | | }; |
283 | | |
284 | | template <typename T> |
285 | | inline constexpr auto clz_(T) -> not_supported_t |
286 | | { |
287 | | IMMER_UNREACHABLE; |
288 | | return {}; |
289 | | } |
290 | | #if defined(_MSC_VER) |
291 | | // inline auto clz_(unsigned short x) { return __lzcnt16(x); } |
292 | | // inline auto clz_(unsigned int x) { return __lzcnt(x); } |
293 | | // inline auto clz_(unsigned __int64 x) { return __lzcnt64(x); } |
294 | | #else |
295 | 0 | inline constexpr auto clz_(unsigned int x) { return __builtin_clz(x); } |
296 | 0 | inline constexpr auto clz_(unsigned long x) { return __builtin_clzl(x); } |
297 | 0 | inline constexpr auto clz_(unsigned long long x) { return __builtin_clzll(x); } |
298 | | #endif |
299 | | |
300 | | template <typename T> |
301 | | inline constexpr T log2_aux(T x, T r = 0) |
302 | | { |
303 | | return x <= 1 ? r : log2_aux(x >> 1, r + 1); |
304 | | } |
305 | | |
306 | | template <typename T> |
307 | | inline constexpr auto log2(T x) -> std:: |
308 | | enable_if_t<!std::is_same<decltype(clz_(x)), not_supported_t>::value, T> |
309 | | { |
310 | | return x == 0 ? 0 : sizeof(std::size_t) * 8 - 1 - clz_(x); |
311 | | } |
312 | | |
313 | | template <typename T> |
314 | | inline constexpr auto log2(T x) |
315 | | -> std::enable_if_t<std::is_same<decltype(clz_(x)), not_supported_t>::value, |
316 | | T> |
317 | | { |
318 | | return log2_aux(x); |
319 | | } |
320 | | |
321 | | template <typename T> |
322 | | constexpr T ipow(T num, unsigned int pow) |
323 | | { |
324 | | return pow == 0 ? 1 : num * ipow(num, pow - 1); |
325 | | } |
326 | | |
327 | | template <bool b, typename F> |
328 | | auto static_if(F&& f) -> std::enable_if_t<b> |
329 | | { |
330 | | std::forward<F>(f)(empty_t{}); |
331 | | } |
332 | | template <bool b, typename F> |
333 | | auto static_if(F&& f) -> std::enable_if_t<!b> |
334 | | { |
335 | | } |
336 | | |
337 | | template <bool b, typename R = void, typename F1, typename F2> |
338 | | auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t<b, R> |
339 | | { |
340 | | return std::forward<F1>(f1)(empty_t{}); |
341 | | } |
342 | | template <bool b, typename R = void, typename F1, typename F2> |
343 | | auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t<!b, R> |
344 | | { |
345 | | return std::forward<F2>(f2)(empty_t{}); |
346 | | } |
347 | | |
348 | | template <typename T, T value> |
349 | | struct constantly |
350 | | { |
351 | | template <typename... Args> |
352 | | T operator()(Args&&...) const |
353 | 494k | { |
354 | 494k | return value; |
355 | 494k | } immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > const* immer::detail::constantly<immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > const*, (immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > const*)0>::operator()<>() const Line | Count | Source | 353 | 1.84k | { | 354 | 1.84k | return value; | 355 | 1.84k | } |
unsigned long immer::detail::constantly<unsigned long, 1ul>::operator()<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >&>(std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::box<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true> > >&) const Line | Count | Source | 353 | 246k | { | 354 | 246k | return value; | 355 | 246k | } |
unsigned long immer::detail::constantly<unsigned long, 0ul>::operator()<>() const Line | Count | Source | 353 | 246k | { | 354 | 246k | return value; | 355 | 246k | } |
|
356 | | }; |
357 | | |
358 | | /*! |
359 | | * An alias to `std::distance` |
360 | | */ |
361 | | template <typename Iterator, |
362 | | typename Sentinel, |
363 | | std::enable_if_t<detail::std_distance_supports_v<Iterator, Sentinel>, |
364 | | bool> = true> |
365 | | typename std::iterator_traits<Iterator>::difference_type |
366 | | distance(Iterator first, Sentinel last) |
367 | | { |
368 | | return std::distance(first, last); |
369 | | } |
370 | | |
371 | | /*! |
372 | | * Equivalent of the `std::distance` applied to the sentinel-delimited |
373 | | * forward range @f$ [first, last) @f$ |
374 | | */ |
375 | | template <typename Iterator, |
376 | | typename Sentinel, |
377 | | std::enable_if_t< |
378 | | (!detail::std_distance_supports_v<Iterator, Sentinel>) &&detail:: |
379 | | is_forward_iterator_v<Iterator> && |
380 | | detail::compatible_sentinel_v<Iterator, Sentinel> && |
381 | | (!detail::is_subtractable_v<Sentinel, Iterator>), |
382 | | bool> = true> |
383 | | typename std::iterator_traits<Iterator>::difference_type |
384 | | distance(Iterator first, Sentinel last) |
385 | | { |
386 | | std::size_t result = 0; |
387 | | while (first != last) { |
388 | | ++first; |
389 | | ++result; |
390 | | } |
391 | | return result; |
392 | | } |
393 | | |
394 | | /*! |
395 | | * Equivalent of the `std::distance` applied to the sentinel-delimited |
396 | | * random access range @f$ [first, last) @f$ |
397 | | */ |
398 | | template <typename Iterator, |
399 | | typename Sentinel, |
400 | | std::enable_if_t< |
401 | | (!detail::std_distance_supports_v<Iterator, Sentinel>) &&detail:: |
402 | | is_forward_iterator_v<Iterator> && |
403 | | detail::compatible_sentinel_v<Iterator, Sentinel> && |
404 | | detail::is_subtractable_v<Sentinel, Iterator>, |
405 | | bool> = true> |
406 | | typename std::iterator_traits<Iterator>::difference_type |
407 | | distance(Iterator first, Sentinel last) |
408 | | { |
409 | | return last - first; |
410 | | } |
411 | | |
412 | | } // namespace detail |
413 | | } // namespace immer |