summaryrefslogtreecommitdiffstats
path: root/contrib/frozen
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/frozen')
-rw-r--r--contrib/frozen/AUTHORS3
-rw-r--r--contrib/frozen/CMakeLists.txt12
-rw-r--r--contrib/frozen/LICENSE202
-rw-r--r--contrib/frozen/include/frozen/algorithm.h197
-rw-r--r--contrib/frozen/include/frozen/bits/algorithms.h229
-rw-r--r--contrib/frozen/include/frozen/bits/basic_types.h200
-rw-r--r--contrib/frozen/include/frozen/bits/constexpr_assert.h40
-rw-r--r--contrib/frozen/include/frozen/bits/defines.h58
-rw-r--r--contrib/frozen/include/frozen/bits/elsa.h50
-rw-r--r--contrib/frozen/include/frozen/bits/exceptions.h39
-rw-r--r--contrib/frozen/include/frozen/bits/pmh.h240
-rw-r--r--contrib/frozen/include/frozen/bits/version.h30
-rw-r--r--contrib/frozen/include/frozen/map.h323
-rw-r--r--contrib/frozen/include/frozen/random.h90
-rw-r--r--contrib/frozen/include/frozen/set.h220
-rw-r--r--contrib/frozen/include/frozen/string.h152
-rw-r--r--contrib/frozen/include/frozen/unordered_map.h197
-rw-r--r--contrib/frozen/include/frozen/unordered_set.h147
18 files changed, 2429 insertions, 0 deletions
diff --git a/contrib/frozen/AUTHORS b/contrib/frozen/AUTHORS
new file mode 100644
index 0000000..d83d0f8
--- /dev/null
+++ b/contrib/frozen/AUTHORS
@@ -0,0 +1,3 @@
+serge-sans-paille <sguelton@quarkslab.com>
+Jérôme Dumesnil <jerome.dumesnil@gmail.com>
+Chris Beck <chbeck@tesla.com>
diff --git a/contrib/frozen/CMakeLists.txt b/contrib/frozen/CMakeLists.txt
new file mode 100644
index 0000000..185378d
--- /dev/null
+++ b/contrib/frozen/CMakeLists.txt
@@ -0,0 +1,12 @@
+target_sources(frozen-headers INTERFACE
+ "${prefix}/frozen/algorithm.h"
+ "${prefix}/frozen/map.h"
+ "${prefix}/frozen/random.h"
+ "${prefix}/frozen/set.h"
+ "${prefix}/frozen/string.h"
+ "${prefix}/frozen/unordered_map.h"
+ "${prefix}/frozen/unordered_set.h"
+ "${prefix}/frozen/bits/algorithms.h"
+ "${prefix}/frozen/bits/basic_types.h"
+ "${prefix}/frozen/bits/elsa.h"
+ "${prefix}/frozen/bits/pmh.h")
diff --git a/contrib/frozen/LICENSE b/contrib/frozen/LICENSE
new file mode 100644
index 0000000..5b4b9bd
--- /dev/null
+++ b/contrib/frozen/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2017 Quarkslab
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/contrib/frozen/include/frozen/algorithm.h b/contrib/frozen/include/frozen/algorithm.h
new file mode 100644
index 0000000..a543eb3
--- /dev/null
+++ b/contrib/frozen/include/frozen/algorithm.h
@@ -0,0 +1,197 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_ALGORITHM_H
+#define FROZEN_LETITGO_ALGORITHM_H
+
+#include "frozen/bits/basic_types.h"
+#include "frozen/bits/version.h"
+#include "frozen/string.h"
+
+namespace frozen {
+
+// 'search' implementation if C++17 is not available
+// https://en.cppreference.com/w/cpp/algorithm/search
+template<class ForwardIterator, class Searcher>
+ForwardIterator search(ForwardIterator first, ForwardIterator last, const Searcher & searcher)
+{
+ return searcher(first, last).first;
+}
+
+// text book implementation from
+// https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
+
+template <std::size_t size> class knuth_morris_pratt_searcher {
+ bits::carray<std::ptrdiff_t, size> step_;
+ bits::carray<char, size> needle_;
+
+ static constexpr bits::carray<std::ptrdiff_t, size>
+ build_kmp_cache(char const (&needle)[size + 1]) {
+ std::ptrdiff_t cnd = 0;
+ bits::carray<std::ptrdiff_t, size> cache;
+
+ cache.fill(-1);
+ for (std::size_t pos = 1; pos < size; ++pos) {
+ if (needle[pos] == needle[cnd]) {
+ cache[pos] = cache[cnd];
+ cnd += 1;
+ } else {
+ cache[pos] = cnd;
+ cnd = cache[cnd];
+ while (cnd >= 0 && needle[pos] != needle[cnd])
+ cnd = cache[cnd];
+ cnd += 1;
+ }
+ }
+ return cache;
+ }
+
+public:
+ constexpr knuth_morris_pratt_searcher(char const (&needle)[size + 1])
+ : step_{build_kmp_cache(needle)}, needle_(needle) {}
+
+ template <class ForwardIterator>
+ constexpr std::pair<ForwardIterator, ForwardIterator> operator()(ForwardIterator first, ForwardIterator last) const {
+ std::size_t i = 0;
+ ForwardIterator iter = first;
+ while (iter != last) {
+ if (needle_[i] == *iter) {
+ if (i == (size - 1))
+ return { iter - i, iter - i + size };
+ ++i;
+ ++iter;
+ } else {
+ if (step_[i] > -1) {
+ i = step_[i];
+ } else {
+ ++iter;
+ i = 0;
+ }
+ }
+ }
+ return { last, last };
+ }
+};
+
+template <std::size_t N>
+constexpr knuth_morris_pratt_searcher<N - 1> make_knuth_morris_pratt_searcher(char const (&needle)[N]) {
+ return {needle};
+}
+
+// text book implementation from
+// https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm
+
+template <std::size_t size> class boyer_moore_searcher {
+ using skip_table_type = bits::carray<std::ptrdiff_t, sizeof(char) << 8>;
+ using suffix_table_type = bits::carray<std::ptrdiff_t, size>;
+
+ skip_table_type skip_table_;
+ suffix_table_type suffix_table_;
+ bits::carray<char, size> needle_;
+
+ constexpr auto build_skip_table(char const (&needle)[size + 1]) {
+ skip_table_type skip_table;
+
+ skip_table.fill(size);
+ for (std::size_t i = 0; i < size - 1; ++i)
+ skip_table[needle[i]] -= i + 1;
+ return skip_table;
+ }
+
+ constexpr bool is_prefix(char const (&needle)[size + 1], std::size_t pos) {
+ std::size_t suffixlen = size - pos;
+
+ for (std::size_t i = 0; i < suffixlen; i++) {
+ if (needle[i] != needle[pos + i])
+ return false;
+ }
+ return true;
+ }
+
+ constexpr std::size_t suffix_length(char const (&needle)[size + 1],
+ std::size_t pos) {
+ // increment suffix length slen to the first mismatch or beginning
+ // of the word
+ for (std::size_t slen = 0; slen < pos ; slen++)
+ if (needle[pos - slen] != needle[size - 1 - slen])
+ return slen;
+
+ return pos;
+ }
+
+ constexpr auto build_suffix_table(char const (&needle)[size + 1]) {
+ suffix_table_type suffix;
+ std::ptrdiff_t last_prefix_index = size - 1;
+
+ // first loop
+ for (std::ptrdiff_t p = size - 1; p >= 0; p--) {
+ if (is_prefix(needle, p + 1))
+ last_prefix_index = p + 1;
+
+ suffix[p] = last_prefix_index + (size - 1 - p);
+ }
+
+ // second loop
+ for (std::size_t p = 0; p < size - 1; p++) {
+ auto slen = suffix_length(needle, p);
+ if (needle[p - slen] != needle[size - 1 - slen])
+ suffix[size - 1 - slen] = size - 1 - p + slen;
+
+ }
+ return suffix;
+ }
+
+public:
+ constexpr boyer_moore_searcher(char const (&needle)[size + 1])
+ : skip_table_{build_skip_table(needle)},
+ suffix_table_{build_suffix_table(needle)},
+ needle_(needle) {}
+
+ template <class ForwardIterator>
+ constexpr std::pair<ForwardIterator, ForwardIterator> operator()(ForwardIterator first, ForwardIterator last) const {
+ if (size == 0)
+ return { first, first + size };
+
+ ForwardIterator iter = first + size - 1;
+ while (iter < last) {
+ std::ptrdiff_t j = size - 1;
+ while (j > 0 && (*iter == needle_[j])) {
+ --iter;
+ --j;
+ }
+ if (*iter == needle_[0])
+ return { iter, iter + size};
+
+ iter += std::max(skip_table_[*iter], suffix_table_[j]);
+ }
+ return { last, last + size};
+ }
+};
+
+template <std::size_t N>
+constexpr boyer_moore_searcher<N - 1> make_boyer_moore_searcher(char const (&needle)[N]) {
+ return {needle};
+}
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/bits/algorithms.h b/contrib/frozen/include/frozen/bits/algorithms.h
new file mode 100644
index 0000000..8d1ffbc
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/algorithms.h
@@ -0,0 +1,229 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_BITS_ALGORITHMS_H
+#define FROZEN_LETITGO_BITS_ALGORITHMS_H
+
+#include "frozen/bits/basic_types.h"
+
+#include <limits>
+#include <tuple>
+
+namespace frozen {
+
+namespace bits {
+
+auto constexpr next_highest_power_of_two(std::size_t v) {
+ // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ constexpr auto trip_count = std::numeric_limits<decltype(v)>::digits;
+ v--;
+ for(std::size_t i = 1; i < trip_count; i <<= 1)
+ v |= v >> i;
+ v++;
+ return v;
+}
+
+template<class T>
+auto constexpr log(T v) {
+ std::size_t n = 0;
+ while (v > 1) {
+ n += 1;
+ v >>= 1;
+ }
+ return n;
+}
+
+constexpr std::size_t bit_weight(std::size_t n) {
+ return (n <= 8*sizeof(unsigned int))
+ + (n <= 8*sizeof(unsigned long))
+ + (n <= 8*sizeof(unsigned long long))
+ + (n <= 128);
+}
+
+unsigned int select_uint_least(std::integral_constant<std::size_t, 4>);
+unsigned long select_uint_least(std::integral_constant<std::size_t, 3>);
+unsigned long long select_uint_least(std::integral_constant<std::size_t, 2>);
+template<std::size_t N>
+unsigned long long select_uint_least(std::integral_constant<std::size_t, N>) {
+ static_assert(N < 2, "unsupported type size");
+ return {};
+}
+
+
+template<std::size_t N>
+using select_uint_least_t = decltype(select_uint_least(std::integral_constant<std::size_t, bit_weight(N)>()));
+
+template <typename Iter, typename Compare>
+constexpr auto min_element(Iter begin, const Iter end,
+ Compare const &compare) {
+ auto result = begin;
+ while (begin != end) {
+ if (compare(*begin, *result)) {
+ result = begin;
+ }
+ ++begin;
+ }
+ return result;
+}
+
+template <class T>
+constexpr void cswap(T &a, T &b) {
+ auto tmp = a;
+ a = b;
+ b = tmp;
+}
+
+template <class T, class U>
+constexpr void cswap(std::pair<T, U> & a, std::pair<T, U> & b) {
+ cswap(a.first, b.first);
+ cswap(a.second, b.second);
+}
+
+template <class... Tys, std::size_t... Is>
+constexpr void cswap(std::tuple<Tys...> &a, std::tuple<Tys...> &b, std::index_sequence<Is...>) {
+ using swallow = int[];
+ (void) swallow{(cswap(std::get<Is>(a), std::get<Is>(b)), 0)...};
+}
+
+template <class... Tys>
+constexpr void cswap(std::tuple<Tys...> &a, std::tuple<Tys...> &b) {
+ cswap(a, b, std::make_index_sequence<sizeof...(Tys)>());
+}
+
+template <typename Iterator, class Compare>
+constexpr Iterator partition(Iterator left, Iterator right, Compare const &compare) {
+ auto pivot = left + (right - left) / 2;
+ auto value = *pivot;
+ cswap(*right, *pivot);
+ for (auto it = left; 0 < right - it; ++it) {
+ if (compare(*it, value)) {
+ cswap(*it, *left);
+ left++;
+ }
+ }
+ cswap(*right, *left);
+ return left;
+}
+
+template <typename Iterator, class Compare>
+constexpr void quicksort(Iterator left, Iterator right, Compare const &compare) {
+ while (0 < right - left) {
+ auto new_pivot = bits::partition(left, right, compare);
+ quicksort(left, new_pivot, compare);
+ left = new_pivot + 1;
+ }
+}
+
+template <typename T, std::size_t N, class Compare>
+constexpr bits::carray<T, N> quicksort(bits::carray<T, N> const &array,
+ Compare const &compare) {
+ bits::carray<T, N> res = array;
+ quicksort(res.begin(), res.end() - 1, compare);
+ return res;
+}
+
+template <class T, class Compare> struct LowerBound {
+ T const &value_;
+ Compare const &compare_;
+ constexpr LowerBound(T const &value, Compare const &compare)
+ : value_(value), compare_(compare) {}
+
+ template <class ForwardIt>
+ inline constexpr ForwardIt doit_fast(ForwardIt first,
+ std::integral_constant<std::size_t, 0>) {
+ return first;
+ }
+
+ template <class ForwardIt, std::size_t N>
+ inline constexpr ForwardIt doit_fast(ForwardIt first,
+ std::integral_constant<std::size_t, N>) {
+ auto constexpr step = N / 2;
+ static_assert(N/2 == N - N / 2 - 1, "power of two minus 1");
+ auto it = first + step;
+ auto next_it = compare_(*it, value_) ? it + 1 : first;
+ return doit_fast(next_it, std::integral_constant<std::size_t, N / 2>{});
+ }
+
+ template <class ForwardIt, std::size_t N>
+ inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, N>, std::integral_constant<bool, true>) {
+ return doit_fast(first, std::integral_constant<std::size_t, N>{});
+ }
+
+ template <class ForwardIt, std::size_t N>
+ inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, N>, std::integral_constant<bool, false>) {
+ auto constexpr next_power = next_highest_power_of_two(N);
+ auto constexpr next_start = next_power / 2 - 1;
+ auto it = first + next_start;
+ if (compare_(*it, value_)) {
+ auto constexpr next = N - next_start - 1;
+ return doitfirst(it + 1, std::integral_constant<std::size_t, next>{}, std::integral_constant<bool, next_highest_power_of_two(next) - 1 == next>{});
+ }
+ else
+ return doit_fast(first, std::integral_constant<std::size_t, next_start>{});
+ }
+
+ template <class ForwardIt>
+ inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, 1>, std::integral_constant<bool, false>) {
+ return doit_fast(first, std::integral_constant<std::size_t, 1>{});
+ }
+};
+
+template <std::size_t N, class ForwardIt, class T, class Compare>
+constexpr ForwardIt lower_bound(ForwardIt first, const T &value, Compare const &compare) {
+ return LowerBound<T, Compare>{value, compare}.doitfirst(first, std::integral_constant<std::size_t, N>{}, std::integral_constant<bool, next_highest_power_of_two(N) - 1 == N>{});
+}
+
+template <std::size_t N, class Compare, class ForwardIt, class T>
+constexpr bool binary_search(ForwardIt first, const T &value,
+ Compare const &compare) {
+ ForwardIt where = lower_bound<N>(first, value, compare);
+ return (!(where == first + N) && !(compare(value, *where)));
+}
+
+
+template<class InputIt1, class InputIt2>
+constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
+{
+ for (; first1 != last1; ++first1, ++first2) {
+ if (!(*first1 == *first2)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<class InputIt1, class InputIt2>
+constexpr bool lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
+{
+ for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) {
+ if (*first1 < *first2)
+ return true;
+ if (*first2 < *first1)
+ return false;
+ }
+ return (first1 == last1) && (first2 != last2);
+}
+
+} // namespace bits
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/bits/basic_types.h b/contrib/frozen/include/frozen/bits/basic_types.h
new file mode 100644
index 0000000..9814bac
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/basic_types.h
@@ -0,0 +1,200 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_BASIC_TYPES_H
+#define FROZEN_LETITGO_BASIC_TYPES_H
+
+#include "frozen/bits/exceptions.h"
+
+#include <utility>
+#include <iterator>
+#include <string>
+
+namespace frozen {
+
+namespace bits {
+
+// used as a fake argument for frozen::make_set and frozen::make_map in the case of N=0
+struct ignored_arg {};
+
+template <class T, std::size_t N>
+class cvector {
+ T data [N] = {}; // zero-initialization for scalar type T, default-initialized otherwise
+ std::size_t dsize = 0;
+
+public:
+ // Container typdefs
+ using value_type = T;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ // Constructors
+ constexpr cvector(void) = default;
+ constexpr cvector(size_type count, const T& value) : dsize(count) {
+ for (std::size_t i = 0; i < N; ++i)
+ data[i] = value;
+ }
+
+ // Iterators
+ constexpr iterator begin() noexcept { return data; }
+ constexpr iterator end() noexcept { return data + dsize; }
+
+ // Capacity
+ constexpr size_type size() const { return dsize; }
+
+ // Element access
+ constexpr reference operator[](std::size_t index) { return data[index]; }
+ constexpr const_reference operator[](std::size_t index) const { return data[index]; }
+
+ constexpr reference back() { return data[dsize - 1]; }
+ constexpr const_reference back() const { return data[dsize - 1]; }
+
+ // Modifiers
+ constexpr void push_back(const T & a) { data[dsize++] = a; }
+ constexpr void push_back(T && a) { data[dsize++] = std::move(a); }
+ constexpr void pop_back() { --dsize; }
+
+ constexpr void clear() { dsize = 0; }
+};
+
+template <class T, std::size_t N>
+class carray {
+ T data_ [N] = {}; // zero-initialization for scalar type T, default-initialized otherwise
+
+ template <std::size_t M, std::size_t... I>
+ constexpr carray(T const (&init)[M], std::index_sequence<I...>)
+ : data_{init[I]...} {}
+ template <class Iter, std::size_t... I>
+ constexpr carray(Iter iter, std::index_sequence<I...>)
+ : data_{((void)I, *iter++)...} {}
+
+public:
+ // Container typdefs
+ using value_type = T;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ // Constructors
+ constexpr carray(void) = default;
+ template <std::size_t M>
+ constexpr carray(T const (&init)[M])
+ : carray(init, std::make_index_sequence<N>())
+ {
+ static_assert(M >= N, "Cannot initialize a carray with an smaller array");
+ }
+ constexpr carray(std::initializer_list<T> init)
+ : carray(init.begin(), std::make_index_sequence<N>())
+ {
+ // clang & gcc doesn't recognize init.size() as a constexpr
+ // static_assert(init.size() >= N, "Cannot initialize a carray with an smaller initializer list");
+ }
+
+ // Iterators
+ constexpr iterator begin() noexcept { return data_; }
+ constexpr const_iterator begin() const noexcept { return data_; }
+ constexpr const_iterator cbegin() const noexcept { return data_; }
+ constexpr iterator end() noexcept { return data_ + N; }
+ constexpr const_iterator end() const noexcept { return data_ + N; }
+ constexpr const_iterator cend() const noexcept { return data_ + 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()); }
+
+ // Capacity
+ constexpr size_type size() const { return N; }
+ constexpr size_type max_size() const { return N; }
+
+ // Element access
+ constexpr reference operator[](std::size_t index) { return data_[index]; }
+ constexpr const_reference operator[](std::size_t index) const { return data_[index]; }
+
+ constexpr reference at(std::size_t index) {
+ if (index > N)
+ FROZEN_THROW_OR_ABORT(std::out_of_range("Index (" + std::to_string(index) + ") out of bound (" + std::to_string(N) + ')'));
+ return data_[index];
+ }
+ constexpr const_reference at(std::size_t index) const {
+ if (index > N)
+ FROZEN_THROW_OR_ABORT(std::out_of_range("Index (" + std::to_string(index) + ") out of bound (" + std::to_string(N) + ')'));
+ return data_[index];
+ }
+
+ constexpr reference front() { return data_[0]; }
+ constexpr const_reference front() const { return data_[0]; }
+
+ constexpr reference back() { return data_[N - 1]; }
+ constexpr const_reference back() const { return data_[N - 1]; }
+
+ constexpr value_type* data() noexcept { return data_; }
+ constexpr const value_type* data() const noexcept { return data_; }
+
+ // Modifiers
+ constexpr void fill(const value_type& val) {
+ for (std::size_t i = 0; i < N; ++i)
+ data_[i] = val;
+ }
+};
+template <class T>
+class carray<T, 0> {
+
+public:
+ // Container typdefs
+ using value_type = T;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ // Constructors
+ constexpr carray(void) = default;
+
+};
+
+} // namespace bits
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/bits/constexpr_assert.h b/contrib/frozen/include/frozen/bits/constexpr_assert.h
new file mode 100644
index 0000000..912210d
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/constexpr_assert.h
@@ -0,0 +1,40 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_CONSTEXPR_ASSERT_H
+#define FROZEN_LETITGO_CONSTEXPR_ASSERT_H
+
+#include <cassert>
+
+#ifdef _MSC_VER
+
+// FIXME: find a way to implement that correctly for msvc
+#define constexpr_assert(cond, msg)
+
+#else
+
+#define constexpr_assert(cond, msg)\
+ assert(cond && msg);
+#endif
+
+#endif
+
diff --git a/contrib/frozen/include/frozen/bits/defines.h b/contrib/frozen/include/frozen/bits/defines.h
new file mode 100644
index 0000000..0a1663d
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/defines.h
@@ -0,0 +1,58 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_DEFINES_H
+#define FROZEN_LETITGO_DEFINES_H
+
+#if defined(_MSVC_LANG) && !(defined(__EDG__) && defined(__clang__)) // TRANSITION, VSO#273681
+ #define FROZEN_LETITGO_IS_MSVC
+#endif
+
+// Code taken from https://stackoverflow.com/questions/43639122/which-values-can-msvc-lang-have
+#if defined(FROZEN_LETITGO_IS_MSVC)
+ #if _MSVC_LANG > 201402
+ #define FROZEN_LETITGO_HAS_CXX17 1
+ #else /* _MSVC_LANG > 201402 */
+ #define FROZEN_LETITGO_HAS_CXX17 0
+ #endif /* _MSVC_LANG > 201402 */
+#else /* _MSVC_LANG etc. */
+ #if __cplusplus > 201402
+ #define FROZEN_LETITGO_HAS_CXX17 1
+ #else /* __cplusplus > 201402 */
+ #define FROZEN_LETITGO_HAS_CXX17 0
+ #endif /* __cplusplus > 201402 */
+#endif /* _MSVC_LANG etc. */
+// End if taken code
+
+#if FROZEN_LETITGO_HAS_CXX17 == 1 && defined(FROZEN_LETITGO_IS_MSVC)
+ #define FROZEN_LETITGO_HAS_STRING_VIEW // We assume Visual Studio always has string_view in C++17
+#else
+ #if FROZEN_LETITGO_HAS_CXX17 == 1 && __has_include(<string_view>)
+ #define FROZEN_LETITGO_HAS_STRING_VIEW
+ #endif
+#endif
+
+#ifdef __cpp_char8_t
+ #define FROZEN_LETITGO_HAS_CHAR8T
+#endif
+
+#endif // FROZEN_LETITGO_DEFINES_H
diff --git a/contrib/frozen/include/frozen/bits/elsa.h b/contrib/frozen/include/frozen/bits/elsa.h
new file mode 100644
index 0000000..d7388be
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/elsa.h
@@ -0,0 +1,50 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_ELSA_H
+#define FROZEN_LETITGO_ELSA_H
+
+#include <type_traits>
+
+namespace frozen {
+
+template <class T> struct elsa {
+ static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
+ "only supports integral types, specialize for other types");
+
+ constexpr std::size_t operator()(T const &value, std::size_t seed) const {
+ std::size_t key = seed ^ static_cast<std::size_t>(value);
+ key = (~key) + (key << 21); // key = (key << 21) - key - 1;
+ key = key ^ (key >> 24);
+ key = (key + (key << 3)) + (key << 8); // key * 265
+ key = key ^ (key >> 14);
+ key = (key + (key << 2)) + (key << 4); // key * 21
+ key = key ^ (key >> 28);
+ key = key + (key << 31);
+ return key;
+ }
+};
+
+template <class T> using anna = elsa<T>;
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/bits/exceptions.h b/contrib/frozen/include/frozen/bits/exceptions.h
new file mode 100644
index 0000000..b43e3e6
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/exceptions.h
@@ -0,0 +1,39 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_EXCEPTIONS_H
+#define FROZEN_LETITGO_EXCEPTIONS_H
+
+#if defined(FROZEN_NO_EXCEPTIONS) || (defined(_MSC_VER) && !defined(_CPPUNWIND)) || (!defined(_MSC_VER) && !defined(__cpp_exceptions))
+
+#include <cstdlib>
+#define FROZEN_THROW_OR_ABORT(_) std::abort()
+
+#else
+
+#include <stdexcept>
+#define FROZEN_THROW_OR_ABORT(err) throw err
+
+
+#endif
+
+#endif
diff --git a/contrib/frozen/include/frozen/bits/pmh.h b/contrib/frozen/include/frozen/bits/pmh.h
new file mode 100644
index 0000000..76e7ebe
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/pmh.h
@@ -0,0 +1,240 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// inspired from http://stevehanov.ca/blog/index.php?id=119
+#ifndef FROZEN_LETITGO_PMH_H
+#define FROZEN_LETITGO_PMH_H
+
+#include "frozen/bits/algorithms.h"
+#include "frozen/bits/basic_types.h"
+
+#include <array>
+#include <limits>
+
+namespace frozen {
+
+namespace bits {
+
+// Function object for sorting buckets in decreasing order of size
+struct bucket_size_compare {
+ template <typename B>
+ bool constexpr operator()(B const &b0,
+ B const &b1) const {
+ return b0.size() > b1.size();
+ }
+};
+
+// Step One in pmh routine is to take all items and hash them into buckets,
+// with some collisions. Then process those buckets further to build a perfect
+// hash function.
+// pmh_buckets represents the initial placement into buckets.
+
+template <size_t M>
+struct pmh_buckets {
+ // Step 0: Bucket max is 2 * sqrt M
+ // TODO: Come up with justification for this, should it not be O(log M)?
+ static constexpr auto bucket_max = 2 * (1u << (log(M) / 2));
+
+ using bucket_t = cvector<std::size_t, bucket_max>;
+ carray<bucket_t, M> buckets;
+ uint64_t seed;
+
+ // Represents a reference to a bucket. This is used because the buckets
+ // have to be sorted, but buckets are big, making it slower than sorting refs
+ struct bucket_ref {
+ unsigned hash;
+ const bucket_t * ptr;
+
+ // Forward some interface of bucket
+ using value_type = typename bucket_t::value_type;
+ using const_iterator = typename bucket_t::const_iterator;
+
+ constexpr auto size() const { return ptr->size(); }
+ constexpr const auto & operator[](std::size_t idx) const { return (*ptr)[idx]; }
+ constexpr auto begin() const { return ptr->begin(); }
+ constexpr auto end() const { return ptr->end(); }
+ };
+
+ // Make a bucket_ref for each bucket
+ template <std::size_t... Is>
+ carray<bucket_ref, M> constexpr make_bucket_refs(std::index_sequence<Is...>) const {
+ return {{ bucket_ref{Is, &buckets[Is]}... }};
+ }
+
+ // Makes a bucket_ref for each bucket and sorts them by size
+ carray<bucket_ref, M> constexpr get_sorted_buckets() const {
+ carray<bucket_ref, M> result{this->make_bucket_refs(std::make_index_sequence<M>())};
+ bits::quicksort(result.begin(), result.end() - 1, bucket_size_compare{});
+ return result;
+ }
+};
+
+template <size_t M, class Item, size_t N, class Hash, class Key, class PRG>
+pmh_buckets<M> constexpr make_pmh_buckets(const carray<Item, N> & items,
+ Hash const & hash,
+ Key const & key,
+ PRG & prg) {
+ using result_t = pmh_buckets<M>;
+ result_t result{};
+ bool rejected = false;
+ // Continue until all items are placed without exceeding bucket_max
+ while (1) {
+ for (auto & b : result.buckets) {
+ b.clear();
+ }
+ result.seed = prg();
+ rejected = false;
+ for (std::size_t i = 0; i < N; ++i) {
+ auto & bucket = result.buckets[hash(key(items[i]), static_cast<size_t>(result.seed)) % M];
+ if (bucket.size() >= result_t::bucket_max) {
+ rejected = true;
+ break;
+ }
+ bucket.push_back(i);
+ }
+ if (!rejected) { return result; }
+ }
+}
+
+// Check if an item appears in a cvector
+template<class T, size_t N>
+constexpr bool all_different_from(cvector<T, N> & data, T & a) {
+ for (std::size_t i = 0; i < data.size(); ++i)
+ if (data[i] == a)
+ return false;
+
+ return true;
+}
+
+// Represents either an index to a data item array, or a seed to be used with
+// a hasher. Seed must have high bit of 1, value has high bit of zero.
+struct seed_or_index {
+ using value_type = uint64_t;
+
+private:
+ static constexpr value_type MINUS_ONE = std::numeric_limits<value_type>::max();
+ static constexpr value_type HIGH_BIT = ~(MINUS_ONE >> 1);
+
+ value_type value_ = 0;
+
+public:
+ constexpr value_type value() const { return value_; }
+ constexpr bool is_seed() const { return value_ & HIGH_BIT; }
+
+ constexpr seed_or_index(bool is_seed, value_type value)
+ : value_(is_seed ? (value | HIGH_BIT) : (value & ~HIGH_BIT)) {}
+
+ constexpr seed_or_index() = default;
+ constexpr seed_or_index(const seed_or_index &) = default;
+ constexpr seed_or_index & operator =(const seed_or_index &) = default;
+};
+
+// Represents the perfect hash function created by pmh algorithm
+template <std::size_t M, class Hasher>
+struct pmh_tables {
+ uint64_t first_seed_;
+ carray<seed_or_index, M> first_table_;
+ carray<std::size_t, M> second_table_;
+ Hasher hash_;
+
+ // Looks up a given key, to find its expected index in carray<Item, N>
+ // Always returns a valid index, must use KeyEqual test after to confirm.
+ template <typename KeyType>
+ constexpr std::size_t lookup(const KeyType & key) const {
+ auto const d = first_table_[hash_(key, static_cast<size_t>(first_seed_)) % M];
+ if (!d.is_seed()) { return static_cast<std::size_t>(d.value()); } // this is narrowing uint64 -> size_t but should be fine
+ else { return second_table_[hash_(key, static_cast<std::size_t>(d.value())) % M]; }
+ }
+};
+
+// Make pmh tables for given items, hash function, prg, etc.
+template <std::size_t M, class Item, std::size_t N, class Hash, class Key, class PRG>
+pmh_tables<M, Hash> constexpr make_pmh_tables(const carray<Item, N> &
+ items,
+ Hash const &hash,
+ Key const &key,
+ PRG prg) {
+ // Step 1: Place all of the keys into buckets
+ auto step_one = make_pmh_buckets<M>(items, hash, key, prg);
+
+ // Step 2: Sort the buckets to process the ones with the most items first.
+ auto buckets = step_one.get_sorted_buckets();
+
+ // G becomes the first hash table in the resulting pmh function
+ carray<seed_or_index, M> G; // Default constructed to "index 0"
+
+ // H becomes the second hash table in the resulting pmh function
+ constexpr std::size_t UNUSED = std::numeric_limits<std::size_t>::max();
+ carray<std::size_t, M> H;
+ H.fill(UNUSED);
+
+ // Step 3: Map the items in buckets into hash tables.
+ for (const auto & bucket : buckets) {
+ auto const bsize = bucket.size();
+
+ if (bsize == 1) {
+ // Store index to the (single) item in G
+ // assert(bucket.hash == hash(key(items[bucket[0]]), step_one.seed) % M);
+ G[bucket.hash] = {false, static_cast<uint64_t>(bucket[0])};
+ } else if (bsize > 1) {
+
+ // Repeatedly try different H of d until we find a hash function
+ // that places all items in the bucket into free slots
+ seed_or_index d{true, prg()};
+ cvector<std::size_t, decltype(step_one)::bucket_max> bucket_slots;
+
+ while (bucket_slots.size() < bsize) {
+ auto slot = hash(key(items[bucket[bucket_slots.size()]]), static_cast<size_t>(d.value())) % M;
+
+ if (H[slot] != UNUSED || !all_different_from(bucket_slots, slot)) {
+ bucket_slots.clear();
+ d = {true, prg()};
+ continue;
+ }
+
+ bucket_slots.push_back(slot);
+ }
+
+ // Put successful seed in G, and put indices to items in their slots
+ // assert(bucket.hash == hash(key(items[bucket[0]]), step_one.seed) % M);
+ G[bucket.hash] = d;
+ for (std::size_t i = 0; i < bsize; ++i)
+ H[bucket_slots[i]] = bucket[i];
+ }
+ }
+
+ // Any unused entries in the H table have to get changed to zero.
+ // This is because hashing should not fail or return an out-of-bounds entry.
+ // A lookup fails after we apply user-supplied KeyEqual to the query and the
+ // key found by hashing. Sending such queries to zero cannot hurt.
+ for (std::size_t i = 0; i < M; ++i)
+ if (H[i] == UNUSED)
+ H[i] = 0;
+
+ return {step_one.seed, G, H, hash};
+}
+
+} // namespace bits
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/bits/version.h b/contrib/frozen/include/frozen/bits/version.h
new file mode 100644
index 0000000..51804d2
--- /dev/null
+++ b/contrib/frozen/include/frozen/bits/version.h
@@ -0,0 +1,30 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_VERSION_H
+#define FROZEN_LETITGO_VERSION_H
+
+#define FROZEN_MAJOR_VERSION 1
+#define FROZEN_MINOR_VERSION 0
+#define FROZEN_PATCH_VERSION 1
+
+#endif
diff --git a/contrib/frozen/include/frozen/map.h b/contrib/frozen/include/frozen/map.h
new file mode 100644
index 0000000..107179c
--- /dev/null
+++ b/contrib/frozen/include/frozen/map.h
@@ -0,0 +1,323 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_MAP_H
+#define FROZEN_LETITGO_MAP_H
+
+#include "frozen/bits/algorithms.h"
+#include "frozen/bits/basic_types.h"
+#include "frozen/bits/constexpr_assert.h"
+#include "frozen/bits/exceptions.h"
+#include "frozen/bits/version.h"
+
+#include <utility>
+
+namespace frozen {
+
+namespace impl {
+
+template <class Comparator> class CompareKey {
+
+ Comparator const comparator_;
+
+public:
+ constexpr CompareKey(Comparator const &comparator)
+ : comparator_(comparator) {}
+
+ template <class Key, class Value>
+ constexpr int operator()(std::pair<Key, Value> const &self,
+ std::pair<Key, Value> const &other) const {
+ return comparator_(std::get<0>(self), std::get<0>(other));
+ }
+
+ template <class Key, class Value>
+ constexpr int operator()(Key const &self_key,
+ std::pair<Key, Value> const &other) const {
+ return comparator_(self_key, std::get<0>(other));
+ }
+
+ template <class Key, class Value>
+ constexpr int operator()(std::pair<Key, Value> const &self,
+ Key const &other_key) const {
+ return comparator_(std::get<0>(self), other_key);
+ }
+
+ template <class Key>
+ constexpr int operator()(Key const &self_key, Key const &other_key) const {
+ return comparator_(self_key, other_key);
+ }
+};
+
+} // namespace impl
+
+template <class Key, class Value, std::size_t N, class Compare = std::less<Key>>
+class map {
+ using container_type = bits::carray<std::pair<Key, Value>, N>;
+ impl::CompareKey<Compare> less_than_;
+ container_type items_;
+
+public:
+ using key_type = Key;
+ using mapped_type = Value;
+ using value_type = typename container_type::value_type;
+ using size_type = typename container_type::size_type;
+ using difference_type = typename container_type::difference_type;
+ using key_compare = decltype(less_than_);
+ using reference = typename container_type::reference;
+ using const_reference = typename container_type::const_reference;
+ using pointer = typename container_type::pointer;
+ using const_pointer = typename container_type::const_pointer;
+ using iterator = typename container_type::iterator;
+ using const_iterator = typename container_type::const_iterator;
+ using reverse_iterator = typename container_type::reverse_iterator;
+ using const_reverse_iterator =
+ typename container_type::const_reverse_iterator;
+
+public:
+ /* constructors */
+ constexpr map(container_type items, Compare const &compare)
+ : less_than_{compare}
+ , items_{bits::quicksort(items, less_than_)} {}
+
+ explicit constexpr map(container_type items)
+ : map{items, Compare{}} {}
+
+ constexpr map(std::initializer_list<value_type> items, Compare const &compare)
+ : map{container_type {items}, compare} {
+ constexpr_assert(items.size() == N, "Inconsistent initializer_list size and type size argument");
+ }
+
+ constexpr map(std::initializer_list<value_type> items)
+ : map{items, Compare{}} {}
+
+ /* element access */
+ constexpr Value const& at(Key const &key) const {
+ return at_impl(*this, key);
+ }
+ constexpr Value& at(Key const &key) {
+ return at_impl(*this, key);
+ }
+
+ /* iterators */
+ constexpr iterator begin() { return items_.begin(); }
+ constexpr const_iterator begin() const { return items_.begin(); }
+ constexpr const_iterator cbegin() const { return items_.cbegin(); }
+ constexpr iterator end() { return items_.end(); }
+ constexpr const_iterator end() const { return items_.end(); }
+ constexpr const_iterator cend() const { return items_.cend(); }
+
+ constexpr reverse_iterator rbegin() { return items_.rbegin(); }
+ constexpr const_reverse_iterator rbegin() const { return items_.rbegin(); }
+ constexpr const_reverse_iterator crbegin() const { return items_.crbegin(); }
+ constexpr reverse_iterator rend() { return items_.rend(); }
+ constexpr const_reverse_iterator rend() const { return items_.rend(); }
+ constexpr const_reverse_iterator crend() const { return items_.crend(); }
+
+ /* capacity */
+ constexpr bool empty() const { return !N; }
+ constexpr size_type size() const { return N; }
+ constexpr size_type max_size() const { return N; }
+
+ /* lookup */
+
+ constexpr std::size_t count(Key const &key) const {
+ return bits::binary_search<N>(items_.begin(), key, less_than_);
+ }
+
+ constexpr const_iterator find(Key const &key) const {
+ return find_impl(*this, key);
+ }
+ constexpr iterator find(Key const &key) {
+ return find_impl(*this, key);
+ }
+
+ constexpr std::pair<const_iterator, const_iterator>
+ equal_range(Key const &key) const {
+ return equal_range_impl(*this, key);
+ }
+ constexpr std::pair<iterator, iterator> equal_range(Key const &key) {
+ return equal_range_impl(*this, key);
+ }
+
+ constexpr const_iterator lower_bound(Key const &key) const {
+ return lower_bound_impl(*this, key);
+ }
+ constexpr iterator lower_bound(Key const &key) {
+ return lower_bound_impl(*this, key);
+ }
+
+ constexpr const_iterator upper_bound(Key const &key) const {
+ return upper_bound_impl(*this, key);
+ }
+ constexpr iterator upper_bound(Key const &key) {
+ return upper_bound_impl(*this, key);
+ }
+
+ /* observers */
+ constexpr key_compare key_comp() const { return less_than_; }
+ constexpr key_compare value_comp() const { return less_than_; }
+
+ private:
+ template <class This>
+ static inline constexpr auto& at_impl(This&& self, Key const &key) {
+ auto where = self.lower_bound(key);
+ if (where != self.end())
+ return where->second;
+ else
+ FROZEN_THROW_OR_ABORT(std::out_of_range("unknown key"));
+ }
+
+ template <class This>
+ static inline constexpr auto find_impl(This&& self, Key const &key) {
+ auto where = self.lower_bound(key);
+ if ((where != self.end()) && !self.less_than_(key, *where))
+ return where;
+ else
+ return self.end();
+ }
+
+ template <class This>
+ static inline constexpr auto equal_range_impl(This&& self, Key const &key) {
+ auto lower = self.lower_bound(key);
+ using lower_t = decltype(lower);
+ if (lower == self.end())
+ return std::pair<lower_t, lower_t>{lower, lower};
+ else
+ return std::pair<lower_t, lower_t>{lower, lower + 1};
+ }
+
+ template <class This>
+ static inline constexpr auto lower_bound_impl(This&& self, Key const &key) -> decltype(self.end()) {
+ auto where = bits::lower_bound<N>(self.items_.begin(), key, self.less_than_);
+ if ((where != self.end()) && !self.less_than_(key, *where))
+ return where;
+ else
+ return self.end();
+ }
+
+ template <class This>
+ static inline constexpr auto upper_bound_impl(This&& self, Key const &key) -> decltype(self.end()) {
+ auto where = bits::lower_bound<N>(self.items_.begin(), key, self.less_than_);
+ if ((where != self.end()) && !self.less_than_(key, *where))
+ return where + 1;
+ else
+ return self.end();
+ }
+};
+
+template <class Key, class Value, class Compare>
+class map<Key, Value, 0, Compare> {
+ using container_type = bits::carray<std::pair<Key, Value>, 0>;
+ impl::CompareKey<Compare> less_than_;
+
+public:
+ using key_type = Key;
+ using mapped_type = Value;
+ using value_type = typename container_type::value_type;
+ using size_type = typename container_type::size_type;
+ using difference_type = typename container_type::difference_type;
+ using key_compare = decltype(less_than_);
+ using reference = typename container_type::reference;
+ using const_reference = typename container_type::const_reference;
+ using pointer = typename container_type::pointer;
+ using const_pointer = typename container_type::const_pointer;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = pointer;
+ using const_reverse_iterator = const_pointer;
+
+public:
+ /* constructors */
+ constexpr map(const map &other) = default;
+ constexpr map(std::initializer_list<value_type>, Compare const &compare)
+ : less_than_{compare} {}
+ constexpr map(std::initializer_list<value_type> items)
+ : map{items, Compare{}} {}
+
+ /* element access */
+ constexpr mapped_type at(Key const &) const {
+ FROZEN_THROW_OR_ABORT(std::out_of_range("invalid key"));
+ }
+ constexpr mapped_type at(Key const &) {
+ FROZEN_THROW_OR_ABORT(std::out_of_range("invalid key"));
+ }
+
+ /* iterators */
+ constexpr iterator begin() { return nullptr; }
+ constexpr const_iterator begin() const { return nullptr; }
+ constexpr const_iterator cbegin() const { return nullptr; }
+ constexpr iterator end() { return nullptr; }
+ constexpr const_iterator end() const { return nullptr; }
+ constexpr const_iterator cend() const { return nullptr; }
+
+ constexpr reverse_iterator rbegin() { return nullptr; }
+ constexpr const_reverse_iterator rbegin() const { return nullptr; }
+ constexpr const_reverse_iterator crbegin() const { return nullptr; }
+ constexpr reverse_iterator rend() { return nullptr; }
+ constexpr const_reverse_iterator rend() const { return nullptr; }
+ constexpr const_reverse_iterator crend() const { return nullptr; }
+
+ /* capacity */
+ constexpr bool empty() const { return true; }
+ constexpr size_type size() const { return 0; }
+ constexpr size_type max_size() const { return 0; }
+
+ /* lookup */
+
+ constexpr std::size_t count(Key const &) const { return 0; }
+
+ constexpr const_iterator find(Key const &) const { return end(); }
+ constexpr iterator find(Key const &) { return end(); }
+
+ constexpr std::pair<const_iterator, const_iterator>
+ equal_range(Key const &) const {
+ return {end(), end()};
+ }
+ constexpr std::pair<iterator, iterator>
+ equal_range(Key const &) {
+ return {end(), end()};
+ }
+
+ constexpr const_iterator lower_bound(Key const &) const { return end(); }
+ constexpr iterator lower_bound(Key const &) { return end(); }
+
+ constexpr const_iterator upper_bound(Key const &) const { return end(); }
+ constexpr iterator upper_bound(Key const &) { return end(); }
+
+ /* observers */
+ constexpr key_compare key_comp() const { return less_than_; }
+ constexpr key_compare value_comp() const { return less_than_; }
+};
+
+template <typename T, typename U>
+constexpr auto make_map(bits::ignored_arg = {}/* for consistency with the initializer below for N = 0*/) {
+ return map<T, U, 0>{};
+}
+
+template <typename T, typename U, std::size_t N>
+constexpr auto make_map(std::pair<T, U> const (&items)[N]) {
+ return map<T, U, N>{items};
+}
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/random.h b/contrib/frozen/include/frozen/random.h
new file mode 100644
index 0000000..ea494dc
--- /dev/null
+++ b/contrib/frozen/include/frozen/random.h
@@ -0,0 +1,90 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_RANDOM_H
+#define FROZEN_LETITGO_RANDOM_H
+
+#include "frozen/bits/algorithms.h"
+#include "frozen/bits/version.h"
+
+#include <cstdint>
+#include <type_traits>
+
+namespace frozen {
+template <class UIntType, UIntType a, UIntType c, UIntType m>
+class linear_congruential_engine {
+
+ static_assert(std::is_unsigned<UIntType>::value,
+ "UIntType must be an unsigned integral type");
+
+public:
+ using result_type = UIntType;
+ static constexpr result_type multiplier = a;
+ static constexpr result_type increment = c;
+ static constexpr result_type modulus = m;
+ static constexpr result_type default_seed = 1u;
+
+ linear_congruential_engine() = default;
+ constexpr linear_congruential_engine(result_type s) { seed(s); }
+
+ void seed(result_type s = default_seed) { state_ = s; }
+ constexpr result_type operator()() {
+ using uint_least_t = bits::select_uint_least_t<bits::log(a) + bits::log(m) + 4>;
+ uint_least_t tmp = static_cast<uint_least_t>(multiplier) * state_ + increment;
+
+ // the static cast below may end up doing a truncation
+ if(modulus != 0)
+ state_ = static_cast<result_type>(tmp % modulus);
+ else
+ state_ = static_cast<result_type>(tmp);
+ return state_;
+ }
+ constexpr void discard(unsigned long long n) {
+ while (n--)
+ operator()();
+ }
+ static constexpr result_type min() { return increment == 0u ? 1u : 0u; };
+ static constexpr result_type max() { return modulus - 1u; };
+ friend constexpr bool operator==(linear_congruential_engine const &self,
+ linear_congruential_engine const &other) {
+ return self.state_ == other.state_;
+ }
+ friend constexpr bool operator!=(linear_congruential_engine const &self,
+ linear_congruential_engine const &other) {
+ return !(self == other);
+ }
+
+private:
+ result_type state_ = default_seed;
+};
+
+using minstd_rand0 =
+ linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647>;
+using minstd_rand =
+ linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647>;
+
+// This generator is used by default in unordered frozen containers
+using default_prg_t = minstd_rand;
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/set.h b/contrib/frozen/include/frozen/set.h
new file mode 100644
index 0000000..d86d814
--- /dev/null
+++ b/contrib/frozen/include/frozen/set.h
@@ -0,0 +1,220 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_SET_H
+#define FROZEN_SET_H
+
+#include "frozen/bits/algorithms.h"
+#include "frozen/bits/basic_types.h"
+#include "frozen/bits/constexpr_assert.h"
+#include "frozen/bits/version.h"
+
+#include <utility>
+
+namespace frozen {
+
+template <class Key, std::size_t N, class Compare = std::less<Key>> class set {
+ using container_type = bits::carray<Key, N>;
+ Compare less_than_;
+ container_type keys_;
+
+public:
+ /* container typedefs*/
+ using key_type = Key;
+ using value_type = Key;
+ using size_type = typename container_type::size_type;
+ using difference_type = typename container_type::size_type;
+ using key_compare = Compare;
+ using value_compare = Compare;
+ using reference = typename container_type::const_reference;
+ using const_reference = reference;
+ using pointer = typename container_type::const_pointer;
+ using const_pointer = pointer;
+ using iterator = typename container_type::const_iterator;
+ using reverse_iterator = typename container_type::const_reverse_iterator;
+ using const_iterator = iterator;
+ using const_reverse_iterator = reverse_iterator;
+
+public:
+ /* constructors */
+ constexpr set(const set &other) = default;
+
+ constexpr set(container_type keys, Compare const & comp)
+ : less_than_{comp}
+ , keys_(bits::quicksort(keys, less_than_)) {
+ }
+
+ explicit constexpr set(container_type keys)
+ : set{keys, Compare{}} {}
+
+ constexpr set(std::initializer_list<Key> keys, Compare const & comp)
+ : set{container_type{keys}, comp} {
+ constexpr_assert(keys.size() == N, "Inconsistent initializer_list size and type size argument");
+ }
+
+ constexpr set(std::initializer_list<Key> keys)
+ : set{keys, Compare{}} {}
+
+ /* capacity */
+ constexpr bool empty() const { return !N; }
+ constexpr size_type size() const { return N; }
+ constexpr size_type max_size() const { return N; }
+
+ /* lookup */
+ constexpr std::size_t count(Key const &key) const {
+ return bits::binary_search<N>(keys_.begin(), key, less_than_);
+ }
+
+ constexpr const_iterator find(Key const &key) const {
+ const_iterator where = lower_bound(key);
+ if ((where != end()) && !less_than_(key, *where))
+ return where;
+ else
+ return end();
+ }
+
+ constexpr std::pair<const_iterator, const_iterator> equal_range(Key const &key) const {
+ auto const lower = lower_bound(key);
+ if (lower == end())
+ return {lower, lower};
+ else
+ return {lower, lower + 1};
+ }
+
+ constexpr const_iterator lower_bound(Key const &key) const {
+ auto const where = bits::lower_bound<N>(keys_.begin(), key, less_than_);
+ if ((where != end()) && !less_than_(key, *where))
+ return where;
+ else
+ return end();
+ }
+
+ constexpr const_iterator upper_bound(Key const &key) const {
+ auto const where = bits::lower_bound<N>(keys_.begin(), key, less_than_);
+ if ((where != end()) && !less_than_(key, *where))
+ return where + 1;
+ else
+ return end();
+ }
+
+ /* observers */
+ constexpr key_compare key_comp() const { return less_than_; }
+ constexpr key_compare value_comp() const { return less_than_; }
+
+ /* iterators */
+ constexpr const_iterator begin() const { return keys_.begin(); }
+ constexpr const_iterator cbegin() const { return keys_.cbegin(); }
+ constexpr const_iterator end() const { return keys_.end(); }
+ constexpr const_iterator cend() const { return keys_.cend(); }
+
+ constexpr const_reverse_iterator rbegin() const { return keys_.rbegin(); }
+ constexpr const_reverse_iterator crbegin() const { return keys_.crbegin(); }
+ constexpr const_reverse_iterator rend() const { return keys_.rend(); }
+ constexpr const_reverse_iterator crend() const { return keys_.crend(); }
+
+ /* comparison */
+ constexpr bool operator==(set const& rhs) const { return bits::equal(begin(), end(), rhs.begin()); }
+ constexpr bool operator!=(set const& rhs) const { return !(*this == rhs); }
+ constexpr bool operator<(set const& rhs) const { return bits::lexicographical_compare(begin(), end(), rhs.begin(), rhs.end()); }
+ constexpr bool operator<=(set const& rhs) const { return (*this < rhs) || (*this == rhs); }
+ constexpr bool operator>(set const& rhs) const { return bits::lexicographical_compare(rhs.begin(), rhs.end(), begin(), end()); }
+ constexpr bool operator>=(set const& rhs) const { return (*this > rhs) || (*this == rhs); }
+};
+
+template <class Key, class Compare> class set<Key, 0, Compare> {
+ using container_type = bits::carray<Key, 0>; // just for the type definitions
+ Compare less_than_;
+
+public:
+ /* container typedefs*/
+ using key_type = Key;
+ using value_type = Key;
+ using size_type = typename container_type::size_type;
+ using difference_type = typename container_type::size_type;
+ using key_compare = Compare;
+ using value_compare = Compare;
+ using reference = typename container_type::const_reference;
+ using const_reference = reference;
+ using pointer = typename container_type::const_pointer;
+ using const_pointer = pointer;
+ using iterator = pointer;
+ using reverse_iterator = pointer;
+ using const_iterator = const_pointer;
+ using const_reverse_iterator = const_pointer;
+
+public:
+ /* constructors */
+ constexpr set(const set &other) = default;
+ constexpr set(bits::carray<Key, 0>, Compare const &) {}
+ explicit constexpr set(bits::carray<Key, 0>) {}
+
+ constexpr set(std::initializer_list<Key>, Compare const &comp)
+ : less_than_{comp} {}
+ constexpr set(std::initializer_list<Key> keys) : set{keys, Compare{}} {}
+
+ /* capacity */
+ constexpr bool empty() const { return true; }
+ constexpr size_type size() const { return 0; }
+ constexpr size_type max_size() const { return 0; }
+
+ /* lookup */
+ constexpr std::size_t count(Key const &) const { return 0; }
+
+ constexpr const_iterator find(Key const &) const { return end(); }
+
+ constexpr std::pair<const_iterator, const_iterator>
+ equal_range(Key const &) const { return {end(), end()}; }
+
+ constexpr const_iterator lower_bound(Key const &) const { return end(); }
+
+ constexpr const_iterator upper_bound(Key const &) const { return end(); }
+
+ /* observers */
+ constexpr key_compare key_comp() const { return less_than_; }
+ constexpr key_compare value_comp() const { return less_than_; }
+
+ /* iterators */
+ constexpr const_iterator begin() const { return nullptr; }
+ constexpr const_iterator cbegin() const { return nullptr; }
+ constexpr const_iterator end() const { return nullptr; }
+ constexpr const_iterator cend() const { return nullptr; }
+
+ constexpr const_reverse_iterator rbegin() const { return nullptr; }
+ constexpr const_reverse_iterator crbegin() const { return nullptr; }
+ constexpr const_reverse_iterator rend() const { return nullptr; }
+ constexpr const_reverse_iterator crend() const { return nullptr; }
+};
+
+template <typename T>
+constexpr auto make_set(bits::ignored_arg = {}/* for consistency with the initializer below for N = 0*/) {
+ return set<T, 0>{};
+}
+
+template <typename T, std::size_t N>
+constexpr auto make_set(const T (&args)[N]) {
+ return set<T, N>(args);
+}
+
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/string.h b/contrib/frozen/include/frozen/string.h
new file mode 100644
index 0000000..4505bbf
--- /dev/null
+++ b/contrib/frozen/include/frozen/string.h
@@ -0,0 +1,152 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_STRING_H
+#define FROZEN_LETITGO_STRING_H
+
+#include "frozen/bits/elsa.h"
+#include "frozen/bits/version.h"
+#include "frozen/bits/defines.h"
+
+#include <functional>
+
+#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
+#include <string_view>
+#endif
+
+namespace frozen {
+
+template <typename _CharT>
+class basic_string {
+ using chr_t = _CharT;
+
+ chr_t const *data_;
+ std::size_t size_;
+
+public:
+ template <std::size_t N>
+ constexpr basic_string(chr_t const (&data)[N])
+ : data_(data), size_(N - 1) {}
+ constexpr basic_string(chr_t const *data, std::size_t size)
+ : data_(data), size_(size) {}
+
+#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
+ constexpr basic_string(std::basic_string_view<chr_t> data)
+ : data_(data.data()), size_(data.size()) {}
+#endif
+
+ constexpr basic_string(const basic_string &) noexcept = default;
+ constexpr basic_string &operator=(const basic_string &) noexcept = default;
+
+ constexpr std::size_t size() const { return size_; }
+
+ constexpr chr_t operator[](std::size_t i) const { return data_[i]; }
+
+ constexpr bool operator==(basic_string other) const {
+ if (size_ != other.size_)
+ return false;
+ for (std::size_t i = 0; i < size_; ++i)
+ if (data_[i] != other.data_[i])
+ return false;
+ return true;
+ }
+
+ constexpr bool operator<(const basic_string &other) const {
+ unsigned i = 0;
+ while (i < size() && i < other.size()) {
+ if ((*this)[i] < other[i]) {
+ return true;
+ }
+ if ((*this)[i] > other[i]) {
+ return false;
+ }
+ ++i;
+ }
+ return size() < other.size();
+ }
+
+ constexpr const chr_t *data() const { return data_; }
+};
+
+template <typename _CharT> struct elsa<basic_string<_CharT>> {
+ constexpr std::size_t operator()(basic_string<_CharT> value) const {
+ std::size_t d = 5381;
+ for (std::size_t i = 0; i < value.size(); ++i)
+ d = d * 33 + value[i];
+ return d;
+ }
+ // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+ // With the lowest bits removed, based on experimental setup.
+ constexpr std::size_t operator()(basic_string<_CharT> value, std::size_t seed) const {
+ std::size_t d = (0x811c9dc5 ^ seed) * 0x01000193;
+ for (std::size_t i = 0; i < value.size(); ++i)
+ d = (d ^ value[i]) * 0x01000193;
+ return d >> 8 ;
+ }
+};
+
+using string = basic_string<char>;
+using wstring = basic_string<wchar_t>;
+using u16string = basic_string<char16_t>;
+using u32string = basic_string<char32_t>;
+
+#ifdef FROZEN_LETITGO_HAS_CHAR8T
+using u8string = basic_string<char8_t>;
+#endif
+
+namespace string_literals {
+
+constexpr string operator"" _s(const char *data, std::size_t size) {
+ return {data, size};
+}
+
+constexpr wstring operator"" _s(const wchar_t *data, std::size_t size) {
+ return {data, size};
+}
+
+constexpr u16string operator"" _s(const char16_t *data, std::size_t size) {
+ return {data, size};
+}
+
+constexpr u32string operator"" _s(const char32_t *data, std::size_t size) {
+ return {data, size};
+}
+
+#ifdef FROZEN_LETITGO_HAS_CHAR8T
+constexpr u8string operator"" _s(const char8_t *data, std::size_t size) {
+ return {data, size};
+}
+#endif
+
+} // namespace string_literals
+
+} // namespace frozen
+
+namespace std {
+template <typename _CharT> struct hash<frozen::basic_string<_CharT>> {
+ size_t operator()(frozen::basic_string<_CharT> s) const {
+ return frozen::elsa<frozen::basic_string<_CharT>>{}(s);
+ }
+};
+} // namespace std
+
+#endif
diff --git a/contrib/frozen/include/frozen/unordered_map.h b/contrib/frozen/include/frozen/unordered_map.h
new file mode 100644
index 0000000..5e1e399
--- /dev/null
+++ b/contrib/frozen/include/frozen/unordered_map.h
@@ -0,0 +1,197 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_UNORDERED_MAP_H
+#define FROZEN_LETITGO_UNORDERED_MAP_H
+
+#include "frozen/bits/basic_types.h"
+#include "frozen/bits/constexpr_assert.h"
+#include "frozen/bits/elsa.h"
+#include "frozen/bits/exceptions.h"
+#include "frozen/bits/pmh.h"
+#include "frozen/bits/version.h"
+#include "frozen/random.h"
+
+#include <tuple>
+#include <functional>
+
+namespace frozen {
+
+namespace bits {
+
+struct GetKey {
+ template <class KV> constexpr auto const &operator()(KV const &kv) const {
+ return kv.first;
+ }
+};
+
+} // namespace bits
+
+template <class Key, class Value, std::size_t N, typename Hash = anna<Key>,
+ class KeyEqual = std::equal_to<Key>>
+class unordered_map {
+ static constexpr std::size_t storage_size =
+ bits::next_highest_power_of_two(N) * (N < 32 ? 2 : 1); // size adjustment to prevent high collision rate for small sets
+ using container_type = bits::carray<std::pair<Key, Value>, N>;
+ using tables_type = bits::pmh_tables<storage_size, Hash>;
+
+ KeyEqual const equal_;
+ container_type items_;
+ tables_type tables_;
+
+public:
+ /* typedefs */
+ using Self = unordered_map<Key, Value, N, Hash, KeyEqual>;
+ using key_type = Key;
+ using mapped_type = Value;
+ using value_type = typename container_type::value_type;
+ using size_type = typename container_type::size_type;
+ using difference_type = typename container_type::difference_type;
+ using hasher = Hash;
+ using key_equal = KeyEqual;
+ using reference = typename container_type::reference;
+ using const_reference = typename container_type::const_reference;
+ using pointer = typename container_type::pointer;
+ using const_pointer = typename container_type::const_pointer;
+ using iterator = typename container_type::iterator;
+ using const_iterator = typename container_type::const_iterator;
+
+public:
+ /* constructors */
+ unordered_map(unordered_map const &) = default;
+ constexpr unordered_map(container_type items,
+ Hash const &hash, KeyEqual const &equal)
+ : equal_{equal}
+ , items_{items}
+ , tables_{
+ bits::make_pmh_tables<storage_size>(
+ items_, hash, bits::GetKey{}, default_prg_t{})} {}
+ explicit constexpr unordered_map(container_type items)
+ : unordered_map{items, Hash{}, KeyEqual{}} {}
+
+ constexpr unordered_map(std::initializer_list<value_type> items,
+ Hash const & hash, KeyEqual const & equal)
+ : unordered_map{container_type{items}, hash, equal} {
+ constexpr_assert(items.size() == N, "Inconsistent initializer_list size and type size argument");
+ }
+
+ constexpr unordered_map(std::initializer_list<value_type> items)
+ : unordered_map{items, Hash{}, KeyEqual{}} {}
+
+ /* iterators */
+ constexpr iterator begin() { return items_.begin(); }
+ constexpr iterator end() { return items_.end(); }
+ constexpr const_iterator begin() const { return items_.begin(); }
+ constexpr const_iterator end() const { return items_.end(); }
+ constexpr const_iterator cbegin() const { return items_.cbegin(); }
+ constexpr const_iterator cend() const { return items_.cend(); }
+
+ /* capacity */
+ constexpr bool empty() const { return !N; }
+ constexpr size_type size() const { return N; }
+ constexpr size_type max_size() const { return N; }
+
+ /* lookup */
+ constexpr std::size_t count(Key const &key) const {
+ auto const &kv = lookup(key);
+ return equal_(kv.first, key);
+ }
+
+ constexpr Value const &at(Key const &key) const {
+ return at_impl(*this, key);
+ }
+ constexpr Value &at(Key const &key) {
+ return at_impl(*this, key);
+ }
+
+ constexpr const_iterator find(Key const &key) const {
+ return find_impl(*this, key);
+ }
+ constexpr iterator find(Key const &key) {
+ return find_impl(*this, key);
+ }
+
+ constexpr std::pair<const_iterator, const_iterator> equal_range(Key const &key) const {
+ return equal_range_impl(*this, key);
+ }
+ constexpr std::pair<iterator, iterator> equal_range(Key const &key) {
+ return equal_range_impl(*this, key);
+ }
+
+ /* bucket interface */
+ constexpr std::size_t bucket_count() const { return storage_size; }
+ constexpr std::size_t max_bucket_count() const { return storage_size; }
+
+ /* observers*/
+ constexpr hasher hash_function() const { return tables_.hash_; }
+ constexpr key_equal key_eq() const { return equal_; }
+
+private:
+ template <class This>
+ static inline constexpr auto& at_impl(This&& self, Key const &key) {
+ auto& kv = self.lookup(key);
+ if (self.equal_(kv.first, key))
+ return kv.second;
+ else
+ FROZEN_THROW_OR_ABORT(std::out_of_range("unknown key"));
+ }
+
+ template <class This>
+ static inline constexpr auto find_impl(This&& self, Key const &key) {
+ auto& kv = self.lookup(key);
+ if (self.equal_(kv.first, key))
+ return &kv;
+ else
+ return self.items_.end();
+ }
+
+ template <class This>
+ static inline constexpr auto equal_range_impl(This&& self, Key const &key) {
+ auto& kv = self.lookup(key);
+ using kv_ptr = decltype(&kv);
+ if (self.equal_(kv.first, key))
+ return std::pair<kv_ptr, kv_ptr>{&kv, &kv + 1};
+ else
+ return std::pair<kv_ptr, kv_ptr>{self.items_.end(), self.items_.end()};
+ }
+
+ template <class This>
+ static inline constexpr auto& lookup_impl(This&& self, Key const &key) {
+ return self.items_[self.tables_.lookup(key)];
+ }
+
+ constexpr auto const& lookup(Key const &key) const {
+ return lookup_impl(*this, key);
+ }
+ constexpr auto& lookup(Key const &key) {
+ return lookup_impl(*this, key);
+ }
+};
+
+template <typename T, typename U, std::size_t N>
+constexpr auto make_unordered_map(std::pair<T, U> const (&items)[N]) {
+ return unordered_map<T, U, N>{items};
+}
+
+} // namespace frozen
+
+#endif
diff --git a/contrib/frozen/include/frozen/unordered_set.h b/contrib/frozen/include/frozen/unordered_set.h
new file mode 100644
index 0000000..0fca292
--- /dev/null
+++ b/contrib/frozen/include/frozen/unordered_set.h
@@ -0,0 +1,147 @@
+/*
+ * Frozen
+ * Copyright 2016 QuarksLab
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef FROZEN_LETITGO_UNORDERED_SET_H
+#define FROZEN_LETITGO_UNORDERED_SET_H
+
+#include "frozen/bits/basic_types.h"
+#include "frozen/bits/constexpr_assert.h"
+#include "frozen/bits/elsa.h"
+#include "frozen/bits/pmh.h"
+#include "frozen/bits/version.h"
+#include "frozen/random.h"
+
+#include <utility>
+
+namespace frozen {
+
+namespace bits {
+
+struct Get {
+ template <class T> constexpr T const &operator()(T const &key) const {
+ return key;
+ }
+};
+
+} // namespace bits
+
+template <class Key, std::size_t N, typename Hash = elsa<Key>,
+ class KeyEqual = std::equal_to<Key>>
+class unordered_set {
+ static constexpr std::size_t storage_size =
+ bits::next_highest_power_of_two(N) * (N < 32 ? 2 : 1); // size adjustment to prevent high collision rate for small sets
+ using container_type = bits::carray<Key, N>;
+ using tables_type = bits::pmh_tables<storage_size, Hash>;
+
+ KeyEqual const equal_;
+ container_type keys_;
+ tables_type tables_;
+
+public:
+ /* typedefs */
+ using key_type = Key;
+ using value_type = Key;
+ using size_type = typename container_type::size_type;
+ using difference_type = typename container_type::difference_type;
+ using hasher = Hash;
+ using key_equal = KeyEqual;
+ using const_reference = typename container_type::const_reference;
+ using reference = const_reference;
+ using const_pointer = typename container_type::const_pointer;
+ using pointer = const_pointer;
+ using const_iterator = const_pointer;
+ using iterator = const_iterator;
+
+public:
+ /* constructors */
+ unordered_set(unordered_set const &) = default;
+ constexpr unordered_set(container_type keys, Hash const &hash,
+ KeyEqual const &equal)
+ : equal_{equal}
+ , keys_{keys}
+ , tables_{bits::make_pmh_tables<storage_size>(
+ keys_, hash, bits::Get{}, default_prg_t{})} {}
+ explicit constexpr unordered_set(container_type keys)
+ : unordered_set{keys, Hash{}, KeyEqual{}} {}
+
+ constexpr unordered_set(std::initializer_list<Key> keys)
+ : unordered_set{keys, Hash{}, KeyEqual{}} {}
+
+ constexpr unordered_set(std::initializer_list<Key> keys, Hash const & hash, KeyEqual const & equal)
+ : unordered_set{container_type{keys}, hash, equal} {
+ constexpr_assert(keys.size() == N, "Inconsistent initializer_list size and type size argument");
+ }
+
+ /* iterators */
+ constexpr const_iterator begin() const { return keys_.begin(); }
+ constexpr const_iterator end() const { return keys_.end(); }
+ constexpr const_iterator cbegin() const { return keys_.cbegin(); }
+ constexpr const_iterator cend() const { return keys_.cend(); }
+
+ /* capacity */
+ constexpr bool empty() const { return !N; }
+ constexpr size_type size() const { return N; }
+ constexpr size_type max_size() const { return N; }
+
+ /* lookup */
+ constexpr std::size_t count(Key const &key) const {
+ auto const k = lookup(key);
+ return equal_(k, key);
+ }
+ constexpr const_iterator find(Key const &key) const {
+ auto const &k = lookup(key);
+ if (equal_(k, key))
+ return &k;
+ else
+ return keys_.end();
+ }
+
+ constexpr std::pair<const_iterator, const_iterator> equal_range(Key const &key) const {
+ auto const &k = lookup(key);
+ if (equal_(k, key))
+ return {&k, &k + 1};
+ else
+ return {keys_.end(), keys_.end()};
+ }
+
+ /* bucket interface */
+ constexpr std::size_t bucket_count() const { return storage_size; }
+ constexpr std::size_t max_bucket_count() const { return storage_size; }
+
+ /* observers*/
+ constexpr hasher hash_function() const { return tables_.hash_; }
+ constexpr key_equal key_eq() const { return equal_; }
+
+private:
+ constexpr auto const &lookup(Key const &key) const {
+ return keys_[tables_.lookup(key)];
+ }
+};
+
+template <typename T, std::size_t N>
+constexpr auto make_unordered_set(T const (&keys)[N]) {
+ return unordered_set<T, N>{keys};
+}
+
+} // namespace frozen
+
+#endif