--- /dev/null
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_CONSTEXPR_ARRAY_H_
+#define UTIL_CONSTEXPR_ARRAY_H_
+
+#include "is_swappable.h"
+#include <type_traits>
+#include <utility>
+#include <iterator>
+#include <stdexcept>
+
+namespace vulkan_cpu
+{
+namespace util
+{
+template <typename T, std::size_t N>
+struct Constexpr_array
+{
+ T values[N];
+ typedef T value_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef T &reference;
+ typedef const T &const_reference;
+ typedef T *pointer;
+ typedef const T *const_pointer;
+ typedef T *iterator;
+ typedef const T *const_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ constexpr T &at(std::size_t index)
+ {
+ if(index >= N)
+ throw std::out_of_range("Constexpr_array::at");
+ return values[index];
+ }
+ constexpr const T &at(std::size_t index) const
+ {
+ if(index >= N)
+ throw std::out_of_range("Constexpr_array::at");
+ return values[index];
+ }
+ constexpr T &operator[](std::size_t index) noexcept
+ {
+ return values[index];
+ }
+ constexpr const T &operator[](std::size_t index) const noexcept
+ {
+ return values[index];
+ }
+ constexpr T &front() noexcept
+ {
+ return values[0];
+ }
+ constexpr const T &front() const noexcept
+ {
+ return values[0];
+ }
+ constexpr T &back() noexcept
+ {
+ return values[N - 1];
+ }
+ constexpr const T &back() const noexcept
+ {
+ return values[N - 1];
+ }
+ constexpr T *data() noexcept
+ {
+ return values;
+ }
+ constexpr const T *data() const noexcept
+ {
+ return values;
+ }
+ constexpr iterator begin() noexcept
+ {
+ return values;
+ }
+ constexpr const_iterator begin() const noexcept
+ {
+ return values;
+ }
+ constexpr const_iterator cbegin() const noexcept
+ {
+ return values;
+ }
+ constexpr iterator end() noexcept
+ {
+ return values + N;
+ }
+ constexpr const_iterator end() const noexcept
+ {
+ return values + N;
+ }
+ constexpr const_iterator cend() const noexcept
+ {
+ return values + N;
+ }
+ constexpr reverse_iterator rbegin() noexcept
+ {
+ return reverse_iterator(end());
+ }
+ constexpr const_reverse_iterator rbegin() const noexcept
+ {
+ return const_reverse_iterator(end());
+ }
+ constexpr const_reverse_iterator crbegin() const noexcept
+ {
+ return const_reverse_iterator(end());
+ }
+ constexpr reverse_iterator rend() noexcept
+ {
+ return reverse_iterator(begin());
+ }
+ constexpr const_reverse_iterator rend() const noexcept
+ {
+ return const_reverse_iterator(begin());
+ }
+ constexpr const_reverse_iterator crend() const noexcept
+ {
+ return const_reverse_iterator(begin());
+ }
+ constexpr bool empty() const noexcept
+ {
+ return size() == 0;
+ }
+ constexpr std::size_t size() const noexcept
+ {
+ return N;
+ }
+ constexpr std::size_t max_size() const noexcept
+ {
+ return N;
+ }
+ constexpr void fill(const T &value) noexcept(std::is_nothrow_copy_assignable<T>::value)
+ {
+ for(auto &i : values)
+ i = value;
+ }
+ constexpr void swap(Constexpr_array &other) noexcept(is_nothrow_swappable_v<T>)
+ {
+ using std::swap;
+ for(std::size_t index = 0; index < size(); index++)
+ swap(values[index], other.values[index]);
+ }
+};
+
+template <typename T, std::size_t N>
+constexpr void swap(Constexpr_array<T, N> &a,
+ Constexpr_array<T, N> &b) noexcept(is_nothrow_swappable_v<T>)
+{
+ a.swap(b);
+}
+
+template <std::size_t I, typename T, std::size_t N>
+constexpr T &get(Constexpr_array<T, N> &v) noexcept
+{
+ static_assert(I < N, "");
+ return v[I];
+}
+
+template <std::size_t I, typename T, std::size_t N>
+constexpr const T &get(const Constexpr_array<T, N> &v) noexcept
+{
+ static_assert(I < N, "");
+ return v[I];
+}
+
+template <std::size_t I, typename T, std::size_t N>
+constexpr const T &&get(const Constexpr_array<T, N> &&v) noexcept
+{
+ static_assert(I < N, "");
+ return std::move(v[I]);
+}
+
+template <std::size_t I, typename T, std::size_t N>
+constexpr T &&get(Constexpr_array<T, N> &&v) noexcept
+{
+ static_assert(I < N, "");
+ return std::move(v[I]);
+}
+}
+}
+
+#endif /* UTIL_CONSTEXPR_ARRAY_H_ */
--- /dev/null
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_ENUM_H_
+#define UTIL_ENUM_H_
+
+#include <type_traits>
+#include <utility>
+#include "constexpr_array.h"
+#include "bitset.h"
+
+namespace vulkan_cpu
+{
+namespace util
+{
+template <typename T>
+void enum_traits_resolve_function(T) = delete;
+
+template <typename T>
+struct Enum_traits
+{
+private:
+ typedef decltype(enum_traits_resolve_function(T())) base;
+
+public:
+ static constexpr std::size_t value_count = base::values.size();
+ static constexpr Constexpr_array<T, value_count> values = base::values;
+ typedef typename std::underlying_type<T>::type underlying_type;
+
+private:
+ static constexpr bool is_compact_helper() noexcept
+ {
+ for(std::size_t i = 0; i < value_count; i++)
+ if(i
+ != static_cast<std::size_t>(static_cast<underlying_type>(values[i]))
+ - static_cast<std::size_t>(static_cast<underlying_type>(values.front())))
+ return false;
+ return true;
+ }
+
+public:
+ static constexpr bool is_compact = is_compact_helper();
+
+private:
+ template <std::size_t N>
+ static constexpr Constexpr_array<std::pair<T, std::size_t>, N> sort_value_index_map(
+ const std::pair<T, std::size_t> *value_index_map) noexcept
+ {
+ // uses merge sort algorithm
+ if(N == 0)
+ return {};
+ Constexpr_array<std::pair<T, std::size_t>, N> retval{};
+ if(N == 1)
+ {
+ retval[0] = value_index_map[0];
+ return;
+ }
+
+ // split
+ constexpr std::size_t split_index = N2 / 2;
+ constexpr std::size_t part1_size = split_index;
+ constexpr std::size_t part2_size = N2 - part1_size;
+ auto part1 = sort_value_index_map<part1_size>(value_index_map);
+ auto part2 = sort_value_index_map<part2_size>(value_index_map + split_index);
+
+ // merge, preserving order of equal values
+ std::size_t part1_index = 0;
+ std::size_t part2_index = 0;
+ std::size_t retval_index = 0;
+ while(part1_index < part1_size && part2_index < part2_size)
+ {
+ // we want to copy from part1 if values are equal
+ if(static_cast<underlying_type>(std::get<0>(part2[part2_index]))
+ < static_cast<underlying_type>(std::get<0>(part1[part1_index])))
+ retval[retval_index++] = part2[part2_index++];
+ else
+ retval[retval_index++] = part1[part1_index++];
+ }
+ while(part1_index < part1_size)
+ retval[retval_index++] = part1[part1_index++];
+ while(part2_index < part2_size)
+ retval[retval_index++] = part2[part2_index++];
+ return retval;
+ }
+ static constexpr Constexpr_array<std::pair<T, std::size_t>, value_count>
+ make_sorted_value_index_map() noexcept
+ {
+ Constexpr_array<std::pair<T, std::size_t>, N> retval{};
+ for(std::size_t i = 0; i < value_count; i++)
+ retval[i] = {values[i], i};
+ retval = sort_value_index_map<N>(retval.data());
+ return retval;
+ }
+
+public:
+ static constexpr Constexpr_array<std::pair<T, std::size_t>, value_count>
+ sorted_value_index_map = make_sorted_value_index_map();
+ static constexpr std::size_t npos = -1;
+ /** find first occurrence of value in values and return index if found, otherwise return npos */
+ static constexpr std::size_t find_value(T value) noexcept
+ {
+ std::size_t retval{};
+ constexpr std::size_t binary_search_transition = 8;
+ if(is_compact)
+ {
+ retval = static_cast<std::size_t>(static_cast<underlying_type>(value))
+ - static_cast<std::size_t>(static_cast<underlying_type>(values.front()));
+ }
+ else if(value_count < 8)
+ {
+ retval = -1;
+ for(std::size_t i = 0; i < value_count; i++)
+ {
+ if(values[i] == value)
+ {
+ retval = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ retval = 0;
+ std::size_t count = value_count;
+ while(count != 0)
+ {
+ std::size_t step = count / 2;
+ if(static_cast<underlying_type>(values[retval + step])
+ < static_cast<underlying_type>(value))
+ {
+ retval += step + 1;
+ count -= step + 1;
+ }
+ else
+ {
+ count = step;
+ }
+ }
+ }
+ if(retval >= value_count)
+ return npos;
+ return retval;
+ }
+};
+
+template <typename T>
+constexpr std::size_t Enum_traits<T>::value_count;
+
+template <typename T>
+constexpr Constexpr_array<T, Enum_traits<T>::value_count> Enum_traits<T>::values;
+
+template <typename T>
+constexpr bool Enum_traits<T>::is_compact;
+
+template <typename T>
+constexpr Constexpr_array<std::pair<T, std::size_t>, Enum_traits<T>::value_count>
+ Enum_traits<T>::sorted_value_index_map;
+
+template <typename T>
+constexpr std::size_t Enum_traits<T>::npos;
+
+namespace detail
+{
+template <typename Enum, Enum... Values>
+struct Default_enum_traits
+{
+ static constexpr Constexpr_array<Enum, sizeof...(Values)> values = {{Values...}};
+};
+
+template <typename Enum, Enum... Values>
+static constexpr Enum_values<Enum, sizeof...(Values)> Default_enum_traits<Enum, Values...>::values;
+#define vulkan_cpu_util_generate_enum_traits(...) \
+ ::vulkan_cpu::util::detail::Default_enum_traits<__VA_ARGS__> enum_traits_resolve_function(Enum);
+}
+
+template <typename T>
+class Enum_set
+{
+private:
+ util::bitset<Enum_traits<T>::value_count> bits;
+
+public:
+ constexpr enum_set() noexcept : bits(0)
+ {
+ }
+#warning finish
+};
+}
+}
+
+#endif /* UTIL_ENUM_H_ */