@@ -29,4 +29,5 @@ | |||
| fpconv | ? | Boost | YES | many changes | | |||
| fastutf8 | ? | MIT | YES | many changes | | |||
| expected | v1.0 | Public Domain / CC0 | NO | | | |||
| robin-hood | 3.9.1 | MIT | NO | | | |||
| robin-hood | 3.9.1 | MIT | NO | | | |||
| frozen | 1.0.1 | Apache 2 | NO | | |
@@ -0,0 +1,3 @@ | |||
serge-sans-paille <sguelton@quarkslab.com> | |||
Jérôme Dumesnil <jerome.dumesnil@gmail.com> | |||
Chris Beck <chbeck@tesla.com> |
@@ -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") |
@@ -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. |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 | |||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |