2 * Copyright 2017 Jacob Lifshay
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 #include <type_traits>
30 #include "constexpr_array.h"
38 void enum_traits_resolve_function(T
) = delete;
44 typedef decltype(enum_traits_resolve_function(T())) base
;
47 static constexpr std::size_t value_count
= base::values
.size();
48 static constexpr Constexpr_array
<T
, value_count
> values
= base::values
;
49 typedef typename
std::underlying_type
<T
>::type underlying_type
;
52 static constexpr bool is_compact_helper() noexcept
54 for(std::size_t i
= 0; i
< value_count
; i
++)
56 != static_cast<std::size_t>(static_cast<underlying_type
>(values
[i
]))
57 - static_cast<std::size_t>(static_cast<underlying_type
>(values
.front())))
63 static constexpr bool is_compact
= is_compact_helper();
64 struct Value_and_index
68 constexpr Value_and_index() noexcept
: value(), index()
71 constexpr Value_and_index(T value
, std::size_t index
) noexcept
: value(value
), index(index
)
77 template <std::size_t N
>
78 static constexpr Constexpr_array
<Value_and_index
, N
> sort_value_index_map(
79 const Value_and_index
*value_index_map
) noexcept
81 // uses merge sort algorithm
84 Constexpr_array
<Value_and_index
, N
> retval
{};
87 retval
[0] = value_index_map
[0];
92 constexpr std::size_t split_index
= N
/ 2;
93 constexpr std::size_t part1_size
= split_index
;
94 constexpr std::size_t part2_size
= N
- part1_size
;
95 auto part1
= sort_value_index_map
<part1_size
>(value_index_map
);
96 auto part2
= sort_value_index_map
<part2_size
>(value_index_map
+ split_index
);
98 // merge, preserving order of equal values
99 std::size_t part1_index
= 0;
100 std::size_t part2_index
= 0;
101 std::size_t retval_index
= 0;
102 while(part1_index
< part1_size
&& part2_index
< part2_size
)
104 // we want to copy from part1 if values are equal
105 if(static_cast<underlying_type
>(part2
[part2_index
].value
)
106 < static_cast<underlying_type
>(part1
[part1_index
].value
))
107 retval
[retval_index
++] = part2
[part2_index
++];
109 retval
[retval_index
++] = part1
[part1_index
++];
111 while(part1_index
< part1_size
)
112 retval
[retval_index
++] = part1
[part1_index
++];
113 while(part2_index
< part2_size
)
114 retval
[retval_index
++] = part2
[part2_index
++];
117 static constexpr Constexpr_array
<Value_and_index
, value_count
>
118 make_sorted_value_index_map() noexcept
120 Constexpr_array
<Value_and_index
, value_count
> retval
{};
121 for(std::size_t i
= 0; i
< value_count
; i
++)
122 retval
[i
] = {values
[i
], i
};
123 retval
= sort_value_index_map
<value_count
>(retval
.data());
128 static constexpr Constexpr_array
<Value_and_index
, value_count
> sorted_value_index_map
=
129 make_sorted_value_index_map();
130 static constexpr std::size_t npos
= -1;
131 /** find first occurrence of value in values and return index if found, otherwise return npos */
132 static constexpr std::size_t find_value(T value
) noexcept
134 std::size_t retval
{};
135 constexpr std::size_t binary_search_transition
= 8;
138 retval
= static_cast<std::size_t>(static_cast<underlying_type
>(value
))
139 - static_cast<std::size_t>(static_cast<underlying_type
>(values
.front()));
141 else if(value_count
< binary_search_transition
)
144 for(std::size_t i
= 0; i
< value_count
; i
++)
146 if(values
[i
] == value
)
156 std::size_t count
= value_count
;
159 std::size_t step
= count
/ 2;
160 if(static_cast<underlying_type
>(values
[retval
+ step
])
161 < static_cast<underlying_type
>(value
))
172 if(retval
>= value_count
)
178 template <typename T
>
179 constexpr std::size_t Enum_traits
<T
>::value_count
;
181 template <typename T
>
182 constexpr Constexpr_array
<T
, Enum_traits
<T
>::value_count
> Enum_traits
<T
>::values
;
184 template <typename T
>
185 constexpr bool Enum_traits
<T
>::is_compact
;
187 template <typename T
>
188 constexpr Constexpr_array
<typename Enum_traits
<T
>::Value_and_index
, Enum_traits
<T
>::value_count
>
189 Enum_traits
<T
>::sorted_value_index_map
;
191 template <typename T
>
192 constexpr std::size_t Enum_traits
<T
>::npos
;
196 template <typename Enum
, Enum
... Values
>
197 struct Default_enum_traits
199 static constexpr Constexpr_array
<Enum
, sizeof...(Values
)> values
= {{Values
...}};
202 template <typename Enum
, Enum
... Values
>
203 constexpr Constexpr_array
<Enum
, sizeof...(Values
)> Default_enum_traits
<Enum
, Values
...>::values
;
204 /** generate code for Enum_traits instantiation; use like
205 * <code>vulkan_cpu_util_generate_enum_traits(Enum, Enum::Value1, Enum::Value2, Enum::Value3,
207 #define vulkan_cpu_util_generate_enum_traits(Enum, ...) \
208 ::vulkan_cpu::util::detail::Default_enum_traits<Enum, __VA_ARGS__> \
209 enum_traits_resolve_function(Enum)
212 /** behaves like a std::set<T> */
213 template <typename T
>
217 typedef util::bitset
<Enum_traits
<T
>::value_count
> Bits
;
221 typedef T value_type
;
222 typedef std::size_t size_type
;
223 typedef std::ptrdiff_t difference_type
;
224 typedef T
&reference
;
225 typedef const T
&const_reference
;
227 typedef const T
*const_pointer
;
231 friend class Enum_set
;
234 typedef std::ptrdiff_t difference_type
;
235 typedef T value_type
;
236 typedef const T
*pointer
;
237 typedef const T
&reference
;
238 std::bidirectional_iterator_tag iterator_category
;
241 const Enum_set
*enum_set
;
245 constexpr iterator() noexcept
: enum_set(nullptr), index(0)
250 constexpr iterator(const Enum_set
*enum_set
, std::size_t index
) noexcept
251 : enum_set(enum_set
),
255 static constexpr iterator
first_at_or_after(const Enum_set
*enum_set
,
256 std::size_t index
) noexcept
258 return iterator(enum_set
, enum_set
->bits
.find_first(true, index
));
260 static constexpr iterator
first_at_or_before(const Enum_set
*enum_set
,
261 std::size_t index
) noexcept
263 return iterator(enum_set
, enum_set
->bits
.find_last(true, index
));
267 constexpr bool operator==(const iterator
&rt
) const noexcept
269 return index
== rt
.index
&& enum_set
== rt
.enum_set
;
271 constexpr bool operator!=(const iterator
&rt
) const noexcept
273 return !operator==(rt
);
275 constexpr iterator
&operator++() noexcept
277 *this = first_at_or_after(enum_set
, index
+ 1);
280 constexpr iterator
&operator--() noexcept
282 *this = first_at_or_before(enum_set
, index
- 1);
285 constexpr iterator
operator++(int) noexcept
291 constexpr iterator
operator--(int) noexcept
297 constexpr const T
&operator*() const noexcept
299 return Enum_traits
<T
>::values
[index
];
301 constexpr const T
*operator->() const noexcept
306 typedef iterator const_iterator
;
307 typedef std::reverse_iterator
<iterator
> reverse_iterator
;
308 typedef reverse_iterator reverse_const_iterator
;
314 constexpr Enum_set() noexcept
: bits(0)
317 template <typename Iter
>
318 constexpr Enum_set(Iter first
, Iter last
)
321 insert(std::move(first
), std::move(last
));
323 constexpr Enum_set(std::initializer_list
<T
> il
) noexcept
: Enum_set(il
.begin(), il
.end())
326 constexpr Enum_set
&operator=(std::initializer_list
<T
> il
) noexcept
328 *this = Enum_set(il
);
331 constexpr iterator
begin() const noexcept
333 return iterator::first_at_or_after(this, 0);
335 constexpr iterator
end() const noexcept
337 return iterator(this, Bits::npos
);
339 constexpr iterator
cbegin() const noexcept
343 constexpr iterator
cend() const noexcept
347 constexpr bool empty() const noexcept
351 constexpr std::size_t size() const noexcept
355 constexpr std::size_t max_size() const noexcept
359 constexpr void clear() noexcept
363 constexpr std::pair
<iterator
, bool> insert(T value
) noexcept
365 std::size_t index
= Enum_traits
<T
>::find_value(value
);
366 bool inserted
= !bits
[index
];
368 return {iterator(this, index
), inserted
};
370 constexpr iterator
insert(iterator hint
, T value
) noexcept
372 std::size_t index
= Enum_traits
<T
>::find_value(value
);
374 return iterator(this, index
);
376 template <typename Iter
>
377 constexpr void insert(Iter first
, Iter last
)
379 for(; first
!= last
; ++first
)
382 constexpr void insert(std::initializer_list
<T
> il
) noexcept
384 insert(il
.begin(), il
.end());
386 template <typename
... Args
>
387 std::pair
<iterator
, bool> emplace(Args
&&... args
)
389 return insert(T(std::forward
<Args
>(args
)...));
391 template <typename
... Args
>
392 iterator
emplace_hint(iterator hint
, Args
&&... args
)
394 return insert(hint
, T(std::forward
<Args
>(args
)...));
396 constexpr std::size_t erase(T value
) noexcept
398 std::size_t index
= Enum_traits
<T
>::find_value(value
);
399 std::size_t retval
= 0;
400 if(index
< bits
.size())
402 retval
= bits
[index
] ? 1 : 0;
407 constexpr iterator
erase(iterator pos
) noexcept
411 bits
[pos
.index
] = false;
414 constexpr iterator
erase(iterator first
, iterator last
) noexcept
417 first
= erase(first
);
420 /** invalidates all iterators, all references still valid because they are bound to static
422 constexpr void swap(Enum_set
&other
) noexcept
425 swap(bits
, other
.bits
);
427 constexpr std::size_t count(T value
) const noexcept
429 std::size_t index
= Enum_traits
<T
>::find_value(value
);
430 if(index
< bits
.size() && bits
[index
])
434 constexpr iterator
find(T value
) const noexcept
436 std::size_t index
= Enum_traits
<T
>::find_value(value
);
437 if(index
< bits
.size() && bits
[index
])
438 return iterator(this, index
);
441 std::pair
<iterator
, iterator
> equal_range(T value
) const noexcept
443 std::size_t index
= Enum_traits
<T
>::find_value(value
);
444 if(index
< bits
.size() && bits
[index
])
446 auto first
= iterator(this, index
);
449 return {first
, last
};
451 return {end(), end()};
457 #endif /* UTIL_ENUM_H_ */