Browse Source

[Project] Css: Add frozen library from https://github.com/serge-sans-paille/frozen/

tags/3.0
Vsevolod Stakhov 3 years ago
parent
commit
e2799764c4

+ 2
- 1
contrib/DEPENDENCY_INFO.md View File

@@ -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 | |

+ 3
- 0
contrib/frozen/AUTHORS View File

@@ -0,0 +1,3 @@
serge-sans-paille <sguelton@quarkslab.com>
Jérôme Dumesnil <jerome.dumesnil@gmail.com>
Chris Beck <chbeck@tesla.com>

+ 12
- 0
contrib/frozen/CMakeLists.txt View File

@@ -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")

+ 202
- 0
contrib/frozen/LICENSE View File

@@ -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.

+ 197
- 0
contrib/frozen/include/frozen/algorithm.h View File

@@ -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

+ 229
- 0
contrib/frozen/include/frozen/bits/algorithms.h View File

@@ -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

+ 200
- 0
contrib/frozen/include/frozen/bits/basic_types.h View File

@@ -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

+ 40
- 0
contrib/frozen/include/frozen/bits/constexpr_assert.h View File

@@ -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


+ 58
- 0
contrib/frozen/include/frozen/bits/defines.h View File

@@ -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

+ 50
- 0
contrib/frozen/include/frozen/bits/elsa.h View File

@@ -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

+ 39
- 0
contrib/frozen/include/frozen/bits/exceptions.h View File

@@ -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

+ 240
- 0
contrib/frozen/include/frozen/bits/pmh.h View File

@@ -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

+ 30
- 0
contrib/frozen/include/frozen/bits/version.h View File

@@ -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

+ 323
- 0
contrib/frozen/include/frozen/map.h View File

@@ -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

+ 90
- 0
contrib/frozen/include/frozen/random.h View File

@@ -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

+ 220
- 0
contrib/frozen/include/frozen/set.h View File

@@ -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

+ 152
- 0
contrib/frozen/include/frozen/string.h View File

@@ -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

+ 197
- 0
contrib/frozen/include/frozen/unordered_map.h View File

@@ -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

+ 147
- 0
contrib/frozen/include/frozen/unordered_set.h View File

@@ -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

Loading…
Cancel
Save