更新:1、新增数据记录功能,将过程数据录入数据库;

2、增加输入点迹数据、凝聚后点迹数据记录;

Signed-off-by: waiwaylee <waiwaylee@foxmail.com>
This commit is contained in:
2026-09-30 09:02:28 +08:00
parent ff9b111d34
commit a4f32e4036
111 changed files with 321343 additions and 262 deletions
+240
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.
*/
#ifndef FROZEN_LETITGO_BITS_ALGORITHMS_H
#define FROZEN_LETITGO_BITS_ALGORITHMS_H
#include <limits>
#include <tuple>
#include "frozen/bits/basic_types.h"
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
+224
View File
@@ -0,0 +1,224 @@
/*
* 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 <array>
#include <iterator>
#include <string>
#include <utility>
#include "frozen/bits/exceptions.h"
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");
}
template <std::size_t M>
constexpr carray(std::array<T, M> const &init)
: carray(&init[0], 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
+38
View File
@@ -0,0 +1,38 @@
/*
* 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
+69
View File
@@ -0,0 +1,69 @@
/*
* 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
#if __cpp_deduction_guides >= 201703L
#define FROZEN_LETITGO_HAS_DEDUCTION_GUIDES
#endif
#if __cpp_lib_constexpr_string >= 201907L
#define FROZEN_LETITGO_HAS_CONSTEXPR_STRING
#endif
#endif // FROZEN_LETITGO_DEFINES_H
+60
View File
@@ -0,0 +1,60 @@
/*
* 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 = void>
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 <>
struct elsa<void> {
template <class T>
constexpr std::size_t operator()(T const &value, std::size_t seed) const {
return elsa<T>{}(value, seed);
}
};
template <class T>
using anna = elsa<T>;
} // namespace frozen
#endif
+44
View File
@@ -0,0 +1,44 @@
#ifndef FROZEN_LETITGO_BITS_ELSA_STD_H
#define FROZEN_LETITGO_BITS_ELSA_STD_H
#include "elsa.h"
#include "hash_string.h"
#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
#include <string_view>
#endif
#include <string>
namespace frozen {
#ifdef FROZEN_LETITGO_HAS_STRING_VIEW
template <typename CharT>
struct elsa<std::basic_string_view<CharT>> {
constexpr std::size_t operator()(
const std::basic_string_view<CharT> &value) const {
return hash_string(value);
}
constexpr std::size_t operator()(const std::basic_string_view<CharT> &value,
std::size_t seed) const {
return hash_string(value, seed);
}
};
#endif
template <typename CharT>
struct elsa<std::basic_string<CharT>> {
constexpr std::size_t operator()(
const std::basic_string<CharT> &value) const {
return hash_string(value);
}
constexpr std::size_t operator()(const std::basic_string<CharT> &value,
std::size_t seed) const {
return hash_string(value, seed);
}
};
} // namespace frozen
#endif // FROZEN_LETITGO_BITS_ELSA_STD_H
+40
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_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
+27
View File
@@ -0,0 +1,27 @@
#ifndef FROZEN_LETITGO_BITS_HASH_STRING_H
#define FROZEN_LETITGO_BITS_HASH_STRING_H
#include <cstddef>
namespace frozen {
template <typename String>
constexpr std::size_t hash_string(const String &value) {
std::size_t d = 5381;
for (const auto &c : value) d = d * 33 + static_cast<size_t>(c);
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.
template <typename String>
constexpr std::size_t hash_string(const String &value, std::size_t seed) {
std::size_t d = (0x811c9dc5 ^ seed) * static_cast<size_t>(0x01000193);
for (const auto &c : value)
d = (d ^ static_cast<size_t>(c)) * static_cast<size_t>(0x01000193);
return d >> 8;
}
} // namespace frozen
#endif // FROZEN_LETITGO_BITS_HASH_STRING_H
+259
View File
@@ -0,0 +1,259 @@
/*
* 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 <array>
#include <limits>
#include "frozen/bits/algorithms.h"
#include "frozen/bits/basic_types.h"
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_;
template <typename KeyType>
constexpr std::size_t lookup(const KeyType &key) const {
return lookup(key, 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, typename HasherType>
constexpr std::size_t lookup(const KeyType &key,
const HasherType &hasher) const {
auto const d =
first_table_[hasher(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_[hasher(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
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 1
#define FROZEN_PATCH_VERSION 1
#endif