Compare commits

..

54 commits

Author SHA1 Message Date
King_DuckZ
96c6ac1df3 No idea what this is
This stuff's been laying around for months and years,
just committing and crossing fingers - pro coding here!
2025-08-23 12:39:15 +01:00
King_DuckZ
a2d6944249 New PackedPointer class 2025-08-23 12:36:29 +01:00
King_DuckZ
cc129eb4e2 Update catch2 2025-08-23 12:35:08 +01:00
4d904ac689 Fix deprecation warning
Also put iterator into dhandy namespace. I don't
remember why I left it out, and it's probably a
sign I should have not done so.
2024-04-26 00:19:50 +02:00
d3092f9359 Update catch ref to 3.5.4
Fix noob mistake in previous commit
2024-04-25 23:48:40 +02:00
cd85666005 Fix build of unit tests 2024-04-19 23:18:26 +02:00
fc5f917970 Update copyright year 2024-03-27 15:56:33 +01:00
180c338901 Just leave 'cpp' in there
It seems to be required now, but also '' is not
a valid language and the whole get_option() thing
is not working when duckhandy is a submodule.
2024-02-15 23:14:45 +01:00
100b1d557e Remove Catch2 submodule, use meson wrap
Catch2 seems to be Meson-ready now so
removing custom meson file too
2024-02-15 22:43:14 +01:00
df2f614642 Build fix on newer Meson versions 2024-02-15 22:07:05 +01:00
f04eb9f5d3 Forgot this 2022-06-07 16:51:37 +02:00
82b5200857 Add meson build scripts 2022-06-07 16:43:26 +02:00
9919f1aeb2 Use std::to_string when doing ascii conversions
It's fast, it works, it's correct. No need for
any of the fancy stuff when all we want is int
to ascii string.

Currently on my system the implementation of
std::to_string is *very* similar to mine, but
it doesn't have the overhead of calculating
ASCII offsets because their lookup already
contains ASCII values.
2021-06-07 23:10:35 +02:00
e1599820b4 Revert "Trying with a smaller lookup, still slower than std::to_string"
This reverts commit 18cdd4d9b5.
2021-06-07 22:13:50 +02:00
18cdd4d9b5 Trying with a smaller lookup, still slower than std::to_string 2021-06-07 22:12:58 +02:00
180f79fae9 Replace std::array with C array 2021-06-07 21:54:46 +02:00
c9b2d36491 Pull lookup out.
This makes the function run faster
2021-06-07 21:52:33 +02:00
a171faa95d Revert lookup removal, but keep the speed test cpp
This reverts commit 4f1c0f8d6df21d7c3b404d41512bba0b60ba7689.
2021-06-07 20:21:44 +02:00
a68815b3cd Same conversion but without any lookup 2021-06-07 20:21:32 +02:00
e3140a3add Trying with a smaller lookup, still slower than std::to_string 2021-06-07 20:20:35 +02:00
9dbabcb5c4 Working on optimisation but I'm still losing to std::to_string() 2021-05-29 22:52:30 +02:00
420257f578 Use parameter instead of assuming 10 numeric digits 2021-05-29 17:07:55 +02:00
199db7640e Add support for int_conv<std::array>() 2021-05-29 16:47:48 +02:00
938c8fa9a4 Make code a bit more readable
Changed so that int_conv<string_view>() called on a
non-constexpr doesn't compiler anymore (because code
would try to go through a consteval method). It
wouldn't work anyways as the returned value would be
always garbage. If you want a string_view then you
must either give a constexpr input value or you must
call int_conv_raw and call to_string_view() yourself.
This is better than throwing a runtime exception (which
was working ok btw).

All the SafeRetVal stuff is not needed anymore.

Also no need for all that confusing sfinae, I can just
use a bool FromInt and specialise on that.
2021-05-29 16:44:06 +02:00
a675624cab Add case sensitivity support to sse conversion 2021-05-29 12:01:01 +02:00
094f7fc679 Rename HashType to TigerHash 2021-05-29 00:57:24 +02:00
e8467cebe0 Remove custom lengthof()
duckhandy has an implementation already
2021-05-29 00:56:39 +02:00
d068e68e75 Replace with consteval
It doesn't makes any sense to use this implementation
at runtime.
2021-05-29 00:52:13 +02:00
327d93a6a4 Fix namespaces, copyright and magic numbers 2021-05-29 00:52:13 +02:00
d3731253e4 Import build time tiger hasd from doorkeeper 2021-05-29 00:34:39 +02:00
db554b8b85 Update Catch2 to latest v2.x branch 2021-05-28 02:54:18 +02:00
1ec0e143fd Replace string with basic_string<T> 2021-05-28 02:48:49 +02:00
d0e7ca0bee Merge functions 2021-05-28 02:48:07 +02:00
9539b5430f Some small code improvements 2021-05-28 02:41:41 +02:00
562eba5f68 Delete sequence_bt.hpp
This stuff has been in the standard lib
for a long time now.
2021-05-28 02:40:19 +02:00
422b475ce3 Add support for constexpr string_view creation 2021-05-28 02:06:28 +02:00
e62da38cf9 Cleaning up and simplifying code a bit 2021-05-28 02:03:52 +02:00
7f8f092372 Fix wrong variable name 2021-05-28 01:44:49 +02:00
29f6a56fc8 Some cleaning 2021-05-28 01:44:28 +02:00
eedad0d82c Move Version to bt namespace 2021-04-22 14:10:28 +02:00
5ccf4dde55 Update Catch2 to latest v2.x branch 2021-04-22 14:08:13 +02:00
5db217c978 Update copyright to 2021 2021-04-22 14:07:53 +02:00
710cdf9f04 Allow string_view conv when it's safe
You can still force a string_view conv even when it's
not safe to do so if you only intend to use the
return value during its lifetime validity. Call
int_conv_temporary() in that case.
2021-04-22 13:59:51 +02:00
b52343014b int_conv can be constexpr sometimes 2021-04-22 13:57:57 +02:00
1f44e74465 Test if conversion is using the sse when possible 2021-04-22 13:44:49 +02:00
13bd166827 Rename Count to lowercase, make const 2021-04-22 13:37:02 +02:00
3124548314 Implement Version class 2021-04-22 13:34:05 +02:00
da136cd52f Build fix in unit test 2021-04-22 13:14:10 +02:00
93d2ad6bd0 Make ary_to_int() constexpr 2021-04-22 13:02:51 +02:00
3343b51a39 Simplify code 2021-04-22 03:09:31 +02:00
40bae9c49d Build fix for clang 2021-04-22 02:59:51 +02:00
1c6de14cd4 Add test for upper case conversions and fix as necessary 2020-08-14 00:30:22 +01:00
f1d6ac789e Indentation 2020-08-14 00:04:05 +01:00
79ca881bc1 Warning fix
This fixes ary_to_int() for negative values
2020-08-13 23:54:06 +01:00
58 changed files with 4433 additions and 1968 deletions

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
tags
compile_commands.json
.clangd
.cache
subprojects/Catch2/
subprojects/sprout/

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "lib/Catch2"]
path = lib/Catch2
url = https://github.com/catchorg/Catch2.git

View file

@ -2,16 +2,15 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(duckhandy VERSION 0.1.0)
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
include(shared_git_project)
include(CTest)
find_package(Sprout REQUIRED)
set(DUCKHANDY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
if (BUILD_TESTING)
set(BUILD_TESTS CACHE BOOL ON)
set(BUILD_TESTING CACHE BOOL ON)
else()
set(BUILD_TESTS CACHE BOOL OFF)
set(BUILD_TESTING CACHE BOOL OFF)
endif()
add_library(${PROJECT_NAME} INTERFACE)
@ -27,7 +26,7 @@ target_compile_features(${PROJECT_NAME}
INTERFACE cxx_decltype_incomplete_return_types
INTERFACE cxx_noexcept
INTERFACE cxx_rvalue_references
INTERFACE cxx_std_17
INTERFACE cxx_std_20
)
target_include_directories(${PROJECT_NAME}
@ -42,6 +41,10 @@ target_compile_definitions(${PROJECT_NAME}
INTERFACE SPROUT_USE_TEMPLATE_ALIASES
)
target_compile_options(${PROJECT_NAME}
INTERFACE -mprfchw
)
if (BUILD_TESTING)
add_subdirectory(test/unit)
endif()

View file

@ -1,85 +0,0 @@
cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR)
function (add_shared_git_project SUBMODULE_PATH)
if (IS_ABSOLUTE "${SUBMODULE_PATH}")
set(submod_path "${SUBMODULE_PATH}")
else()
set(submod_path "${CMAKE_CURRENT_SOURCE_DIR}/${SUBMODULE_PATH}")
endif()
if (NOT EXISTS "${submod_path}")
message(FATAL_ERROR "Path \"${submod_path}\" doesn't exist")
endif()
if (NOT IS_DIRECTORY "${submod_path}")
message(FATAL_ERROR "Path \"${submod_path}\" is not a valid directory")
endif()
if (NOT EXISTS "${submod_path}/.git")
message(FATAL_ERROR ".git not found in \"${submod_path}\". Not a git submodule?")
endif()
if (IS_DIRECTORY "${submod_path}/.git")
message(FATAL_ERROR "\"${submod_path}.git\" is a directory, not a file as expected. Not a git submodule?")
endif()
get_filename_component(proj_name_orig "${submod_path}" NAME)
if ("${proj_name_orig}" STREQUAL "")
message(FATAL_ERROR "Couldn't make up a name for given project in \"${submod_path}\"")
endif()
string(MAKE_C_IDENTIFIER "${proj_name_orig}" proj_name_c_id)
string(TOUPPER ${proj_name_c_id} proj_name)
get_property(shared_projects_list GLOBAL PROPERTY SHARED_PROJECTS_LIST)
list(FIND shared_projects_list ${proj_name} found_index)
if (${found_index} GREATER -1)
#nothing to do, the variable is already set so the project must have been
#included already
return()
endif()
#Obtain the path to the working tree
# see http://stackoverflow.com/questions/27379818/git-possible-to-use-same-submodule-working-copy-by-multiple-projects
# git rev-parse --git-dir --show-toplevel
execute_process(
COMMAND git rev-parse --show-toplevel
WORKING_DIRECTORY "${submod_path}"
OUTPUT_VARIABLE matched_gitdir
OUTPUT_STRIP_TRAILING_WHITESPACE
)
#Make sure we got an absolute path
if (IS_ABSOLUTE "${matched_gitdir}")
set(reported_submodule_dir "${matched_gitdir}")
else()
file(RELATIVE_PATH reported_submodule_dir "${CMAKE_CURRENT_SOURCE_DIR}" "${submod_path}/${matched_gitdir}")
endif()
unset(matched_gitdir)
#Check if submodule is a subdirectory of the current source dir
file(RELATIVE_PATH reported_submodule_rel_path "${CMAKE_CURRENT_SOURCE_DIR}" "${reported_submodule_dir}")
string(LENGTH "${reported_submodule_rel_path}" rel_path_len)
if (${rel_path_len} GREATER 2)
string(SUBSTRING "${reported_submodule_rel_path}" 0 3 first_bit)
if ("../" STREQUAL "${first_bit}")
set(is_out_of_dirtree ON)
else()
set(is_out_of_dirtree OFF)
endif()
unset(first_bit)
else()
set(is_out_of_dirtree OFF)
endif()
unset(rel_path_len)
#Globally mark current submodule as handled
set_property(GLOBAL APPEND PROPERTY SHARED_PROJECTS_LIST ${proj_name})
set(shared_project_binary "${CMAKE_CURRENT_BINARY_DIR}/shared_projects/${proj_name_orig}")
if (is_out_of_dirtree)
#message(FATAL_ERROR "Would call add_subdirectory(\"${reported_submodule_dir}\" \"${shared_project_binary}\")")
add_subdirectory("${reported_submodule_dir}" "${shared_project_binary}" ${ARGN})
else()
#message(FATAL_ERROR "Would call add_subdirectory(\"${reported_submodule_rel_path}\")")
add_subdirectory("${reported_submodule_rel_path}" ${ARGN})
endif()
endfunction()

View file

@ -1,2 +0,0 @@
inplace_submodules:
- Sprout

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2025 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -99,7 +99,8 @@ namespace dhandy {
};
template <typename T>
constexpr inline T make_mask (std::size_t len) {
[[gnu::const]]
constexpr inline T make_mask (std::size_t len) noexcept {
return (1 << len) - 1;
}
} //namespace implem
@ -118,7 +119,7 @@ namespace dhandy {
template <std::size_t Idx, typename U, std::size_t... S> friend U get (const BitfieldPack<U, S...>&);
template <std::size_t Idx, typename U, typename V, std::size_t... S> friend void set (BitfieldPack<U, S...>&, V);
typedef implem::BitfieldData<T, Facts::ElementCount> base_type;
static_assert(Facts::LargestSize <= sizeof(T) * CHAR_BIT, "Bitfield size can't be larget than the data type itself");
static_assert(Facts::LargestSize <= sizeof(T) * CHAR_BIT, "Bitfield size can't be larger than the data type itself");
public:
BitfieldPack (T init=T{}) : base_type(init) {}
};
@ -136,15 +137,16 @@ namespace dhandy {
const constexpr bool bleeds_into_next = reloffs + so.size > sizeof(T) * CHAR_BIT;
const T bottom = static_cast<const BitfieldData<T, index + 1>&>(pack).value() >> reloffs;
if (bleeds_into_next) {
const std::size_t safe_index = index + 2 - not bleeds_into_next;
if constexpr (bleeds_into_next) {
const std::size_t safe_index = index + 2;
const T val = static_cast<const BitfieldData<T, safe_index>&>(pack).value();
const T top = val << (sizeof(T) * CHAR_BIT - reloffs);
return static_cast<T>(top | bottom) & make_mask<T>(so.size);
}
else {
return bottom & make_mask<T>(so.size);
}
}
template <std::size_t Idx, typename T, typename V, std::size_t... Sizes>
void set (BitfieldPack<T, Sizes...>& pack, V val) {

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -18,11 +18,13 @@
#ifndef id4754A95F12BE4ADEA65642A056A51907
#define id4754A95F12BE4ADEA65642A056A51907
#include "duckhandy/implem/reversed_sized_array_bt.hpp"
#include "reversed_sized_array_bt.hpp"
#include "../has_method.hpp"
#include <sprout/math/log10.hpp>
#include <sprout/math/abs.hpp>
#include <sprout/math/ceil.hpp>
#include <cstddef>
#include <cstdint>
#include <array>
#include <limits>
#include <emmintrin.h>
@ -33,6 +35,7 @@
# include <string_view>
# include <string>
#endif
#include <type_traits>
namespace dhandy {
namespace implem {
@ -49,6 +52,14 @@ namespace dhandy {
}
} //unnamed namespace
//Used for checking ASCIITranslator::AltLetter
define_has_enum(AltLetter, AltLetter);
template <typename Tr, bool=HasAltLetterEnum<Tr>::value != 0>
inline auto g_AltLetterOrZero = Tr::AltLetter;
template <typename Tr>
inline auto g_AltLetterOrZero<Tr, false> = Tr::NullChar;
template <typename T, typename C, unsigned int Base, typename Tr>
T to_integer_sse (const C* s, std::size_t l);
@ -68,6 +79,9 @@ namespace dhandy {
static const constexpr std::size_t max_len = max_digit_count<typename std::conditional<always_unsigned, std::make_unsigned_t<I>, I>::type, Base> + is_signed;
};
template <typename I, unsigned int Base, typename Tr>
using RevArray = ReversedSizedArray<typename Tr::char_type, int_info<I, Base>::max_len + 1>;
template <typename I, unsigned int Base, bool Signed=int_info<I, Base>::is_signed>
struct IsNegative { static constexpr bool check (I) { return false; } };
template <typename I, unsigned int Base>
@ -90,21 +104,35 @@ namespace dhandy {
template <typename L>
[[gnu::pure,gnu::always_inline]]
static constexpr L abs(L in) { return (not BecomesUnsigned and std::numeric_limits<L>::is_signed and in < L(0) ? -in : in); }
static constexpr L abs(L v);
[[gnu::pure,gnu::always_inline]]
static constexpr CastedType cast (I in) { return static_cast<CastedType>(in); }
};
template <typename I, std::size_t Base, bool IsSigned, bool ForceUnsigned>
template <typename L>
[[gnu::const,gnu::always_inline]]
inline constexpr L NumberAdaptation<I, Base, IsSigned, ForceUnsigned>::abs(L v) {
if constexpr (not BecomesUnsigned and std::numeric_limits<L>::is_signed) {
//https://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs
const L mask = v >> (sizeof(L) * CHAR_BIT - 1);
const UnsignedType r = (v + mask) ^ mask;
return static_cast<L>(r);
}
else {
return v;
}
}
template <typename I, unsigned int Base, typename Tr, typename=void>
struct IntConversion {
static constexpr ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, implem::int_info<I, Base>::max_len + 1> to_ary (I in) {
using RetType = ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, implem::int_info<I, Base>::max_len + 1>;
static constexpr RevArray<I, Base, Tr> to_ary (I in) {
using Num = implem::NumberAdaptation<I, Base>;
const bool was_negative = implem::is_negative<I, Base>(in);
RetType arr;
arr.push_front('\0');
RevArray<I, Base, Tr> arr;
arr.push_front(Tr::NullChar);
do {
arr.push_front(Tr::to_digit(static_cast<int>(Num::abs(Num::cast(in)) % Base)));
in = static_cast<I>(Num::cast(in) / static_cast<I>(Base));
@ -117,11 +145,9 @@ namespace dhandy {
template <unsigned int Base, typename Tr>
struct IntConversion<bool, Base, Tr, void> {
static constexpr ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, 2> to_ary (bool in) {
using RetType = ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, 2>;
RetType arr;
arr.push_front('\0');
static constexpr ReversedSizedArray<typename Tr::char_type, 2> to_ary (bool in) {
ReversedSizedArray<typename Tr::char_type, 2> arr;
arr.push_front(Tr::NullChar);
arr.push_front(in ? Tr::to_digit(1) : Tr::to_digit(0));
return arr;
}
@ -129,11 +155,8 @@ namespace dhandy {
template <typename I, typename Tr>
struct IntConversion<I, 10, Tr, typename std::enable_if<std::is_integral<I>::value and not std::is_same<I, bool>::value>::type> {
static constexpr ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, implem::int_info<I, 10>::max_len + 1> to_ary (I in) {
using RetType = ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, implem::int_info<I, 10>::max_len + 1>;
using Num = implem::NumberAdaptation<I, 10>;
const constexpr char lookup[200] = {
private:
static const constexpr char lookup[200] = {
0,0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,1,0,1,1,1,2,1,3,1,4,
1,5,1,6,1,7,1,8,1,9,2,0,2,1,2,2,2,3,2,4,2,5,2,6,2,7,2,8,2,9,
3,0,3,1,3,2,3,3,3,4,3,5,3,6,3,7,3,8,3,9,4,0,4,1,4,2,4,3,4,4,
@ -142,21 +165,30 @@ namespace dhandy {
7,5,7,6,7,7,7,8,7,9,8,0,8,1,8,2,8,3,8,4,8,5,8,6,8,7,8,8,8,9,
9,0,9,1,9,2,9,3,9,4,9,5,9,6,9,7,9,8,9,9
};
public:
static constexpr RevArray<I, 10, Tr> to_ary (I in) {
using RetType = RevArray<I, 10, Tr>;
using Num = implem::NumberAdaptation<I, 10>;
const bool was_negative = implem::is_negative<I, 10>(in);
RetType arr;
arr.push_front('\0');
while (Num::abs(in) >= static_cast<I>(100)) {
const auto index = (Num::abs(in) % 100) * 2;
if (not std::is_constant_evaluated())
__builtin_prefetch(arr.base_ptr(), 1, 3);
arr.push_front(Tr::NullChar);
in = Num::abs(in);
while (in >= static_cast<I>(100)) {
const auto index = (in % 100) * 2;
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 1])));
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
in = static_cast<I>(in / static_cast<I>(100));
};
if (Num::abs(in) < static_cast<I>(10)) {
arr.push_front(Tr::to_digit(static_cast<int>(Num::abs(in))));
if (in < static_cast<I>(10)) {
arr.push_front(Tr::to_digit(static_cast<int>(in)));
}
else {
const auto index = Num::abs(in) * 2;
const auto index = in * 2;
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 1])));
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
}
@ -166,10 +198,22 @@ namespace dhandy {
}
};
template <typename I, unsigned int Base, typename Tr>
template <typename I, I In, unsigned int Base, typename Tr>
inline constexpr const auto g_int_to_str = IntConversion<std::remove_cvref_t<I>, Base, Tr>::to_ary(In);
template <typename T>
[[gnu::always_inline,gnu::pure]]
constexpr inline T negated_ifn (T n, bool negate) {
//return static_cast<int32_t>(((static_cast<unsigned int>(n) - (mask bitand 1)) xor mask) bitor ((mask bitand 1) << 31));
return (negate ? -n : n);
}
template <typename I, unsigned int Base, typename Tr, bool Constexpr, typename=void>
struct AryConversion {
constexpr static const bool is_sse = false;
template <typename C>
static I from_ary (const C* beg, const C* end) {
constexpr static I from_ary (const C* beg, const C* end) {
I retval = 0;
I factor = 1;
std::size_t i = end - beg;
@ -183,34 +227,26 @@ namespace dhandy {
retval += Tr::from_digit(beg[i]) * factor;
factor *= Base;
}
return retval;
return negated_ifn(retval, was_negative);
}
};
template <typename I, typename Tr, typename=typename std::enable_if<Tr::BehavesLikeASCII and std::is_integral<I>::value and not std::is_same<I, bool>::value and sizeof(I) <= sizeof(uint32_t)>::type>
using SelectIForSSEToInt = I;
template <typename I, unsigned int Base, typename Tr>
struct AryConversion<SelectIForSSEToInt<I, Tr>, Base, Tr> {
struct AryConversion<I, Base, Tr, false, typename std::enable_if<std::is_integral<I>::value and not std::is_same<I, bool>::value and sizeof(I) <= sizeof(std::uint32_t)>::type> {
constexpr static const bool is_sse = true;
template <typename C> static I from_ary (C* beg, C* end) { return to_integer_sse<I, C, Base, Tr>(beg, end - beg); }
};
template <unsigned int Base, typename Tr>
struct AryConversion<bool, Base, Tr> {
template <typename C> static bool from_ary (C* beg, C* end) {
template <unsigned int Base, typename Tr, bool Constexpr>
struct AryConversion<bool, Base, Tr, Constexpr> {
constexpr static const bool is_sse = false;
template <typename C> constexpr static bool from_ary (C* beg, C* end) {
if (end == beg)
return false;
return (Tr::from_digit(*beg) ? true : false);
}
};
template <typename T>
[[gnu::always_inline,gnu::pure]]
inline T negated_ifn (T n, bool negate) {
//return static_cast<int32_t>(((static_cast<unsigned int>(n) - (mask bitand 1)) xor mask) bitor ((mask bitand 1) << 31));
return (negate ? -n : n);
}
template <typename T, typename C, unsigned int Base, typename Tr>
[[gnu::pure]]
T to_integer_sse (const C* s, std::size_t l) {
@ -240,13 +276,24 @@ namespace dhandy {
__m128i factor = _mm_set_epi32(base3, base2, base1, 1);
__m128i res = _mm_set1_epi32(0);
const __m128i char_0 = _mm_set1_epi32(Tr::FirstDigit);
const __m128i char_a = _mm_set1_epi32(Tr::FirstLetter);
const __m128i char_befo_a = _mm_set1_epi32(Tr::FirstLetter - 1);
const __m128i char_past_f = _mm_set1_epi32(Tr::FirstLetter + Base - Tr::DigitCount);
std::size_t idx = 0;
const std::size_t cap = l bitand -4;
do {
const __m128i digits = _mm_set_epi32(s[cap - idx - 3 - 1], s[cap - idx - 2 - 1], s[cap - idx - 1 - 1], s[cap - idx - 0 - 1]);
const __m128i mask = _mm_cmplt_epi32(digits, char_a);
const __m128i addend = _mm_add_epi32(_mm_andnot_si128(mask, _mm_sub_epi32(char_a, _mm_set1_epi32(10))), _mm_and_si128(mask, char_0));
__m128i mask = _mm_and_si128(_mm_cmpgt_epi32(digits, char_befo_a), _mm_cmplt_epi32(digits, char_past_f));
__m128i offs = _mm_and_si128(mask, _mm_set1_epi32(Tr::FirstLetter - Tr::DigitCount));
if constexpr (HasAltLetterEnum<Tr>::value) {
const __m128i char_befo_A = _mm_set1_epi32(g_AltLetterOrZero<Tr> - 1);
const __m128i char_past_F = _mm_set1_epi32(g_AltLetterOrZero<Tr> + Base - Tr::DigitCount);
const __m128i alt_mask = _mm_and_si128(_mm_cmpgt_epi32(digits, char_befo_A), _mm_cmplt_epi32(digits, char_past_F));
const __m128i alt_offs = _mm_and_si128(alt_mask, _mm_set1_epi32(g_AltLetterOrZero<Tr> - Tr::DigitCount));
offs = _mm_add_epi32(alt_offs, offs);
mask = _mm_or_si128(mask, alt_mask);
}
const __m128i addend = _mm_add_epi32(offs, _mm_andnot_si128(mask, char_0));
res = _mm_add_epi32(res, muly(_mm_sub_epi32(digits, addend), factor));
factor = muly(factor, _mm_set1_epi32(base4));
idx += 4;
@ -255,7 +302,7 @@ namespace dhandy {
{
res = _mm_add_epi32(res, _mm_srli_si128(res, 8));
res = _mm_add_epi32(res, _mm_srli_si128(res, 4));
const std::array<int, 4> scale {1, base1, base2, base3};
constexpr const std::array<int, 4> scale {1, base1, base2, base3};
return negated_ifn(to_integer_sse<T, C, Base, Tr>(s + idx, l - idx) + _mm_cvtsi128_si32(res) * scale[l - idx], was_negative);
}
}
@ -263,39 +310,57 @@ namespace dhandy {
}
} //namespace implem
template <typename C, C FDigit='0', C FLetter='a', C CPlus='+', C CMinus='-'>
template <typename C, C FDigit='0', C FLetter='a', C CPlus='+', C CMinus='-', C CNull='\0', unsigned int DCount=10>
struct ASCIITranslator {
static const constexpr bool BehavesLikeASCII = true;
typedef C char_type;
static const constexpr C FirstDigit = FDigit;
static const constexpr C FirstLetter = FLetter;
//static const constexpr C AltLetter = FAltLetter;
static const constexpr C Plus = CPlus;
static const constexpr C Minus = CMinus;
static const constexpr C NullChar = CNull;
static const constexpr unsigned int DigitCount = DCount;
static constexpr C to_digit (unsigned int num) {
return (num <= 9 ?
static_cast<C>(num + FirstDigit) :
static_cast<C>(num + FirstLetter - 10)
);
constexpr const C ret[2] = {FirstDigit, FirstLetter - DigitCount};
#if 0
//https://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching
const bool f = num >= DigitCount;
constexpr const unsigned int m = 1;
const unsigned int w = (-f & m);
#else
const auto w = (DigitCount - 1 - num) >> (sizeof(unsigned int) * CHAR_BIT - 1);
#endif
return num + ret[w];
}
static constexpr int from_digit (C dig) {
return (dig < FirstLetter ?
dig - FirstDigit :
dig - FirstLetter + 10
);
//return (dig < FirstLetter ? dig - FirstDigit : dig - FirstLetter + DigitCount);
typedef typename std::make_unsigned<C>::type UC;
constexpr const C ret[2] = {FirstLetter - DigitCount, FirstDigit};
const auto w = static_cast<UC>(dig - FirstLetter) >> (sizeof(UC) * CHAR_BIT - 1);
return dig - ret[w];
}
};
template <typename C>
using ASCIITranslatorUpcase = ASCIITranslator<C, 'A'>;
using ASCIITranslatorUpcase = ASCIITranslator<C, '0', 'A'>;
template <typename I, I In, unsigned int Base=10, typename Tr=ASCIITranslator<char>>
constexpr inline const auto& buildtime_int_to_ary() {
return implem::g_int_to_str<I, In, Base, Tr>;
}
template <typename I, unsigned int Base=10, typename Tr=ASCIITranslator<char>>
constexpr inline auto int_to_ary (I in) {
return implem::IntConversion<std::decay_t<I>, Base, Tr>::to_ary(in);
return implem::IntConversion<std::remove_cvref_t<I>, Base, Tr>::to_ary(in);
}
template <typename R, typename C, unsigned int Base=10, typename Tr=ASCIITranslator<C>>
inline R ary_to_int (const C* beg, const C* end) {
return implem::AryConversion<R, Base, Tr>::from_ary(beg, end);
constexpr inline R ary_to_int (const C* beg, const C* end) {
if (std::is_constant_evaluated())
return implem::AryConversion<R, Base, Tr, true>::from_ary(beg, end);
else
return implem::AryConversion<R, Base, Tr, false>::from_ary(beg, end);
}
#if !defined(INT_CONV_WITHOUT_HELPERS)
@ -304,8 +369,9 @@ namespace dhandy {
return std::string(int_to_ary(num).to_string_view());
}
template <std::size_t S>
std::string operator+ (std::string a, const ReversedSizedArray<char, S>& b) {
template <typename C, std::size_t S>
inline
std::basic_string<C> operator+ (std::basic_string<C> a, const ReversedSizedArray<C, S>& b) {
a.append(b.data(), b.size() - 1);
return a;
}

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -18,7 +18,7 @@
#ifndef idFC25566D624140559C54B39FFFE52F04
#define idFC25566D624140559C54B39FFFE52F04
#include <array>
#include "../variadic_repeat_bt.hpp"
#include <type_traits>
#include <stdexcept>
#if !defined(INT_CONV_WITHOUT_HELPERS)
@ -26,6 +26,7 @@
# include <string>
# include <sstream>
#endif
#include <tuple>
namespace dhandy {
template <typename T, std::size_t S>
@ -33,38 +34,75 @@ namespace dhandy {
static_assert(S > 0, "This container requires size to be at least 1");
static_assert(std::is_trivial<T>::value, "Only use this container with trivial types");
public:
using iterator = typename std::array<T, S>::iterator;
constexpr static const std::size_t capacity = S;
using iterator = T*;
constexpr ReversedSizedArray() = default;
constexpr ReversedSizedArray (const ReversedSizedArray&) = default;
constexpr ReversedSizedArray (ReversedSizedArray&&) = default;
template <typename... Items> constexpr explicit ReversedSizedArray (Items&&... items);
~ReversedSizedArray() = default;
constexpr std::size_t size() const { return S - (m_curr + 1); }
constexpr bool empty() const { return m_curr + 1 == S; }
constexpr const T operator[] (std::size_t idx) const { if (idx >= size()) throw std::out_of_range("Out of bound array access"); return m_data[idx + m_curr + 1]; }
constexpr T& operator[] (std::size_t idx) { if (idx >= size()) throw std::out_of_range("Out of bound array access"); return m_data[idx + m_curr + 1]; }
constexpr void push_front (const T& itm) { if (size() == S) throw std::length_error("ReversedSizedArray is full"); m_data[m_curr--] = itm; }
constexpr const T* data() const { return m_data.data() + m_curr + 1; }
constexpr iterator begin() { return m_data.begin() + m_curr + 1; }
constexpr iterator end() { return m_data.end(); }
constexpr const T& back() const { return *(m_data.data() + S - 1); }
constexpr void push_front (const T& itm) { /*if (size() == S) throw std::length_error("ReversedSizedArray is full");*/ m_data[m_curr--] = itm; }
constexpr const T* data() const { return m_data + m_curr + 1; }
constexpr const T* base_ptr() const { return m_data; }
constexpr iterator begin() { return m_data + m_curr + 1; }
constexpr iterator end() { return m_data + S; }
constexpr const T& back() const { return *(m_data + S - 1); }
template <typename V>
constexpr V to() const { return V(data(), size() - (not empty() and not back() ? 1 : 0)); }
constexpr auto to_tuple() const;
#if !defined(INT_CONV_WITHOUT_HELPERS)
constexpr std::basic_string_view<T> to_string_view() const { return to<std::basic_string_view<T>>(); }
bool operator== (const std::basic_string_view<T>& other) const { return to_string_view() == other; }
bool operator!= (const std::basic_string_view<T>& other) const { return not operator==(other); }
bool operator== (const std::string& other) const { return to_string_view() == other; }
bool operator!= (const std::string& other) const { return not operator==(other); }
bool operator== (const std::basic_string<T>& other) const { return to_string_view() == other; }
bool operator!= (const std::basic_string<T>& other) const { return not operator==(other); }
bool operator== (const T* other) const { return to_string_view() == std::basic_string_view<T>(other); }
bool operator!= (const T* other) const { return not operator==(other); }
std::string to_string() const { return to<std::basic_string<T>>(); }
#endif
private:
std::array<T, S> m_data {};
template <T... ItemsFill, typename... Items>
constexpr explicit ReversedSizedArray (bt::variadic_repeat<T, ItemsFill...>, Items&&... items);
T m_data[S];
std::size_t m_curr {S - 1};
};
namespace implem {
template <typename T, std::size_t S, std::size_t... Indices>
constexpr auto elements_or_empty_to_tuple (const T (&elems)[S], std::size_t from_idx, std::index_sequence<Indices...>) {
return std::make_tuple((from_idx + Indices < S ? elems[from_idx + Indices] : T{})...);
}
} //namespace implem
template <typename T, std::size_t S>
template <typename... Items>
inline constexpr ReversedSizedArray<T, S>::ReversedSizedArray (Items&&... items) :
ReversedSizedArray<T, S>(
bt::make_variadic_repeat<S - sizeof...(Items), T>{},
std::forward<Items>(items)...
)
{ }
template <typename T, std::size_t S>
template <T... ItemsFill, typename... Items>
constexpr ReversedSizedArray<T, S>::ReversedSizedArray (bt::variadic_repeat<T, ItemsFill...>, Items&&... items) :
m_data{ItemsFill..., std::forward<Items>(items)...},
m_curr(S - 1 - sizeof...(Items))
{
static_assert(sizeof...(ItemsFill) + sizeof...(Items) == S, "Wrong number of input elements");
}
#if !defined(INT_CONV_WITHOUT_HELPERS)
template <typename T, std::size_t S>
inline
@ -72,14 +110,12 @@ namespace dhandy {
stream << arr.to_string_view();
return stream;
}
#endif
template <typename T, std::size_t S>
inline
std::basic_string<T> operator+ (std::basic_string<T>&& a, const ReversedSizedArray<T, S>& b) {
a.insert(a.end(), b.begin(), b.end());
return a;
constexpr auto ReversedSizedArray<T, S>::to_tuple() const {
return implem::elements_or_empty_to_tuple(m_data, m_curr + 1, std::make_index_sequence<S>{});
}
#endif
} //namespace dhandy
#endif

View file

@ -1,64 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
namespace duckmem {
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K, typename V, typename Hasher>
ScapegoatMap<K, V, Hasher>::DerivedPair::DerivedPair() {
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K, typename V, typename Hasher>
ScapegoatMap<K, V, Hasher>::DerivedPair::DerivedPair (typename Loki::TypeTraits<key_type>::ParameterType parKey, typename Loki::TypeTraits<value_type>::ParameterType parValue) :
parent_type(parKey, parValue)
{
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K, typename V, typename Hasher>
ScapegoatMap<K, V, Hasher>::DerivedPair::~DerivedPair() {
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
// template <typename K, typename V, typename Hasher>
// bool ScapegoatMap<K, V, Hasher>::DerivedPair::operator< (const DerivedPair& parOther) const {
// const typename Hasher::HashType thisHash = Hasher::ComputeFullHash(this->first);
// const typename Hasher::HashType otherHash = Hasher::ComputeFullHash(parOther->first);
// if (thisHash == otherHash) {
// const bool typeMinor = (this->first < parOther.first);
//
// else
//wrong - this breaks total ordering condition return (thisHash < otherHash);
// }
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K, typename V, typename Hasher>
bool ScapegoatMap<K, V, Hasher>::DerivedPair::operator== (const DerivedPair& parOther) const {
const typename Hasher::HashType thisHash = Hasher::ComputeFullHash(this->first);
const typename Hasher::HashType otherHash = Hasher::ComputeFullHash(parOther->first);
if (thisHash != otherHash)
return false;
else
return (this->first == parOther.first);
}
} //namespace duckmem

View file

@ -1,725 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
namespace duckmem {
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
ScapegoatTree<K>::ScapegoatTree() :
m_root(NULL),
m_count(0),
m_countMax(0),
m_reserved(0),
m_alpha(0.6f)
{
m_alphainvloginv = 1.0f / std::log(1.0f / m_alpha);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
ScapegoatTree<K>::ScapegoatTree (float parAlpha) :
m_root(NULL),
m_count(0),
m_countMax(0),
m_reserved(0),
m_alpha(parAlpha)
{
Assert(parAlpha < 1.0f);
Assert(parAlpha >= 0.5f);
m_alphainvloginv = 1.0f / std::log(1.0f / m_alpha);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
ScapegoatTree<K>::~ScapegoatTree() {
delete_nodes(m_root);
#if defined(DUCK_DEBUG)
m_root = NULL;
m_count = 0xDEADBEEF;
m_countMax = 0xDEADBEEF;
m_reserved = 0xDEADBEEF;
#endif
}
///-------------------------------------------------------------------------
///I can't really find a good optimization for this method, so I'll just
///ignore the hint and rely on the normal insert().
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::iterator ScapegoatTree<K>::insert (const iterator&, const K& parValue) {
std::pair<iterator, bool> retVal = insert(parValue);
return retVal.first;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
std::pair<typename ScapegoatTree<K>::iterator, bool> ScapegoatTree<K>::insert (const K& parKey) {
const size_type depthHint = get_max_balanced_depth(std::max<size_type>(m_reserved, m_count + 1), m_alphainvloginv) + 3;
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "insert(): depthHint = " << depthHint << ", m_count = " << m_count << ", m_countMax = " << m_countMax << ", m_reserved = " << m_reserved << std::endl;
#endif
if (NULL == m_root) {
m_root = get_new_node(parKey);
m_root->left = m_root->right = NULL;
m_root->size = 1;
m_count = 1;
m_countMax = 1;
m_reserved = std::max(m_count, m_reserved);
IteratorOnPtr<NodeType**, NodeType*, false> rootWrapper(&m_root, 1);
return std::pair<iterator, bool>(iterator(rootWrapper, 1, depthHint), true);
}
else {
//Refuse to add a new item if the tree has more items than it
//can count
if (std::numeric_limits<size_type>::max() == m_count or std::numeric_limits<typename NodeType::size_type>::max() == m_root->size) {
AssertNotReached();
return std::pair<iterator, bool>(end(), false);
}
NodeStack stack;
stack.reserve(depthHint);
NodeType* const closestMatch = get_insert_parent(m_root, parKey, stack);
Assert(stack.size() <= depthHint);
if (closestMatch->content == parKey)
return std::pair<iterator, bool>(iterator(stack.begin(), stack.size(), depthHint), false);
Assert(NULL == closestMatch->left or closestMatch->left->content < parKey);
Assert(NULL == closestMatch->right or parKey < closestMatch->right->content);
NodeType* const newNode = get_new_node(parKey);
newNode->left = newNode->right = NULL;
newNode->size = 1;
if (parKey < closestMatch->content) {
Assert(NULL == closestMatch->left);
closestMatch->left = newNode;
}
else {
Assert(NULL == closestMatch->right);
closestMatch->right = newNode;
}
++m_count;
m_countMax = std::max(m_count, m_countMax);
m_reserved = std::max(m_reserved, m_count);
//Update the count of every node
for (auto& node : stack) {
++node->size;
}
//Add the new node to the stack
Assert(stack.capacity() > stack.size());
stack.push_back(newNode);
#if defined(SCAPEGOATTREE_PARANOID)
const size_type totalSize = AssertNodeSize(m_root);
Assert(totalSize == m_count);
Assert(m_root->size == duckcore::checked_numcast<typename NodeType::size_type>(m_count));
#endif
size_type newNodeDepth = stack.size() - 1;
//Rebalance if necessary
if (not is_alpha_height_balanced(newNodeDepth, this->size())) {
#if defined(SCAPEGOATTREE_PARANOID)
Assert(find_max_depth(m_root) == newNodeDepth);
#endif
Assert(get_max_balanced_depth(static_cast<size_type>(m_root->size), m_alphainvloginv) + 1 == newNodeDepth);
std::pair<NodeType*, NodeType*> scapegoatAndParent = find_scapegoat(stack);
AssertRelease(NULL != scapegoatAndParent.first);
NodeType* const newRoot = rebalance(scapegoatAndParent.first, newNodeDepth + 1);
NodeType* const parent = scapegoatAndParent.second;
if (parent == NULL) {
Assert(scapegoatAndParent.first == m_root);
m_root = newRoot;
m_countMax = m_count;
}
else {
Assert(newRoot != parent);
if (parent->left == scapegoatAndParent.first) {
parent->left = newRoot;
}
else {
Assert(parent->right == scapegoatAndParent.first);
parent->right = newRoot;
}
}
#if defined(SCAPEGOATTREE_PARANOID)
AssertNodeSize(m_root);
Assert(find_max_depth(m_root) <= get_max_balanced_depth(static_cast<size_type>(m_root->size), m_alphainvloginv));
#endif
//Rebuild the stack.
//TODO: this is ugly and slow, see if you can find a better way
stack.clear();
get_insert_parent(m_root, parKey, stack);
newNodeDepth = stack.size() - 1;
Assert(is_alpha_height_balanced(newNodeDepth, this->size()));
}
return std::pair<iterator, bool>(iterator(stack.begin(), newNodeDepth + 1, duckmath::log2_fast(m_reserved + 1)), true);
}
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::rebalance (NodeType* parSubtree, size_type parDepthHint) {
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "Rebalancing subtree" << std::endl;
#endif
Assert(NULL != parSubtree);
NodeType* const newRoot = compress_first(parSubtree, parDepthHint);
NodeType* const retVal = compress(newRoot);
return retVal;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeTypePair ScapegoatTree<K>::find_scapegoat (NodeStack& parParents) const {
Assert(not parParents.empty());
const size_type height = parParents.size();
for (size_type z = parParents.size() - 1; z > 0; --z) {
NodeType& currNode = *(parParents[z - 1]);
Assert(height - z > 0);
if (not is_alpha_height_balanced(height - z, static_cast<size_type>(currNode.size))) {
NodeType* parent;
if (z == 1)
parent = NULL;
else
parent = parParents[z - 2];
return NodeTypePair(&currNode, parent);
}
}
AssertNotReached();
__builtin_unreachable();
return NodeTypePair(NULL, NULL);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::get_new_node (const K& parKey) {
return new NodeType(parKey);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
template <typename T>
T* ScapegoatTree<K>::find_closest_match (T* parTree, const K& parKey) {
Assert(NULL != parTree);
//if (parTree->left and parKey <= parTree->left->content)
if (parTree->left and not (parTree->left->content < parKey))
return FindClosestMatch(parTree->left, parKey);
//else if (parTree->right and parKey >= parTree->right->content)
else if (parTree->right and not (parKey < parTree->right->content))
return FindClosestMatch(parTree->right, parKey);
else
return parTree;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::get_insert_parent (NodeType* parTree, const K& parKey, NodeStack& parRewind) {
Assert(NULL != parTree);
NodeType* retVal = parTree;
bool goLeft;
while ((goLeft = (retVal->left and parKey < retVal->content)) or (retVal->right and retVal->content < parKey)) {
parRewind.push_back(retVal);
if (goLeft) {
Assert(NULL != retVal->left);
Assert(parKey < retVal->content);
retVal = retVal->left;
}
else {
Assert(NULL != retVal->right);
Assert(retVal->content < parKey);
retVal = retVal->right;
}
}
Assert(NULL != retVal);
Assert(parRewind.empty() or parRewind.back() != retVal);
parRewind.push_back(retVal);
return retVal;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
void ScapegoatTree<K>::delete_nodes (NodeType* parNode) {
if (parNode) {
delete_nodes(parNode->left);
delete_nodes(parNode->right);
delete parNode;
}
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
bool ScapegoatTree<K>::is_alpha_height_balanced (size_type parHeight, size_type parSize) const {
const float sz = static_cast<float>(parSize);
const float ha = std::floor(std::log(sz) * m_alphainvloginv);
const float height = static_cast<float>(parHeight);
return height <= ha;
}
///-------------------------------------------------------------------------
///Stout/Warren vine to tree.
///This function destroys the links of the given subtree and creates a
///structure that is suitable for compress(). Input is treated as if it
///was a linked list.
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::compress_first (NodeType* parFrom, size_type parDepthHint) {
const size_type vineSize = static_cast<size_type>(parFrom->size);
const size_type iteratorDepth = parDepthHint;
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "compress_first(): vineSize = " << vineSize << ", iteratorDepth = " << iteratorDepth << std::endl;
#endif
iterator itFirstStep(parFrom, iteratorDepth);
struct DummyNode {
DummyNode ( void ) : right(NULL) {}
NodeType* right;
};
class NodeWrapper {
public:
NodeWrapper ( void ) {}
explicit NodeWrapper ( NodeType* parOther ) : m_current(parOther), m_right(&parOther->right) {}
explicit NodeWrapper ( DummyNode* parOther ) : m_current(NULL), m_right(&parOther->right) {}
void Replace ( NodeType* parOther ) { m_current = parOther; m_right = &parOther->right; }
void Replace ( NodeWrapper* parOther ) { m_current = parOther->m_current; m_right = parOther->m_right; }
NodeType*& left ( void ) { Assert(m_current); return m_current->left; }
NodeType*& right ( void ) { Assert(m_right); return *m_right; }
typename NodeType::size_type& size ( void ) { Assert(m_current); return m_current->size; }
NodeType* pointer ( void ) { return m_current; }
private:
NodeType* m_current;
NodeType** m_right;
};
DummyNode pseudorootMem;
NodeWrapper parent(&pseudorootMem);
NodeWrapper current;
NodeWrapper child(&pseudorootMem);
size_type iterationsCount;
if (implem::is_power_of_two(vineSize + 1))
iterationsCount = (1 << (duckmath::log2_fast(vineSize))) - 1;
else
iterationsCount = (vineSize - ((1 << duckmath::log2_fast(vineSize)) - 1));
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "vineSize = " << vineSize << ", iterationsCount = " << iterationsCount << std::endl;
#endif
Assert(iterationsCount < vineSize); //Underflow error?
Assert(iterationsCount > 0);
for (size_type z = 0; z < iterationsCount; ++z) {
current.Replace(itFirstStep.GetPointer());
++itFirstStep;
child.Replace(itFirstStep.GetPointer());
++itFirstStep;
current.left() = NULL;
current.right() = NULL;
current.size() = 1;
parent.right() = child.pointer();
child.left() = current.pointer();
Assert(z * 2 < vineSize);
child.size() = static_cast<typename NodeType::size_type>(vineSize - z * 2);
Assert(child.size() >= 1);
parent.Replace(&child);
}
Assert(iterationsCount * 2 <= vineSize);
for (size_type z = iterationsCount * 2; z < vineSize; ++z) {
child.right() = itFirstStep.GetPointer();
child.Replace(itFirstStep.GetPointer());
++itFirstStep;
child.left() = NULL;
child.size() = static_cast<typename NodeType::size_type>(vineSize - z);
}
child.right() = NULL;
child.size() = (child.left() ? 2 : 1);
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "Original size was " << vineSize << ", root's size is " << pseudorootMem.right->size << std::endl;
#endif
Assert(vineSize == static_cast<size_type>(pseudorootMem.right->size));
#if defined(SCAPEGOATTREE_PARANOID)
AssertNodeSize(pseudorootMem.right);
Assert(find_max_depth(pseudorootMem.right) <= vineSize);
#endif
return pseudorootMem.right;
}
///-------------------------------------------------------------------------
///Stout/Warren vine to tree.
///Performs the second and subsequent steps for compressing.
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::compress (NodeType* parFrom) {
Assert(NULL != parFrom);
//We don't know if the tree is complete, so let's calculate its depth
//rounded up to the nearest complete tree
const size_type treeSize = static_cast<size_type>(parFrom->size);
const size_type m = duckmath::log2_fast(1 + treeSize);
const size_type treeHeight = duckmath::log2_fast(treeSize + (1 << m));
#if defined(SCAPEGOATTREE_PARANOID)
size_type maxDepthInTree = find_max_depth(parFrom);
{
//We know step 0 of compression has already been done, so on with
//the spine size at step 1 (the one we're willing to do)
const size_type vineSize = (1 << (treeHeight - 1)) - 1;
size_type count = 0;
NodeType* currNode = parFrom;
do {
++count;
currNode = currNode->right;
} while (currNode);
const size_type countedNodes = ((count + 1) bitand ~1) - 1;
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "treeSize = " << treeSize << ", vineSize = " << vineSize << ", treeHeight = " << treeHeight << ", manually counted " << countedNodes << " nodes (" << count << ")\n";
#endif
Assert(implem::is_power_of_two(countedNodes + 1));
Assert(vineSize == countedNodes);
}
#endif
NodeType* retVal = parFrom;
Assert(treeHeight >= 2);
for (size_type k = 1; k < treeHeight - 1; ++k) {
#if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "compress() step " << k << std::endl;
#endif
//The rebalanced tree takes treeHeight-1 steps. One step has been done
//already, so we perform the remaining treeHeight-2 steps.
NodeType* scanner;
NodeType* child = retVal;
retVal = child->right;
Assert(NULL != retVal);
const size_type spineSize = (1 << (treeHeight - k - 1)) - 1;
Assert(spineSize > 0);
for (size_type s = 0; s < spineSize; ++s) {
scanner = child->right;
Assert(NULL != scanner);
child->right = scanner->left;
scanner->left = child;
const typename NodeType::size_type leftBranchSize = (child->right ? child->right->size : 0);
child->size -= scanner->size - leftBranchSize;
scanner->size += child->size - leftBranchSize;
if (s + 1 < spineSize) {
child = scanner->right;
Assert(NULL != child);
scanner->right = child->right;
}
#if defined(SCAPEGOATTREE_VERBOSE)
const size_type subtreeSize = (1 << (k + 1)) - 1;
std::cout << "k=" << k << " - Scanner's size updated to " << scanner->size << ", calculated subtreeSize = " << subtreeSize << std::endl;
#endif
}
Assert(NULL != scanner);
Assert(NULL != retVal);
Assert(treeSize == static_cast<size_type>(retVal->size));
#if defined(SCAPEGOATTREE_PARANOID)
AssertNodeSize(retVal);
{
const size_type newDepth = find_max_depth(retVal);
Assert(newDepth <= maxDepthInTree);
maxDepthInTree = newDepth;
}
#endif
}
Assert(static_cast<size_type>(retVal->size) == treeSize);
return retVal;
}
#if defined(SCAPEGOATTREE_PARANOID)
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::size_type ScapegoatTree<K>::assert_node_size (const NodeType* parSubtree) {
Assert(parSubtree);
typename NodeType::size_type localSize = 1;
if (parSubtree->left) {
localSize += AssertNodeSize(parSubtree->left);
}
if (parSubtree->right) {
localSize += AssertNodeSize(parSubtree->right);
}
Assert(parSubtree->size == localSize);
return localSize;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::size_type ScapegoatTree<K>::find_max_depth_rec (const NodeType* parSubtree) {
Assert(parSubtree);
typename NodeType::size_type depthLeft = 0;
typename NodeType::size_type depthRight = 0;
if (parSubtree->left) {
depthLeft = FindMaxDepth_rec(parSubtree->left);
}
if (parSubtree->right) {
depthRight = FindMaxDepth_rec(parSubtree->right);
}
return 1 + std::max(depthLeft, depthRight);
}
#endif
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::size_type ScapegoatTree<K>::get_max_balanced_depth (size_type parSize, float parAlphaInvLogInv) {
const float ha = std::log(static_cast<float>(parSize)) * parAlphaInvLogInv;
return static_cast<size_type>(ha);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::iterator ScapegoatTree<K>::begin() {
if (NULL == m_root)
return iterator();
const size_type depthHint = get_tree_min_depth_ib(m_reserved, m_alphainvloginv) + 1;
#if defined(SCAPEGOATTREE_PARANOID)
Assert(is_alpha_height_balanced(find_max_depth(m_root), static_cast<size_type>(m_root->size)));
Assert(find_max_depth(m_root) + 1 <= depthHint);
#endif
return iterator(m_root, depthHint + 1);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::const_iterator ScapegoatTree<K>::begin() const {
if (NULL == m_root)
return iterator();
const size_type depthHint = get_tree_min_depth_ib(m_count, m_alphainvloginv) + 1;
#if defined(SCAPEGOATTREE_PARANOID)
Assert(is_alpha_height_balanced(find_max_depth(m_root), static_cast<size_type>(m_root->size)));
Assert(find_max_depth(m_root) + 1 <= depthHint);
#endif
return const_iterator(m_root, depthHint + 1);
}
///-------------------------------------------------------------------------
///Get min tree depth if balanced
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::size_type ScapegoatTree<K>::get_tree_min_depth_ib (size_type parSize, float parAlphaInvLogInv) {
const float sz = static_cast<float>(parSize);
const size_type roundedDownDepthBase2 = duckmath::log2_fast(parSize + 1);
const float nodesAtLastLevel = (roundedDownDepthBase2 == 0 ? 0 : static_cast<float>(1 << roundedDownDepthBase2) - 1.0f);
const float retVal = std::log(sz + nodesAtLastLevel) * parAlphaInvLogInv;
return static_cast<size_type>(retVal);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
void ScapegoatTree<K>::clear() {
delete_nodes(m_root);
m_count = 0;
m_countMax = 0;
m_root = NULL;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::find_ifp (NodeType* parTree, const K& parKey) {
while (parTree) {
if (parKey < parTree->content)
parTree = parTree->left;
else if (parTree->content < parKey)
parTree = parTree->right;
else
break;
}
return parTree;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::find_parent_ifp (NodeType* parTree, const NodeType* parSearchNodeAddr) {
if (parTree == parSearchNodeAddr)
return NULL;
NodeType* parent = parTree;
while (parTree and (parTree->left != parSearchNodeAddr and parTree->right != parSearchNodeAddr)) {
if (parSearchNodeAddr->content < parTree->content)
parTree = parTree->left;
else if (parTree->content < parSearchNodeAddr->content)
parTree = parTree->right;
else
break;
parent = parTree;
}
return parent;
}
///-------------------------------------------------------------------------
///Set parSuccessor to true to get the in-order successor, or false to
///get the in-order predecessor.
///-------------------------------------------------------------------------
template <typename K>
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::detach_bottom_node (NodeType* parTree, bool parSuccessor) {
AssertRelease(NULL != parTree);
AssertRelease(NULL != parTree->left and NULL != parTree->right);
if (parSuccessor) {
NodeType* inorderSuccessor = parTree->right;
NodeType* successorsParent = parTree;
while (NULL != inorderSuccessor->left) {
successorsParent = inorderSuccessor;
inorderSuccessor = inorderSuccessor->left;
}
Assert(inorderSuccessor == successorsParent->left and inorderSuccessor != successorsParent->right);
Assert(NULL == inorderSuccessor->left);
Assert(NULL == inorderSuccessor->right or inorderSuccessor->right->content < successorsParent->content);
successorsParent->left = inorderSuccessor->right;
Assert(inorderSuccessor);
return inorderSuccessor;
}
else {
NodeType* inorderPredecessor = parTree->left;
NodeType* predecessorsParent = parTree;
while (NULL != inorderPredecessor->right) {
predecessorsParent = inorderPredecessor;
inorderPredecessor = inorderPredecessor->right;
}
Assert(inorderPredecessor == predecessorsParent->right and inorderPredecessor != predecessorsParent->left);
Assert(NULL == inorderPredecessor->right);
Assert(NULL == inorderPredecessor->left or predecessorsParent->content < inorderPredecessor->left->content);
predecessorsParent->right = inorderPredecessor->left;
Assert(inorderPredecessor);
return inorderPredecessor;
}
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
bool ScapegoatTree<K>::include (const K& parSearch) const {
const NodeType* const found = find_ifp(m_root, parSearch);
Assert(not found or not (parSearch < found->content or found->content < parSearch));
return static_cast<bool>(NULL != found);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
void ScapegoatTree<K>::rebalance_after_deletion_ifn() {
const float sz = static_cast<float>(m_count);
const float m = static_cast<float>(m_countMax);
if (sz < m_alpha * m) {
const size_type sizeHint = static_cast<size_type>(std::ceil(std::log(sz) * m_alphainvloginv)) + 1;
rebalance(m_root, sizeHint);
m_countMax = m_count;
}
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
void ScapegoatTree<K>::erase (iterator parItem) {
NodeType* const dele = parItem.GetPointer();
AssertRelease(NULL != dele);
Assert(m_count > 0);
NodeType* parent;
if (dele == m_root)
parent = m_root;
else
parent = find_parent_ifp(m_root, dele);
Assert(NULL != parent);
if (parent) {
Assert(dele == parent->left or dele == parent->right or dele == parent);
NodeType*& parentChildRef = (dele == m_root ? m_root : (dele == parent->left ? parent->left : parent->right));
if (NULL == dele->left and NULL == dele->right) {
parentChildRef = NULL;
}
else if (NULL == dele->left xor NULL == dele->right) {
parentChildRef = (dele->left ? dele->left : dele->right);
}
else {
NodeType* const inorderSuccessor = detach_bottom_node(dele, true);
parentChildRef = inorderSuccessor;
inorderSuccessor->left = dele->left;
inorderSuccessor->right = dele->right;
}
Assert(NULL == parent->left or parent->left->content < parent->content);
Assert(NULL == parent->right or parent->content < parent->right->content);
}
--m_count;
delete dele;
rebalance_after_deletion_ifn();
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
inline typename ScapegoatTree<K>::iterator ScapegoatTree<K>::find (const K& parSearch) {
NodeStack stack;
const size_type depthHint = get_max_balanced_depth(std::max<size_type>(m_reserved, m_count + 1), m_alphainvloginv) + 3;
stack.reserve(depthHint);
NodeType* const closestMatch = get_insert_parent(m_root, parSearch, stack);
Assert(stack.size() <= depthHint);
if (closestMatch->content == parSearch)
return iterator(stack.begin(), stack.size(), depthHint);
else
return this->end();
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename K>
inline typename ScapegoatTree<K>::const_iterator ScapegoatTree<K>::find (const K& parSearch) const {
return const_cast<ScapegoatTree<K>*>(this)->find(parSearch);
}
// ///-------------------------------------------------------------------------
// ///-------------------------------------------------------------------------
// template <typename K>
// void ScapegoatTree<K>::erase (iterator parFrom, iterator parLast) {
// }
//
// ///-------------------------------------------------------------------------
// ///-------------------------------------------------------------------------
// template <typename K>
// typename ScapegoatTree<K>::size_type ScapegoatTree<K>::erase (typename Loki::TypeTraits<value_type>::ParameterType parKey) {
// }
} //namespace duckmem

View file

@ -1,258 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
namespace duckmem {
namespace Implem {
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename P>
bool TreeIterator_base<P>::Exhausted() const {
return m_stack.empty();
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename P>
TreeIterator_base<P>::TreeIterator_base (const TreeIterator_base& parOther) :
m_stack()
{
m_stack.reserve(parOther.m_stack.capacity());
m_stack = parOther.m_stack;
Assert(m_stack.capacity() == parOther.m_stack.capacity());
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename P>
template <typename P1>
TreeIterator_base<P>::TreeIterator_base (const TreeIterator_base<P1>& parOther) {
typename TreeIterator_base<P1>::StackType otherStackCopy(parOther.m_stack);
std::vector<P> localCopy;
localCopy.reserve(parOther.m_stack.size());
while (not otherStackCopy.empty()) {
P convertedItem = otherStackCopy.back();
localCopy.push_back(convertedItem);
otherStackCopy.pop_back();
}
m_stack.reserve(parOther.m_stack.capacity());
for (typename std::vector<P>::reverse_iterator itRev = localCopy.rbegin(), itRevEnd = localCopy.rend(); itRev != itRevEnd; ++itRev) {
Assert(m_stack.capacity() > m_stack.size());
m_stack.push_back(*itRev);
}
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::reference TreeIterator_const_layer<T, N, false>::operator* () {
AssertRelease(not this->Exhausted());
return this->m_stack.back()->content;
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::const_reference TreeIterator_const_layer<T, N, false>::operator* () const {
AssertRelease(not this->Exhausted());
return this->m_stack.back()->content;
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::pointer TreeIterator_const_layer<T, N, false>::operator-> () {
AssertRelease(not this->Exhausted());
return &this->m_stack.back()->content;
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::const_pointer TreeIterator_const_layer<T, N, false>::operator-> () const {
AssertRelease(not this->Exhausted());
return &this->m_stack.back()->content;
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
N* TreeIterator_const_layer<T, N, false>::GetPointer() {
AssertRelease(not this->Exhausted());
return this->m_stack.back();
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
const N* TreeIterator_const_layer<T, N, false>::GetPointer() const {
AssertRelease(not this->Exhausted());
return this->m_stack.back();
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
typename TreeIterator_const_layer<T, N, true>::const_reference TreeIterator_const_layer<T, N, true>::operator* () const {
AssertRelease(not this->Exhausted());
return this->m_stack.back()->content;
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
typename TreeIterator_const_layer<T, N, true>::const_pointer TreeIterator_const_layer<T, N, true>::operator-> () const {
AssertRelease(not this->Exhausted());
return &this->m_stack.back()->content;
}
///---------------------------------------------------------------------
///---------------------------------------------------------------------
template <typename T, typename N>
const N* TreeIterator_const_layer<T, N, true>::GetPointer() const {
AssertRelease(not this->Exhausted());
return this->m_stack.back();
}
} //namespace Implem
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
TreeIterator<T, N>::TreeIterator() {
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
TreeIterator<T, N>::TreeIterator (const TreeIterator& parOther) :
parent_type(parOther)
{
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
template <typename T1>
TreeIterator<T, N>::TreeIterator (const TreeIterator<T1, N>& parOther) :
parent_type(parOther)
{
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
template <typename S>
TreeIterator<T, N>::TreeIterator (S parCopyStackBottomUp, size_type parStackLen, size_type parMaxDepthHint) {
AssertRelease(parStackLen > 0);
this->m_stack.reserve(std::max(parStackLen, parMaxDepthHint));
typename StackType::value_type prevNode = *parCopyStackBottomUp;
++parCopyStackBottomUp;
this->m_stack.push_back(prevNode);
for (size_type z = 1; z < parStackLen; ++z) {
typename StackType::value_type currNode = *parCopyStackBottomUp;
if (prevNode->left == currNode) {
Assert(this->m_stack.capacity() > this->m_stack.size());
this->m_stack.push_back(currNode);
}
else {
//If you get this assertion make sure the iterator you are
//passing in is reversed (ie: from leaf to root)
AssertRelease(currNode == prevNode->right);
this->m_stack.pop_back();
this->m_stack.push_back(currNode);
}
prevNode = currNode;
++parCopyStackBottomUp;
}
Assert(not this->Exhausted());
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
TreeIterator<T, N>::TreeIterator (NodeTypePointer parRoot, size_type parMaxDepthHint) {
if (parMaxDepthHint > 0)
this->m_stack.reserve(parMaxDepthHint);
RecurseLeft(parRoot);
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
TreeIterator<T, N>::~TreeIterator() {
}
///-------------------------------------------------------------------------
///Post-increment
///-------------------------------------------------------------------------
template <typename T, typename N>
TreeIterator<T, N> TreeIterator<T, N>::operator++ (int) {
AssertRelease(not this->Exhausted());
TreeIterator<T, N> retVal = *this;
++(*this);
return retVal;
}
///-------------------------------------------------------------------------
///Pre-increment
///-------------------------------------------------------------------------
template <typename T, typename N>
TreeIterator<T, N>& TreeIterator<T, N>::operator++() {
AssertRelease(not this->Exhausted());
NodeTypePointer currNode = this->m_stack.back();
#if defined(ASSERTIONSENABLED)
const size_type stackCapacity = this->m_stack.capacity();
#endif
AssertRelease(not this->m_stack.empty());
this->m_stack.pop_back();
#if defined(ASSERTIONSENABLED)
//It shouldn't normally happen, but it's just to make sure
Assert(stackCapacity == this->m_stack.capacity());
#endif
RecurseLeft(currNode->right);
return *this;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
const TreeIterator<T, N>& TreeIterator<T, N>::operator= (const TreeIterator& parOther) {
this->m_stack = parOther.m_stack;
Assert(this->m_stack.capacity() >= parOther.m_stack.capacity());
return *this;
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
bool TreeIterator<T, N>::operator== (const TreeIterator& parOther) const {
return this->m_stack.size() == parOther.m_stack.size() and (this->m_stack.empty() or parOther.m_stack.back() == this->m_stack.back());
}
///-------------------------------------------------------------------------
///-------------------------------------------------------------------------
template <typename T, typename N>
void TreeIterator<T, N>::RecurseLeft (NodeTypePointer parFrom) {
NodeTypePointer currNode = parFrom;
while (NULL != currNode) {
Assert(this->m_stack.capacity() > this->m_stack.size());
this->m_stack.push_back(currNode);
currNode = currNode->left;
}
}
} //namespace duckmem

View file

@ -5,12 +5,12 @@
#if !defined(INFIX_ITERATOR_H_)
#define INFIX_ITERATOR_H_
#include <ostream>
#include <iterator>
namespace dhandy {
template <class T,
class charT=char,
class traits=std::char_traits<charT> >
class infix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
class infix_ostream_iterator
{
std::basic_ostream<charT,traits> *os;
charT const* delimiter;
@ -19,6 +19,13 @@ public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
infix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0), first_elem(true)
{}
@ -45,4 +52,5 @@ public:
return *this;
}
};
} //namespace dhandy
#endif

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -22,36 +22,96 @@
#include <type_traits>
#include <string>
#include <string_view>
#include <array>
#define DHANDY_INTCONV_USE_STDSTRING
namespace dhandy {
namespace implem {
template <typename T, typename F>
template <typename T, typename F, typename Tr, bool FromInt=std::is_integral_v<F>>
struct IntConv;
template <typename F>
struct IntConv<std::enable_if_t<std::is_integral_v<F>, std::string>, F> {
static std::string conv (const F& in) {
auto retval = dhandy::int_to_ary(in);
return std::string(retval.begin(), retval.end() - 1);
template <typename Tr>
using IntConvString = std::basic_string<typename Tr::char_type>;
template <typename Tr>
using IntConvStringView = std::basic_string_view<typename Tr::char_type>;
template <typename F, typename Tr>
struct IntConv<IntConvString<Tr>, F, Tr, true> {
static IntConvString<Tr> conv (const F& in) {
auto retval = dhandy::int_to_ary<F, 10, Tr>(in);
return IntConvString<Tr>{retval.begin(), retval.end() - 1};
}
};
template <typename T>
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, std::string>> {
static T conv (const std::string& in) {
return dhandy::ary_to_int<T>(in.data(), in.data() + in.size());
#if defined(DHANDY_INTCONV_USE_STDSTRING)
template <typename F, typename C>
struct IntConv<IntConvString<ASCIITranslator<C>>, F, ASCIITranslator<C>, true> {
static IntConvString<ASCIITranslator<C>> conv (const F& in) {
return std::to_string(in);
}
};
template <typename T>
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, std::string_view>> {
static T conv (const std::string_view& in) {
return dhandy::ary_to_int<T>(in.data(), in.data() + in.size());
#endif
template <typename F, typename Tr>
struct IntConv<IntConvStringView<Tr>, F, Tr, true> {
consteval static IntConvStringView<Tr> conv (const F& in) {
return dhandy::int_to_ary<F, 10, Tr>(in).to_string_view();
}
};
template <typename F, typename Tr, typename C, std::size_t N>
struct IntConv<std::array<C, N>, F, Tr, true> {
private:
template <typename... Args, std::size_t... Indices>
constexpr static std::array<C, N> to_array (const std::tuple<Args...>& vals, std::index_sequence<Indices...>) {
return std::array<C, N>{std::get<Indices>(vals)...};
}
public:
constexpr static std::array<C, N> conv (const F& in) {
return to_array(
dhandy::int_to_ary<F, 10, Tr>(in).to_tuple(),
std::make_index_sequence<
std::min(decltype(dhandy::int_to_ary<F, 10, Tr>(in))::capacity, N)
>{}
);
}
};
template <typename T, typename Tr>
struct IntConv<T, IntConvString<Tr>, Tr, false> {
constexpr static T conv (const IntConvString<Tr>& in) {
return dhandy::ary_to_int<T, char, 10, Tr>(
in.data(),
in.data() + in.size()
);
}
};
template <typename T, typename Tr>
struct IntConv<T, IntConvStringView<Tr>, Tr, false> {
constexpr static T conv (const IntConvStringView<Tr>& in) {
return dhandy::ary_to_int<T, char, 10, Tr>(
in.data(),
in.data() + in.size()
);
}
};
template <typename T, typename F, F In, typename Tr, bool FromInt>
struct IntConv<T, std::integral_constant<F, In>, Tr, FromInt> {
constexpr static T conv (const std::integral_constant<F, In>&) {
return dhandy::buildtime_int_to_ary<F, In, 10, Tr>().to_string_view();
}
};
} //namespace implem
template <typename To, typename From>
inline To int_conv (const From& from) {
return implem::IntConv<To, From>::conv(from);
template <typename To, typename From, bool AllCaps=false>
constexpr inline To int_conv (const From& from, std::integral_constant<bool, AllCaps> = std::integral_constant<bool, AllCaps>{}) {
if constexpr (AllCaps)
return implem::IntConv<To, From, ASCIITranslatorUpcase<char>>::conv(from);
else
return implem::IntConv<To, From, ASCIITranslator<char>>::conv(from);
}
template <typename From>
inline auto int_conv_raw (const From& from) {
return int_to_ary<From, 10, ASCIITranslator<char>>(from);
}
} //namespace dhandy

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,76 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id28695193476D4A9499151FC175A49196
#define id28695193476D4A9499151FC175A49196
#include <cstdint>
#if defined(__linux)
# include <strings.h>
#endif
namespace duckmath {
namespace implem {
#if !defined(__linux)
[[gnu::pure]]
inline uint_fast32_t LowestBitSet ( uint_fast32_t x ) pure_function;
//Precomputed lookup table
const constexpr uint_fast32_t g_multiplyDeBruijnBitPosition[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
///---------------------------------------------------------------------
///Thanks to: http://bits.stephan-brumme.com/lowestBitSet.html
///---------------------------------------------------------------------
[[gnu::pure]]
inline uint_fast32_t LowestBitSet (uint_fast32_t x) {
//Leave only lowest bit
x &= -i32(x);
//DeBruijn constant
x *= 0x077CB531;
//Get upper 5 bits
x >>= 27;
//Convert to actual position
return g_multiplyDeBruijnBitPosition[x];
}
#endif
[[gnu::pure]]
inline uint32_t GetHighestBitOnly (uint32_t parIn) {
parIn |= (parIn >> 1);
parIn |= (parIn >> 2);
parIn |= (parIn >> 4);
parIn |= (parIn >> 8);
parIn |= (parIn >> 16);
return parIn - (parIn >> 1);
}
} //namespace implem
uint_fast32_t log2_fast (uint_fast32_t parX) {
const uint_fast32_t highestPow2 = implem::GetHighestBitOnly(parX);
#if defined(__linux)
const uint_fast32_t retVal = ffs(highestPow2) - 1;
#else
const uint_fast32_t retVal = LowestBitSet(highestPow2);
#endif
return retVal;
}
} //namespace duckmath
#endif

View file

@ -0,0 +1,194 @@
/* Copyright 2016-2025 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id83CE9FAB90684250B98EA584C548E13F
#define id83CE9FAB90684250B98EA584C548E13F
#include "bitfield_pack.hpp"
#include <cstdint>
#include <utility>
#include <climits>
namespace dhandy {
namespace implem {
//This monster expression is just the one-liner version of this
//implementation of log2:
//unsigned int v; // 32-bit value to find the log2 of
//register unsigned int r; // result of log2(v) will go here
//register unsigned int shift;
//
//r = (v > 0xFFFF) << 4; v >>= r;
//shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
//shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
//shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
// r |= (v >> 1);
//see https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog for
//an explanation of that.
//This is a shorter version of it but it only works if the input is a power
//of 2:
//(((((NUM&0xAAAAAAAA)!=0)|((NUM&0xFFFF0000)!=0)<<4)|((NUM&0xFF00FF00)!=0)<<
//3)|((NUM&0xF0F0F0F0)!=0)<<2)|((NUM&0xCCCCCCCC)!=0)<<1
//Source for that is also available at the page linked above.
template <std::uint32_t NUM> const constexpr std::size_t
pointer_unused_bit_count =
((((((NUM > 0xFFFF) << 4) | (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) <<
3)) | ((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) <<
4)) > 0xFF) << 3)) > 0xF) << 2)) | (((((NUM >> ((NUM > 0xFFFF) << 4)) >>
(((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) >> ((((NUM >> ((NUM >
0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF)
<< 2)) > 0x3) << 1)) | (((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> (
(NUM > 0xFFFF) << 4)) > 0xFF) << 3)) >> ((((NUM >> ((NUM > 0xFFFF) << 4)
) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) << 2)) >> ((
(((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << 4)) >
0xFF) << 3)) >> ((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM >
0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) << 2)) > 0x3) << 1)) >> 1))
;
template <std::size_t... S>
BitfieldPack<
std::uintptr_t,
sizeof(std::uintptr_t) * CHAR_BIT - sizeof...(S), (S+1)/(S+1)...
>
guess_bitfield_type (std::index_sequence<S...>);
template <typename T>
using BaseBitfieldPackForPackedPointer = decltype(
implem::guess_bitfield_type(
std::make_index_sequence<implem::pointer_unused_bit_count<alignof(T)>>()
)
);
} //namespace implem
template <typename T>
class PackedPointer : private implem::BaseBitfieldPackForPackedPointer<T> {
static_assert(sizeof(T*) == sizeof(std::uintptr_t), "Mismatching int/pointer size");
typedef implem::BaseBitfieldPackForPackedPointer<T> parent_type;
public:
static const constexpr std::size_t FlagsCount = parent_type::TotalEntries - 1;
PackedPointer();
PackedPointer (T* ptr);
~PackedPointer() = default;
operator T*() const;
operator bool() const;
template <std::size_t Idx> bool flag () const;
template <std::size_t Idx> void set_flag (bool v);
PackedPointer& operator= (T* ptr);
T* operator->();
const T* operator->() const;
T& operator*();
const T& operator*() const;
bool operator== (const PackedPointer& other) const;
bool operator== (T* other) const;
bool operator!= (const PackedPointer& other) const;
bool operator!= (T* other) const;
private:
//static const constexpr uintptr_t PtrMask = static_cast<uintptr_t>(-1) << FlagsCount;
};
template <typename T> const constexpr std::size_t PackedPointer<T>::FlagsCount;
//template <typename T> const constexpr std::uintptr_t PackedPointer<T>::PtrMask;
template <typename T>
PackedPointer<T>::PackedPointer() :
PackedPointer(nullptr)
{
}
template <typename T>
PackedPointer<T>::PackedPointer (T* ptr) :
parent_type(0)
{
(*this) = ptr;
}
template <typename T>
PackedPointer<T>::operator T*() const {
return reinterpret_cast<T*>(this->get(0) << FlagsCount);
}
template <typename T>
PackedPointer<T>::operator bool() const {
return static_cast<T*>(*this) != nullptr;
}
template <typename T>
template <std::size_t Idx>
bool PackedPointer<T>::flag() const {
static_assert(Idx < FlagsCount, "Index out of range");
return static_cast<bool>(this->get(Idx + 1));
}
template <typename T>
template <std::size_t Idx>
void PackedPointer<T>::set_flag (bool v) {
static_assert(Idx < FlagsCount, "Index out of range");
this->set(Idx + 1, (v ? 1 : 0));
}
template <typename T>
PackedPointer<T>& PackedPointer<T>::operator= (T* ptr) {
this->set(0, reinterpret_cast<std::uintptr_t>(ptr) >> FlagsCount);
return *this;
}
template <typename T>
T* PackedPointer<T>::operator->() {
return static_cast<T*>(*this);
}
template <typename T>
const T* PackedPointer<T>::operator->() const {
return static_cast<T*>(*this);
}
template <typename T>
T& PackedPointer<T>::operator*() {
return *static_cast<T*>(*this);
}
template <typename T>
const T& PackedPointer<T>::operator*() const {
return *static_cast<T*>(*this);
}
template <typename T>
bool PackedPointer<T>::operator== (const PackedPointer& other) const {
return this == &other or static_cast<T*>(*this) == static_cast<T*>(other);
}
template <typename T>
bool PackedPointer<T>::operator== (T* other) const {
return static_cast<T*>(*this) == other;
}
template <typename T>
bool PackedPointer<T>::operator!= (const PackedPointer& other) const {
return not this->operator==(other);
}
template <typename T>
bool PackedPointer<T>::operator!= (T* other) const {
return not this->operator==(other);
}
} //namepace dhandy
#endif

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -1,51 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef idDD2D1A57ABEB4BEEA0F7E46C347D1637
#define idDD2D1A57ABEB4BEEA0F7E46C347D1637
#include "scapegoat_tree.hpp"
namespace duckmem {
template <typename K, typename V, typename Hasher>
class ScapegoatMap {
public:
typedef K key_type;
typedef V value_type;
ScapegoatMap ( void );
~ScapegoatMap ( void );
private:
class DerivedPair : public std::pair<key_type, value_type> {
typedef std::pair<key_type, value_type> parent_type;
public:
DerivedPair ( void );
DerivedPair ( typename Loki::TypeTraits<key_type>::ParameterType parKey, typename Loki::TypeTraits<value_type>::ParameterType parValue );
~DerivedPair ( void );
bool operator< ( const DerivedPair& parOther ) const;
bool operator== ( const DerivedPair& parOther ) const;
};
ScapegoatTree<DerivedPair> m_tree;
};
} //namespace duckmem
#include "implem/scapegoat_map.inl"
#endif

View file

@ -1,163 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id79CEDB2530B54204A6BEDCBE0B767EA1
#define id79CEDB2530B54204A6BEDCBE0B767EA1
#include "tree_iterator.hpp"
#include "implem/IteratorOnPtr.hpp"
#include "log2_fast.hpp"
#include <limits>
#include <utility>
#include <cmath>
#include <cassert>
#include <cstdint>
//#define SCAPEGOATTREE_VERBOSE
//#define SCAPEGOATTREE_PARANOID
#define SCAPEGOATTREE_DYNAMIC_SIZE_TYPE
#if defined(DUCK_FINAL)
# if defined(SCAPEGOATTREE_VERBOSE)
# undef(SCAPEGOATTREE_VERBOSE)
# endif
#endif
#if !defined(ASSERTIONSENABLED)
# if defined(SCAPEGOATTREE_PARANOID)
# undef(SCAPEGOATTREE_PARANOID)
# endif
#endif
namespace duckmem {
using dhandy::IteratorOnPtr;
namespace implem {
[[gnu::pure]]
inline bool is_power_of_two (unsigned int parValue) {
return (parValue != 0 and (parValue bitand (~parValue + 1)) == parValue);
}
} //namespace implem
//TODO: implement or remove
class SmallObject {
public:
protected:
SmallObject ( void )=default;
~SmallObject ( void ) noexcept =default;
private:
};
template <typename K>
class ScapegoatTree {
public:
typedef K value_type;
typedef size_t size_type;
private:
template <typename SizeType>
struct TreeNodeStruct : public SmallObject {
typedef SizeType size_type;
TreeNodeStruct ( void );
TreeNodeStruct ( const K& parContent ) : content(parContent) {}
K content;
TreeNodeStruct* left;
TreeNodeStruct* right;
size_type size;
};
#if defined(SCAPEGOATTREE_DYNAMIC_SIZE_TYPE)
typedef typename std::conditional<sizeof(TreeNodeStruct<size_type>) == sizeof(TreeNodeStruct<uint32_t>), size_type, uint32_t>::type TreeNodeSizeType;
typedef TreeNodeStruct<TreeNodeSizeType> TreeNode;
#else
typedef TreeNodeStruct<size_type> TreeNode;
#endif
static_assert(sizeof(typename TreeNode::size_type) <= sizeof(size_type), "Mismatching size_type size");
typedef TreeNode NodeType;
typedef std::vector<NodeType*> NodeStack;
typedef std::pair<NodeType*, NodeType*> NodeTypePair;
public:
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type* const_pointer;
typedef const value_type& const_reference;
typedef duckmem::TreeIterator<value_type, NodeType> iterator;
typedef duckmem::TreeIterator<const value_type, NodeType> const_iterator;
ScapegoatTree ( void );
explicit ScapegoatTree ( float parAlpha );
~ScapegoatTree ( void );
float get_alpha ( void ) const { return m_alpha; }
bool include ( const K& parSearch ) const;
std::pair<iterator, bool> insert ( const K& parKey );
iterator insert ( const iterator&, const K& parValue );
bool empty ( void ) const { return m_count == 0; }
size_type size ( void ) const { return m_count; }
void reserve ( size_type parSize ) { m_reserved = std::max(parSize, m_count); }
size_type capacity ( void ) const { return m_reserved; }
void clear ( void );
void erase ( iterator parItem );
void erase ( iterator parFrom, iterator parLast );
size_type erase ( const value_type& parKey );
iterator find ( const K& parSearch );
const_iterator find ( const K& parSearch ) const;
iterator begin ( void );
const_iterator begin ( void ) const;
iterator end ( void ) { return iterator(); }
const_iterator end ( void ) const { return const_iterator(); }
private:
template <typename T>
static T* find_closest_match ( T* parTree, const K& parKey );
static NodeType* get_insert_parent ( NodeType* parTree, const K& parKey, NodeStack& parRewind );
static NodeType* find_ifp ( NodeType* parTree, const K& parKey );
static NodeType* find_parent_ifp ( NodeType* parTree, const NodeType* parSearchNodeAddr );
static NodeType* get_new_node ( const K& parKey );
static void delete_nodes ( NodeType* parNode );
[[gnu::pure]] bool is_alpha_height_balanced ( size_type parHeight, size_type parSize ) const;
NodeTypePair find_scapegoat ( NodeStack& parParents ) const;
static NodeType* rebalance ( NodeType* parSubtree, size_type parDepthHint );
static NodeType* compress_first ( NodeType* parFrom, size_type parDepthHint );
static NodeType* compress ( NodeType* parFrom );
[[gnu::pure]] static size_type get_max_balanced_depth ( size_type parSize, float parAlphaInvLogInv );
[[gnu::pure]] static size_type get_tree_min_depth_ib ( size_type parSize, float parAlphaInvLogInv );
static NodeType* detach_bottom_node ( NodeType* parTree, bool parSuccessor );
void rebalance_after_deletion_ifn ( void );
#if defined(SCAPEGOATTREE_PARANOID)
static size_type assert_node_size ( const NodeType* parSubtree );
static size_type find_max_depth ( const NodeType* parSubtree ) { return FindMaxDepth_rec(parSubtree) - 1; }
static size_type find_max_depth_rec ( const NodeType* parSubtree );
#endif
NodeType* m_root;
size_type m_count;
size_type m_countMax;
size_type m_reserved;
float m_alpha;
float m_alphainvloginv;
};
} //namespace duckmem
#include "implem/scapegoat_tree.inl"
#endif

View file

@ -1,54 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id4FAEF395B9ED47CB9D6B50B54C9A289A
#define id4FAEF395B9ED47CB9D6B50B54C9A289A
#include <cstddef>
namespace dhandy {
namespace bt {
template <typename T, T... I>
struct number_seq {
};
template <std::size_t... I>
using index_seq = number_seq<std::size_t, I...>;
namespace implem {
template <typename T, T MIN, T MAX, T... I>
struct range_builder;
template <typename T, T MIN, T... I>
struct range_builder<T, MIN, MIN, I...> {
typedef number_seq<T, I...> type;
};
template <typename T, T MIN, T N, T... I>
struct range_builder : public range_builder<T, MIN, N - 1, N - 1, I...> {
};
} //namespace implem
template <typename T, T MIN, T MAX>
using number_range = typename implem::range_builder<T, MIN, MAX>::type;
template <std::size_t MIN, std::size_t MAX>
using index_range = number_range<std::size_t, MIN, MAX>;
} //namespace bt
} //namespace dhandy
#endif

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -18,7 +18,7 @@
#ifndef id170B0E6C34D14EBA9B92A35977BDBFB3
#define id170B0E6C34D14EBA9B92A35977BDBFB3
#include "sequence_bt.hpp"
#include <utility>
#include <cstddef>
#include <iostream>
#include <stdexcept>
@ -58,14 +58,19 @@ namespace dhandy {
private:
template <std::size_t... I>
constexpr string ( const index_seq<I...>&, const value_type* parString );
constexpr string ( const std::index_sequence<I...>&, const value_type* parString );
const value_type m_data[S];
};
template <std::size_t S, typename Ch>
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
}
namespace implem {
template <std::size_t S, std::size_t S2, std::size_t... I>
constexpr string<S + S2 - 1> concat ( const index_seq<I...>&, const string<S>& parLeft, const string<S2>& parRight ) {
constexpr string<S + S2 - 1> concat ( const std::index_sequence<I...>&, const string<S>& parLeft, const string<S2>& parRight ) {
return string<S + S2 - 1>(
(I < S - 1 ? parLeft[I] : (I < S + S2 - 2 ? parRight[I - (S - 1)] : '\0'))...
);
@ -78,14 +83,14 @@ namespace dhandy {
template <std::size_t S, typename Ch>
template <std::size_t... I>
constexpr string<S, Ch>::string (const index_seq<I...>&, const value_type* parString) :
constexpr string<S, Ch>::string (const std::index_sequence<I...>&, const value_type* parString) :
m_data{parString[I]...}
{
}
template <std::size_t S, typename Ch>
inline constexpr string<S, Ch>::string (const value_type* parString) :
string(index_range<0, S>(), parString)
string(std::make_index_sequence<S>(), parString)
{
}
@ -99,7 +104,7 @@ namespace dhandy {
template <std::size_t S, typename Ch>
template <std::size_t S2>
constexpr inline string<S + S2 - 1, Ch> string<S, Ch>::operator+ (const string<S2, Ch>& parOther) const {
return implem::concat(index_range<0, S + S2 - 1>(), string<S>(m_data), parOther);
return implem::concat(std::make_index_sequence<S + S2 - 1>(), string<S>(m_data), parOther);
}
template <std::size_t S, typename Ch>
@ -108,11 +113,6 @@ namespace dhandy {
return parStream;
}
template <std::size_t S, typename Ch>
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
}
template <std::size_t S, typename Ch>
constexpr string<S, Ch> make_string (const Ch (&parData)[S]) {
return string<S>(parData);

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify

View file

@ -0,0 +1,61 @@
/* Copyright 2016-2024, Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id1E6CCE44307549A9B6C9E4E5923AC002
#define id1E6CCE44307549A9B6C9E4E5923AC002
#include "lengthof.h"
#include <cstdint>
#include <ciso646>
#include <climits>
namespace dhandy::bt {
struct TigerHash {
consteval TigerHash ( uint64_t parA, uint64_t parB, uint64_t parC ) :
a(parA), b(parB), c(parC)
{
}
consteval TigerHash ( uint64_t parAP, uint64_t parA, uint64_t parBP, uint64_t parB, uint64_t parCP, uint64_t parC ) :
a(0 == parAP ? parA : (0 == parBP ? parB : (0 == parCP ? parC : throw 0))),
b(1 == parAP ? parA : (1 == parBP ? parB : (1 == parCP ? parC : throw 0))),
c(2 == parAP ? parA : (2 == parBP ? parB : (2 == parCP ? parC : throw 0)))
{
}
consteval TigerHash ( const TigerHash& ) = default;
consteval uint64_t operator[] ( uint64_t parIndex ) const {
return (parIndex == 0 ? a :
(parIndex == 1 ? b :
(parIndex == 2 ? c : throw 0)
)
);
}
uint64_t a;
uint64_t b;
uint64_t c;
};
inline const constexpr char TigerPaddingV1 = 0x01;
inline const constexpr char TigerPaddingV2 = 0x80;
[[gnu::const]]
consteval TigerHash tiger ( const char* parStr, uint64_t parLen, char parPad );
} //namespace dhandy::bt
#include "tiger_bt.inl"
#endif

View file

@ -0,0 +1,488 @@
/* Copyright 2016-2024, Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
namespace dhandy::bt {
namespace implem {
constexpr const uint64_t table[4*256] = {0x02AAB17CF7E90C5EULL, 0xAC424B03E243A8ECULL,
0x72CD5BE30DD5FCD3ULL, 0x6D019B93F6F97F3AULL, 0xCD9978FFD21F9193ULL, 0x7573A1C9708029E2ULL,
0xB164326B922A83C3ULL, 0x46883EEE04915870ULL, 0xEAACE3057103ECE6ULL, 0xC54169B808A3535CULL,
0x4CE754918DDEC47CULL, 0x0AA2F4DFDC0DF40CULL, 0x10B76F18A74DBEFAULL, 0xC6CCB6235AD1AB6AULL,
0x13726121572FE2FFULL, 0x1A488C6F199D921EULL, 0x4BC9F9F4DA0007CAULL, 0x26F5E6F6E85241C7ULL,
0x859079DBEA5947B6ULL, 0x4F1885C5C99E8C92ULL, 0xD78E761EA96F864BULL, 0x8E36428C52B5C17DULL,
0x69CF6827373063C1ULL, 0xB607C93D9BB4C56EULL, 0x7D820E760E76B5EAULL, 0x645C9CC6F07FDC42ULL,
0xBF38A078243342E0ULL, 0x5F6B343C9D2E7D04ULL, 0xF2C28AEB600B0EC6ULL, 0x6C0ED85F7254BCACULL,
0x71592281A4DB4FE5ULL, 0x1967FA69CE0FED9FULL, 0xFD5293F8B96545DBULL, 0xC879E9D7F2A7600BULL,
0x860248920193194EULL, 0xA4F9533B2D9CC0B3ULL, 0x9053836C15957613ULL, 0xDB6DCF8AFC357BF1ULL,
0x18BEEA7A7A370F57ULL, 0x037117CA50B99066ULL, 0x6AB30A9774424A35ULL, 0xF4E92F02E325249BULL,
0x7739DB07061CCAE1ULL, 0xD8F3B49CECA42A05ULL, 0xBD56BE3F51382F73ULL, 0x45FAED5843B0BB28ULL,
0x1C813D5C11BF1F83ULL, 0x8AF0E4B6D75FA169ULL, 0x33EE18A487AD9999ULL, 0x3C26E8EAB1C94410ULL,
0xB510102BC0A822F9ULL, 0x141EEF310CE6123BULL, 0xFC65B90059DDB154ULL, 0xE0158640C5E0E607ULL,
0x884E079826C3A3CFULL, 0x930D0D9523C535FDULL, 0x35638D754E9A2B00ULL, 0x4085FCCF40469DD5ULL,
0xC4B17AD28BE23A4CULL, 0xCAB2F0FC6A3E6A2EULL, 0x2860971A6B943FCDULL, 0x3DDE6EE212E30446ULL,
0x6222F32AE01765AEULL, 0x5D550BB5478308FEULL, 0xA9EFA98DA0EDA22AULL, 0xC351A71686C40DA7ULL,
0x1105586D9C867C84ULL, 0xDCFFEE85FDA22853ULL, 0xCCFBD0262C5EEF76ULL, 0xBAF294CB8990D201ULL,
0xE69464F52AFAD975ULL, 0x94B013AFDF133E14ULL, 0x06A7D1A32823C958ULL, 0x6F95FE5130F61119ULL,
0xD92AB34E462C06C0ULL, 0xED7BDE33887C71D2ULL, 0x79746D6E6518393EULL, 0x5BA419385D713329ULL,
0x7C1BA6B948A97564ULL, 0x31987C197BFDAC67ULL, 0xDE6C23C44B053D02ULL, 0x581C49FED002D64DULL,
0xDD474D6338261571ULL, 0xAA4546C3E473D062ULL, 0x928FCE349455F860ULL, 0x48161BBACAAB94D9ULL,
0x63912430770E6F68ULL, 0x6EC8A5E602C6641CULL, 0x87282515337DDD2BULL, 0x2CDA6B42034B701BULL,
0xB03D37C181CB096DULL, 0xE108438266C71C6FULL, 0x2B3180C7EB51B255ULL, 0xDF92B82F96C08BBCULL,
0x5C68C8C0A632F3BAULL, 0x5504CC861C3D0556ULL, 0xABBFA4E55FB26B8FULL, 0x41848B0AB3BACEB4ULL,
0xB334A273AA445D32ULL, 0xBCA696F0A85AD881ULL, 0x24F6EC65B528D56CULL, 0x0CE1512E90F4524AULL,
0x4E9DD79D5506D35AULL, 0x258905FAC6CE9779ULL, 0x2019295B3E109B33ULL, 0xF8A9478B73A054CCULL,
0x2924F2F934417EB0ULL, 0x3993357D536D1BC4ULL, 0x38A81AC21DB6FF8BULL, 0x47C4FBF17D6016BFULL,
0x1E0FAADD7667E3F5ULL, 0x7ABCFF62938BEB96ULL, 0xA78DAD948FC179C9ULL, 0x8F1F98B72911E50DULL,
0x61E48EAE27121A91ULL, 0x4D62F7AD31859808ULL, 0xECEBA345EF5CEAEBULL, 0xF5CEB25EBC9684CEULL,
0xF633E20CB7F76221ULL, 0xA32CDF06AB8293E4ULL, 0x985A202CA5EE2CA4ULL, 0xCF0B8447CC8A8FB1ULL,
0x9F765244979859A3ULL, 0xA8D516B1A1240017ULL, 0x0BD7BA3EBB5DC726ULL, 0xE54BCA55B86ADB39ULL,
0x1D7A3AFD6C478063ULL, 0x519EC608E7669EDDULL, 0x0E5715A2D149AA23ULL, 0x177D4571848FF194ULL,
0xEEB55F3241014C22ULL, 0x0F5E5CA13A6E2EC2ULL, 0x8029927B75F5C361ULL, 0xAD139FABC3D6E436ULL,
0x0D5DF1A94CCF402FULL, 0x3E8BD948BEA5DFC8ULL, 0xA5A0D357BD3FF77EULL, 0xA2D12E251F74F645ULL,
0x66FD9E525E81A082ULL, 0x2E0C90CE7F687A49ULL, 0xC2E8BCBEBA973BC5ULL, 0x000001BCE509745FULL,
0x423777BBE6DAB3D6ULL, 0xD1661C7EAEF06EB5ULL, 0xA1781F354DAACFD8ULL, 0x2D11284A2B16AFFCULL,
0xF1FC4F67FA891D1FULL, 0x73ECC25DCB920ADAULL, 0xAE610C22C2A12651ULL, 0x96E0A810D356B78AULL,
0x5A9A381F2FE7870FULL, 0xD5AD62EDE94E5530ULL, 0xD225E5E8368D1427ULL, 0x65977B70C7AF4631ULL,
0x99F889B2DE39D74FULL, 0x233F30BF54E1D143ULL, 0x9A9675D3D9A63C97ULL, 0x5470554FF334F9A8ULL,
0x166ACB744A4F5688ULL, 0x70C74CAAB2E4AEADULL, 0xF0D091646F294D12ULL, 0x57B82A89684031D1ULL,
0xEFD95A5A61BE0B6BULL, 0x2FBD12E969F2F29AULL, 0x9BD37013FEFF9FE8ULL, 0x3F9B0404D6085A06ULL,
0x4940C1F3166CFE15ULL, 0x09542C4DCDF3DEFBULL, 0xB4C5218385CD5CE3ULL, 0xC935B7DC4462A641ULL,
0x3417F8A68ED3B63FULL, 0xB80959295B215B40ULL, 0xF99CDAEF3B8C8572ULL, 0x018C0614F8FCB95DULL,
0x1B14ACCD1A3ACDF3ULL, 0x84D471F200BB732DULL, 0xC1A3110E95E8DA16ULL, 0x430A7220BF1A82B8ULL,
0xB77E090D39DF210EULL, 0x5EF4BD9F3CD05E9DULL, 0x9D4FF6DA7E57A444ULL, 0xDA1D60E183D4A5F8ULL,
0xB287C38417998E47ULL, 0xFE3EDC121BB31886ULL, 0xC7FE3CCC980CCBEFULL, 0xE46FB590189BFD03ULL,
0x3732FD469A4C57DCULL, 0x7EF700A07CF1AD65ULL, 0x59C64468A31D8859ULL, 0x762FB0B4D45B61F6ULL,
0x155BAED099047718ULL, 0x68755E4C3D50BAA6ULL, 0xE9214E7F22D8B4DFULL, 0x2ADDBF532EAC95F4ULL,
0x32AE3909B4BD0109ULL, 0x834DF537B08E3450ULL, 0xFA209DA84220728DULL, 0x9E691D9B9EFE23F7ULL,
0x0446D288C4AE8D7FULL, 0x7B4CC524E169785BULL, 0x21D87F0135CA1385ULL, 0xCEBB400F137B8AA5ULL,
0x272E2B66580796BEULL, 0x3612264125C2B0DEULL, 0x057702BDAD1EFBB2ULL, 0xD4BABB8EACF84BE9ULL,
0x91583139641BC67BULL, 0x8BDC2DE08036E024ULL, 0x603C8156F49F68EDULL, 0xF7D236F7DBEF5111ULL,
0x9727C4598AD21E80ULL, 0xA08A0896670A5FD7ULL, 0xCB4A8F4309EBA9CBULL, 0x81AF564B0F7036A1ULL,
0xC0B99AA778199ABDULL, 0x959F1EC83FC8E952ULL, 0x8C505077794A81B9ULL, 0x3ACAAF8F056338F0ULL,
0x07B43F50627A6778ULL, 0x4A44AB49F5ECCC77ULL, 0x3BC3D6E4B679EE98ULL, 0x9CC0D4D1CF14108CULL,
0x4406C00B206BC8A0ULL, 0x82A18854C8D72D89ULL, 0x67E366B35C3C432CULL, 0xB923DD61102B37F2ULL,
0x56AB2779D884271DULL, 0xBE83E1B0FF1525AFULL, 0xFB7C65D4217E49A9ULL, 0x6BDBE0E76D48E7D4ULL,
0x08DF828745D9179EULL, 0x22EA6A9ADD53BD34ULL, 0xE36E141C5622200AULL, 0x7F805D1B8CB750EEULL,
0xAFE5C7A59F58E837ULL, 0xE27F996A4FB1C23CULL, 0xD3867DFB0775F0D0ULL, 0xD0E673DE6E88891AULL,
0x123AEB9EAFB86C25ULL, 0x30F1D5D5C145B895ULL, 0xBB434A2DEE7269E7ULL, 0x78CB67ECF931FA38ULL,
0xF33B0372323BBF9CULL, 0x52D66336FB279C74ULL, 0x505F33AC0AFB4EAAULL, 0xE8A5CD99A2CCE187ULL,
0x534974801E2D30BBULL, 0x8D2D5711D5876D90ULL, 0x1F1A412891BC038EULL, 0xD6E2E71D82E56648ULL,
0x74036C3A497732B7ULL, 0x89B67ED96361F5ABULL, 0xFFED95D8F1EA02A2ULL, 0xE72B3BD61464D43DULL,
0xA6300F170BDC4820ULL, 0xEBC18760ED78A77AULL, 0xE6A6BE5A05A12138ULL, 0xB5A122A5B4F87C98ULL,
0x563C6089140B6990ULL, 0x4C46CB2E391F5DD5ULL, 0xD932ADDBC9B79434ULL, 0x08EA70E42015AFF5ULL,
0xD765A6673E478CF1ULL, 0xC4FB757EAB278D99ULL, 0xDF11C6862D6E0692ULL, 0xDDEB84F10D7F3B16ULL,
0x6F2EF604A665EA04ULL, 0x4A8E0F0FF0E0DFB3ULL, 0xA5EDEEF83DBCBA51ULL, 0xFC4F0A2A0EA4371EULL,
0xE83E1DA85CB38429ULL, 0xDC8FF882BA1B1CE2ULL, 0xCD45505E8353E80DULL, 0x18D19A00D4DB0717ULL,
0x34A0CFEDA5F38101ULL, 0x0BE77E518887CAF2ULL, 0x1E341438B3C45136ULL, 0xE05797F49089CCF9ULL,
0xFFD23F9DF2591D14ULL, 0x543DDA228595C5CDULL, 0x661F81FD99052A33ULL, 0x8736E641DB0F7B76ULL,
0x15227725418E5307ULL, 0xE25F7F46162EB2FAULL, 0x48A8B2126C13D9FEULL, 0xAFDC541792E76EEAULL,
0x03D912BFC6D1898FULL, 0x31B1AAFA1B83F51BULL, 0xF1AC2796E42AB7D9ULL, 0x40A3A7D7FCD2EBACULL,
0x1056136D0AFBBCC5ULL, 0x7889E1DD9A6D0C85ULL, 0xD33525782A7974AAULL, 0xA7E25D09078AC09BULL,
0xBD4138B3EAC6EDD0ULL, 0x920ABFBE71EB9E70ULL, 0xA2A5D0F54FC2625CULL, 0xC054E36B0B1290A3ULL,
0xF6DD59FF62FE932BULL, 0x3537354511A8AC7DULL, 0xCA845E9172FADCD4ULL, 0x84F82B60329D20DCULL,
0x79C62CE1CD672F18ULL, 0x8B09A2ADD124642CULL, 0xD0C1E96A19D9E726ULL, 0x5A786A9B4BA9500CULL,
0x0E020336634C43F3ULL, 0xC17B474AEB66D822ULL, 0x6A731AE3EC9BAAC2ULL, 0x8226667AE0840258ULL,
0x67D4567691CAECA5ULL, 0x1D94155C4875ADB5ULL, 0x6D00FD985B813FDFULL, 0x51286EFCB774CD06ULL,
0x5E8834471FA744AFULL, 0xF72CA0AEE761AE2EULL, 0xBE40E4CDAEE8E09AULL, 0xE9970BBB5118F665ULL,
0x726E4BEB33DF1964ULL, 0x703B000729199762ULL, 0x4631D816F5EF30A7ULL, 0xB880B5B51504A6BEULL,
0x641793C37ED84B6CULL, 0x7B21ED77F6E97D96ULL, 0x776306312EF96B73ULL, 0xAE528948E86FF3F4ULL,
0x53DBD7F286A3F8F8ULL, 0x16CADCE74CFC1063ULL, 0x005C19BDFA52C6DDULL, 0x68868F5D64D46AD3ULL,
0x3A9D512CCF1E186AULL, 0x367E62C2385660AEULL, 0xE359E7EA77DCB1D7ULL, 0x526C0773749ABE6EULL,
0x735AE5F9D09F734BULL, 0x493FC7CC8A558BA8ULL, 0xB0B9C1533041AB45ULL, 0x321958BA470A59BDULL,
0x852DB00B5F46C393ULL, 0x91209B2BD336B0E5ULL, 0x6E604F7D659EF19FULL, 0xB99A8AE2782CCB24ULL,
0xCCF52AB6C814C4C7ULL, 0x4727D9AFBE11727BULL, 0x7E950D0C0121B34DULL, 0x756F435670AD471FULL,
0xF5ADD442615A6849ULL, 0x4E87E09980B9957AULL, 0x2ACFA1DF50AEE355ULL, 0xD898263AFD2FD556ULL,
0xC8F4924DD80C8FD6ULL, 0xCF99CA3D754A173AULL, 0xFE477BACAF91BF3CULL, 0xED5371F6D690C12DULL,
0x831A5C285E687094ULL, 0xC5D3C90A3708A0A4ULL, 0x0F7F903717D06580ULL, 0x19F9BB13B8FDF27FULL,
0xB1BD6F1B4D502843ULL, 0x1C761BA38FFF4012ULL, 0x0D1530C4E2E21F3BULL, 0x8943CE69A7372C8AULL,
0xE5184E11FEB5CE66ULL, 0x618BDB80BD736621ULL, 0x7D29BAD68B574D0BULL, 0x81BB613E25E6FE5BULL,
0x071C9C10BC07913FULL, 0xC7BEEB7909AC2D97ULL, 0xC3E58D353BC5D757ULL, 0xEB017892F38F61E8ULL,
0xD4EFFB9C9B1CC21AULL, 0x99727D26F494F7ABULL, 0xA3E063A2956B3E03ULL, 0x9D4A8B9A4AA09C30ULL,
0x3F6AB7D500090FB4ULL, 0x9CC0F2A057268AC0ULL, 0x3DEE9D2DEDBF42D1ULL, 0x330F49C87960A972ULL,
0xC6B2720287421B41ULL, 0x0AC59EC07C00369CULL, 0xEF4EAC49CB353425ULL, 0xF450244EEF0129D8ULL,
0x8ACC46E5CAF4DEB6ULL, 0x2FFEAB63989263F7ULL, 0x8F7CB9FE5D7A4578ULL, 0x5BD8F7644E634635ULL,
0x427A7315BF2DC900ULL, 0x17D0C4AA2125261CULL, 0x3992486C93518E50ULL, 0xB4CBFEE0A2D7D4C3ULL,
0x7C75D6202C5DDD8DULL, 0xDBC295D8E35B6C61ULL, 0x60B369D302032B19ULL, 0xCE42685FDCE44132ULL,
0x06F3DDB9DDF65610ULL, 0x8EA4D21DB5E148F0ULL, 0x20B0FCE62FCD496FULL, 0x2C1B912358B0EE31ULL,
0xB28317B818F5A308ULL, 0xA89C1E189CA6D2CFULL, 0x0C6B18576AAADBC8ULL, 0xB65DEAA91299FAE3ULL,
0xFB2B794B7F1027E7ULL, 0x04E4317F443B5BEBULL, 0x4B852D325939D0A6ULL, 0xD5AE6BEEFB207FFCULL,
0x309682B281C7D374ULL, 0xBAE309A194C3B475ULL, 0x8CC3F97B13B49F05ULL, 0x98A9422FF8293967ULL,
0x244B16B01076FF7CULL, 0xF8BF571C663D67EEULL, 0x1F0D6758EEE30DA1ULL, 0xC9B611D97ADEB9B7ULL,
0xB7AFD5887B6C57A2ULL, 0x6290AE846B984FE1ULL, 0x94DF4CDEACC1A5FDULL, 0x058A5BD1C5483AFFULL,
0x63166CC142BA3C37ULL, 0x8DB8526EB2F76F40ULL, 0xE10880036F0D6D4EULL, 0x9E0523C9971D311DULL,
0x45EC2824CC7CD691ULL, 0x575B8359E62382C9ULL, 0xFA9E400DC4889995ULL, 0xD1823ECB45721568ULL,
0xDAFD983B8206082FULL, 0xAA7D29082386A8CBULL, 0x269FCD4403B87588ULL, 0x1B91F5F728BDD1E0ULL,
0xE4669F39040201F6ULL, 0x7A1D7C218CF04ADEULL, 0x65623C29D79CE5CEULL, 0x2368449096C00BB1ULL,
0xAB9BF1879DA503BAULL, 0xBC23ECB1A458058EULL, 0x9A58DF01BB401ECCULL, 0xA070E868A85F143DULL,
0x4FF188307DF2239EULL, 0x14D565B41A641183ULL, 0xEE13337452701602ULL, 0x950E3DCF3F285E09ULL,
0x59930254B9C80953ULL, 0x3BF299408930DA6DULL, 0xA955943F53691387ULL, 0xA15EDECAA9CB8784ULL,
0x29142127352BE9A0ULL, 0x76F0371FFF4E7AFBULL, 0x0239F450274F2228ULL, 0xBB073AF01D5E868BULL,
0xBFC80571C10E96C1ULL, 0xD267088568222E23ULL, 0x9671A3D48E80B5B0ULL, 0x55B5D38AE193BB81ULL,
0x693AE2D0A18B04B8ULL, 0x5C48B4ECADD5335FULL, 0xFD743B194916A1CAULL, 0x2577018134BE98C4ULL,
0xE77987E83C54A4ADULL, 0x28E11014DA33E1B9ULL, 0x270CC59E226AA213ULL, 0x71495F756D1A5F60ULL,
0x9BE853FB60AFEF77ULL, 0xADC786A7F7443DBFULL, 0x0904456173B29A82ULL, 0x58BC7A66C232BD5EULL,
0xF306558C673AC8B2ULL, 0x41F639C6B6C9772AULL, 0x216DEFE99FDA35DAULL, 0x11640CC71C7BE615ULL,
0x93C43694565C5527ULL, 0xEA038E6246777839ULL, 0xF9ABF3CE5A3E2469ULL, 0x741E768D0FD312D2ULL,
0x0144B883CED652C6ULL, 0xC20B5A5BA33F8552ULL, 0x1AE69633C3435A9DULL, 0x97A28CA4088CFDECULL,
0x8824A43C1E96F420ULL, 0x37612FA66EEEA746ULL, 0x6B4CB165F9CF0E5AULL, 0x43AA1C06A0ABFB4AULL,
0x7F4DC26FF162796BULL, 0x6CBACC8E54ED9B0FULL, 0xA6B7FFEFD2BB253EULL, 0x2E25BC95B0A29D4FULL,
0x86D6A58BDEF1388CULL, 0xDED74AC576B6F054ULL, 0x8030BDBC2B45805DULL, 0x3C81AF70E94D9289ULL,
0x3EFF6DDA9E3100DBULL, 0xB38DC39FDFCC8847ULL, 0x123885528D17B87EULL, 0xF2DA0ED240B1B642ULL,
0x44CEFADCD54BF9A9ULL, 0x1312200E433C7EE6ULL, 0x9FFCC84F3A78C748ULL, 0xF0CD1F72248576BBULL,
0xEC6974053638CFE4ULL, 0x2BA7B67C0CEC4E4CULL, 0xAC2F4DF3E5CE32EDULL, 0xCB33D14326EA4C11ULL,
0xA4E9044CC77E58BCULL, 0x5F513293D934FCEFULL, 0x5DC9645506E55444ULL, 0x50DE418F317DE40AULL,
0x388CB31A69DDE259ULL, 0x2DB4A83455820A86ULL, 0x9010A91E84711AE9ULL, 0x4DF7F0B7B1498371ULL,
0xD62A2EABC0977179ULL, 0x22FAC097AA8D5C0EULL, 0xF49FCC2FF1DAF39BULL, 0x487FD5C66FF29281ULL,
0xE8A30667FCDCA83FULL, 0x2C9B4BE3D2FCCE63ULL, 0xDA3FF74B93FBBBC2ULL, 0x2FA165D2FE70BA66ULL,
0xA103E279970E93D4ULL, 0xBECDEC77B0E45E71ULL, 0xCFB41E723985E497ULL, 0xB70AAA025EF75017ULL,
0xD42309F03840B8E0ULL, 0x8EFC1AD035898579ULL, 0x96C6920BE2B2ABC5ULL, 0x66AF4163375A9172ULL,
0x2174ABDCCA7127FBULL, 0xB33CCEA64A72FF41ULL, 0xF04A4933083066A5ULL, 0x8D970ACDD7289AF5ULL,
0x8F96E8E031C8C25EULL, 0xF3FEC02276875D47ULL, 0xEC7BF310056190DDULL, 0xF5ADB0AEBB0F1491ULL,
0x9B50F8850FD58892ULL, 0x4975488358B74DE8ULL, 0xA3354FF691531C61ULL, 0x0702BBE481D2C6EEULL,
0x89FB24057DEDED98ULL, 0xAC3075138596E902ULL, 0x1D2D3580172772EDULL, 0xEB738FC28E6BC30DULL,
0x5854EF8F63044326ULL, 0x9E5C52325ADD3BBEULL, 0x90AA53CF325C4623ULL, 0xC1D24D51349DD067ULL,
0x2051CFEEA69EA624ULL, 0x13220F0A862E7E4FULL, 0xCE39399404E04864ULL, 0xD9C42CA47086FCB7ULL,
0x685AD2238A03E7CCULL, 0x066484B2AB2FF1DBULL, 0xFE9D5D70EFBF79ECULL, 0x5B13B9DD9C481854ULL,
0x15F0D475ED1509ADULL, 0x0BEBCD060EC79851ULL, 0xD58C6791183AB7F8ULL, 0xD1187C5052F3EEE4ULL,
0xC95D1192E54E82FFULL, 0x86EEA14CB9AC6CA2ULL, 0x3485BEB153677D5DULL, 0xDD191D781F8C492AULL,
0xF60866BAA784EBF9ULL, 0x518F643BA2D08C74ULL, 0x8852E956E1087C22ULL, 0xA768CB8DC410AE8DULL,
0x38047726BFEC8E1AULL, 0xA67738B4CD3B45AAULL, 0xAD16691CEC0DDE19ULL, 0xC6D4319380462E07ULL,
0xC5A5876D0BA61938ULL, 0x16B9FA1FA58FD840ULL, 0x188AB1173CA74F18ULL, 0xABDA2F98C99C021FULL,
0x3E0580AB134AE816ULL, 0x5F3B05B773645ABBULL, 0x2501A2BE5575F2F6ULL, 0x1B2F74004E7E8BA9ULL,
0x1CD7580371E8D953ULL, 0x7F6ED89562764E30ULL, 0xB15926FF596F003DULL, 0x9F65293DA8C5D6B9ULL,
0x6ECEF04DD690F84CULL, 0x4782275FFF33AF88ULL, 0xE41433083F820801ULL, 0xFD0DFE409A1AF9B5ULL,
0x4325A3342CDB396BULL, 0x8AE77E62B301B252ULL, 0xC36F9E9F6655615AULL, 0x85455A2D92D32C09ULL,
0xF2C7DEA949477485ULL, 0x63CFB4C133A39EBAULL, 0x83B040CC6EBC5462ULL, 0x3B9454C8FDB326B0ULL,
0x56F56A9E87FFD78CULL, 0x2DC2940D99F42BC6ULL, 0x98F7DF096B096E2DULL, 0x19A6E01E3AD852BFULL,
0x42A99CCBDBD4B40BULL, 0xA59998AF45E9C559ULL, 0x366295E807D93186ULL, 0x6B48181BFAA1F773ULL,
0x1FEC57E2157A0A1DULL, 0x4667446AF6201AD5ULL, 0xE615EBCACFB0F075ULL, 0xB8F31F4F68290778ULL,
0x22713ED6CE22D11EULL, 0x3057C1A72EC3C93BULL, 0xCB46ACC37C3F1F2FULL, 0xDBB893FD02AAF50EULL,
0x331FD92E600B9FCFULL, 0xA498F96148EA3AD6ULL, 0xA8D8426E8B6A83EAULL, 0xA089B274B7735CDCULL,
0x87F6B3731E524A11ULL, 0x118808E5CBC96749ULL, 0x9906E4C7B19BD394ULL, 0xAFED7F7E9B24A20CULL,
0x6509EADEEB3644A7ULL, 0x6C1EF1D3E8EF0EDEULL, 0xB9C97D43E9798FB4ULL, 0xA2F2D784740C28A3ULL,
0x7B8496476197566FULL, 0x7A5BE3E6B65F069DULL, 0xF96330ED78BE6F10ULL, 0xEEE60DE77A076A15ULL,
0x2B4BEE4AA08B9BD0ULL, 0x6A56A63EC7B8894EULL, 0x02121359BA34FEF4ULL, 0x4CBF99F8283703FCULL,
0x398071350CAF30C8ULL, 0xD0A77A89F017687AULL, 0xF1C1A9EB9E423569ULL, 0x8C7976282DEE8199ULL,
0x5D1737A5DD1F7ABDULL, 0x4F53433C09A9FA80ULL, 0xFA8B0C53DF7CA1D9ULL, 0x3FD9DCBC886CCB77ULL,
0xC040917CA91B4720ULL, 0x7DD00142F9D1DCDFULL, 0x8476FC1D4F387B58ULL, 0x23F8E7C5F3316503ULL,
0x032A2244E7E37339ULL, 0x5C87A5D750F5A74BULL, 0x082B4CC43698992EULL, 0xDF917BECB858F63CULL,
0x3270B8FC5BF86DDAULL, 0x10AE72BB29B5DD76ULL, 0x576AC94E7700362BULL, 0x1AD112DAC61EFB8FULL,
0x691BC30EC5FAA427ULL, 0xFF246311CC327143ULL, 0x3142368E30E53206ULL, 0x71380E31E02CA396ULL,
0x958D5C960AAD76F1ULL, 0xF8D6F430C16DA536ULL, 0xC8FFD13F1BE7E1D2ULL, 0x7578AE66004DDBE1ULL,
0x05833F01067BE646ULL, 0xBB34B5AD3BFE586DULL, 0x095F34C9A12B97F0ULL, 0x247AB64525D60CA8ULL,
0xDCDBC6F3017477D1ULL, 0x4A2E14D4DECAD24DULL, 0xBDB5E6D9BE0A1EEBULL, 0x2A7E70F7794301ABULL,
0xDEF42D8A270540FDULL, 0x01078EC0A34C22C1ULL, 0xE5DE511AF4C16387ULL, 0x7EBB3A52BD9A330AULL,
0x77697857AA7D6435ULL, 0x004E831603AE4C32ULL, 0xE7A21020AD78E312ULL, 0x9D41A70C6AB420F2ULL,
0x28E06C18EA1141E6ULL, 0xD2B28CBD984F6B28ULL, 0x26B75F6C446E9D83ULL, 0xBA47568C4D418D7FULL,
0xD80BADBFE6183D8EULL, 0x0E206D7F5F166044ULL, 0xE258A43911CBCA3EULL, 0x723A1746B21DC0BCULL,
0xC7CAA854F5D7CDD3ULL, 0x7CAC32883D261D9CULL, 0x7690C26423BA942CULL, 0x17E55524478042B8ULL,
0xE0BE477656A2389FULL, 0x4D289B5E67AB2DA0ULL, 0x44862B9C8FBBFD31ULL, 0xB47CC8049D141365ULL,
0x822C1B362B91C793ULL, 0x4EB14655FB13DFD8ULL, 0x1ECBBA0714E2A97BULL, 0x6143459D5CDE5F14ULL,
0x53A8FBF1D5F0AC89ULL, 0x97EA04D81C5E5B00ULL, 0x622181A8D4FDB3F3ULL, 0xE9BCD341572A1208ULL,
0x1411258643CCE58AULL, 0x9144C5FEA4C6E0A4ULL, 0x0D33D06565CF620FULL, 0x54A48D489F219CA1ULL,
0xC43E5EAC6D63C821ULL, 0xA9728B3A72770DAFULL, 0xD7934E7B20DF87EFULL, 0xE35503B61A3E86E5ULL,
0xCAE321FBC819D504ULL, 0x129A50B3AC60BFA6ULL, 0xCD5E68EA7E9FB6C3ULL, 0xB01C90199483B1C7ULL,
0x3DE93CD5C295376CULL, 0xAED52EDF2AB9AD13ULL, 0x2E60F512C0A07884ULL, 0xBC3D86A3E36210C9ULL,
0x35269D9B163951CEULL, 0x0C7D6E2AD0CDB5FAULL, 0x59E86297D87F5733ULL, 0x298EF221898DB0E7ULL,
0x55000029D1A5AA7EULL, 0x8BC08AE1B5061B45ULL, 0xC2C31C2B6C92703AULL, 0x94CC596BAF25EF42ULL,
0x0A1D73DB22540456ULL, 0x04B6A0F9D9C4179AULL, 0xEFFDAFA2AE3D3C60ULL, 0xF7C8075BB49496C4ULL,
0x9CC5C7141D1CD4E3ULL, 0x78BD1638218E5534ULL, 0xB2F11568F850246AULL, 0xEDFABCFA9502BC29ULL,
0x796CE5F2DA23051BULL, 0xAAE128B0DC93537CULL, 0x3A493DA0EE4B29AEULL, 0xB5DF6B2C416895D7ULL,
0xFCABBD25122D7F37ULL, 0x70810B58105DC4B1ULL, 0xE10FDD37F7882A90ULL, 0x524DCAB5518A3F5CULL,
0x3C9E85878451255BULL, 0x4029828119BD34E2ULL, 0x74A05B6F5D3CECCBULL, 0xB610021542E13ECAULL,
0x0FF979D12F59E2ACULL, 0x6037DA27E4F9CC50ULL, 0x5E92975A0DF1847DULL, 0xD66DE190D3E623FEULL,
0x5032D6B87B568048ULL, 0x9A36B7CE8235216EULL, 0x80272A7A24F64B4AULL, 0x93EFED8B8C6916F7ULL,
0x37DDBFF44CCE1555ULL, 0x4B95DB5D4B99BD25ULL, 0x92D3FDA169812FC0ULL, 0xFB1A4A9A90660BB6ULL,
0x730C196946A4B9B2ULL, 0x81E289AA7F49DA68ULL, 0x64669A0F83B1A05FULL, 0x27B3FF7D9644F48BULL,
0xCC6B615C8DB675B3ULL, 0x674F20B9BCEBBE95ULL, 0x6F31238275655982ULL, 0x5AE488713E45CF05ULL,
0xBF619F9954C21157ULL, 0xEABAC46040A8EAE9ULL, 0x454C6FE9F2C0C1CDULL, 0x419CF6496412691CULL,
0xD3DC3BEF265B0F70ULL, 0x6D0E60F5C3578A9EULL, 0x5B0E608526323C55ULL, 0x1A46C1A9FA1B59F5ULL,
0xA9E245A17C4C8FFAULL, 0x65CA5159DB2955D7ULL, 0x05DB0A76CE35AFC2ULL, 0x81EAC77EA9113D45ULL,
0x528EF88AB6AC0A0DULL, 0xA09EA253597BE3FFULL, 0x430DDFB3AC48CD56ULL, 0xC4B3A67AF45CE46FULL,
0x4ECECFD8FBE2D05EULL, 0x3EF56F10B39935F0ULL, 0x0B22D6829CD619C6ULL, 0x17FD460A74DF2069ULL,
0x6CF8CC8E8510ED40ULL, 0xD6C824BF3A6ECAA7ULL, 0x61243D581A817049ULL, 0x048BACB6BBC163A2ULL,
0xD9A38AC27D44CC32ULL, 0x7FDDFF5BAAF410ABULL, 0xAD6D495AA804824BULL, 0xE1A6A74F2D8C9F94ULL,
0xD4F7851235DEE8E3ULL, 0xFD4B7F886540D893ULL, 0x247C20042AA4BFDAULL, 0x096EA1C517D1327CULL,
0xD56966B4361A6685ULL, 0x277DA5C31221057DULL, 0x94D59893A43ACFF7ULL, 0x64F0C51CCDC02281ULL,
0x3D33BCC4FF6189DBULL, 0xE005CB184CE66AF1ULL, 0xFF5CCD1D1DB99BEAULL, 0xB0B854A7FE42980FULL,
0x7BD46A6A718D4B9FULL, 0xD10FA8CC22A5FD8CULL, 0xD31484952BE4BD31ULL, 0xC7FA975FCB243847ULL,
0x4886ED1E5846C407ULL, 0x28CDDB791EB70B04ULL, 0xC2B00BE2F573417FULL, 0x5C9590452180F877ULL,
0x7A6BDDFFF370EB00ULL, 0xCE509E38D6D9D6A4ULL, 0xEBEB0F00647FA702ULL, 0x1DCC06CF76606F06ULL,
0xE4D9F28BA286FF0AULL, 0xD85A305DC918C262ULL, 0x475B1D8732225F54ULL, 0x2D4FB51668CCB5FEULL,
0xA679B9D9D72BBA20ULL, 0x53841C0D912D43A5ULL, 0x3B7EAA48BF12A4E8ULL, 0x781E0E47F22F1DDFULL,
0xEFF20CE60AB50973ULL, 0x20D261D19DFFB742ULL, 0x16A12B03062A2E39ULL, 0x1960EB2239650495ULL,
0x251C16FED50EB8B8ULL, 0x9AC0C330F826016EULL, 0xED152665953E7671ULL, 0x02D63194A6369570ULL,
0x5074F08394B1C987ULL, 0x70BA598C90B25CE1ULL, 0x794A15810B9742F6ULL, 0x0D5925E9FCAF8C6CULL,
0x3067716CD868744EULL, 0x910AB077E8D7731BULL, 0x6A61BBDB5AC42F61ULL, 0x93513EFBF0851567ULL,
0xF494724B9E83E9D5ULL, 0xE887E1985C09648DULL, 0x34B1D3C675370CFDULL, 0xDC35E433BC0D255DULL,
0xD0AAB84234131BE0ULL, 0x08042A50B48B7EAFULL, 0x9997C4EE44A3AB35ULL, 0x829A7B49201799D0ULL,
0x263B8307B7C54441ULL, 0x752F95F4FD6A6CA6ULL, 0x927217402C08C6E5ULL, 0x2A8AB754A795D9EEULL,
0xA442F7552F72943DULL, 0x2C31334E19781208ULL, 0x4FA98D7CEAEE6291ULL, 0x55C3862F665DB309ULL,
0xBD0610175D53B1F3ULL, 0x46FE6CB840413F27ULL, 0x3FE03792DF0CFA59ULL, 0xCFE700372EB85E8FULL,
0xA7BE29E7ADBCE118ULL, 0xE544EE5CDE8431DDULL, 0x8A781B1B41F1873EULL, 0xA5C94C78A0D2F0E7ULL,
0x39412E2877B60728ULL, 0xA1265EF3AFC9A62CULL, 0xBCC2770C6A2506C5ULL, 0x3AB66DD5DCE1CE12ULL,
0xE65499D04A675B37ULL, 0x7D8F523481BFD216ULL, 0x0F6F64FCEC15F389ULL, 0x74EFBE618B5B13C8ULL,
0xACDC82B714273E1DULL, 0xDD40BFE003199D17ULL, 0x37E99257E7E061F8ULL, 0xFA52626904775AAAULL,
0x8BBBF63A463D56F9ULL, 0xF0013F1543A26E64ULL, 0xA8307E9F879EC898ULL, 0xCC4C27A4150177CCULL,
0x1B432F2CCA1D3348ULL, 0xDE1D1F8F9F6FA013ULL, 0x606602A047A7DDD6ULL, 0xD237AB64CC1CB2C7ULL,
0x9B938E7225FCD1D3ULL, 0xEC4E03708E0FF476ULL, 0xFEB2FBDA3D03C12DULL, 0xAE0BCED2EE43889AULL,
0x22CB8923EBFB4F43ULL, 0x69360D013CF7396DULL, 0x855E3602D2D4E022ULL, 0x073805BAD01F784CULL,
0x33E17A133852F546ULL, 0xDF4874058AC7B638ULL, 0xBA92B29C678AA14AULL, 0x0CE89FC76CFAADCDULL,
0x5F9D4E0908339E34ULL, 0xF1AFE9291F5923B9ULL, 0x6E3480F60F4A265FULL, 0xEEBF3A2AB29B841CULL,
0xE21938A88F91B4ADULL, 0x57DFEFF845C6D3C3ULL, 0x2F006B0BF62CAAF2ULL, 0x62F479EF6F75EE78ULL,
0x11A55AD41C8916A9ULL, 0xF229D29084FED453ULL, 0x42F1C27B16B000E6ULL, 0x2B1F76749823C074ULL,
0x4B76ECA3C2745360ULL, 0x8C98F463B91691BDULL, 0x14BCC93CF1ADE66AULL, 0x8885213E6D458397ULL,
0x8E177DF0274D4711ULL, 0xB49B73B5503F2951ULL, 0x10168168C3F96B6BULL, 0x0E3D963B63CAB0AEULL,
0x8DFC4B5655A1DB14ULL, 0xF789F1356E14DE5CULL, 0x683E68AF4E51DAC1ULL, 0xC9A84F9D8D4B0FD9ULL,
0x3691E03F52A0F9D1ULL, 0x5ED86E46E1878E80ULL, 0x3C711A0E99D07150ULL, 0x5A0865B20C4E9310ULL,
0x56FBFC1FE4F0682EULL, 0xEA8D5DE3105EDF9BULL, 0x71ABFDB12379187AULL, 0x2EB99DE1BEE77B9CULL,
0x21ECC0EA33CF4523ULL, 0x59A4D7521805C7A1ULL, 0x3896F5EB56AE7C72ULL, 0xAA638F3DB18F75DCULL,
0x9F39358DABE9808EULL, 0xB7DEFA91C00B72ACULL, 0x6B5541FD62492D92ULL, 0x6DC6DEE8F92E4D5BULL,
0x353F57ABC4BEEA7EULL, 0x735769D6DA5690CEULL, 0x0A234AA642391484ULL, 0xF6F9508028F80D9DULL,
0xB8E319A27AB3F215ULL, 0x31AD9C1151341A4DULL, 0x773C22A57BEF5805ULL, 0x45C7561A07968633ULL,
0xF913DA9E249DBE36ULL, 0xDA652D9B78A64C68ULL, 0x4C27A97F3BC334EFULL, 0x76621220E66B17F4ULL,
0x967743899ACD7D0BULL, 0xF3EE5BCAE0ED6782ULL, 0x409F753600C879FCULL, 0x06D09A39B5926DB6ULL,
0x6F83AEB0317AC588ULL, 0x01E6CA4A86381F21ULL, 0x66FF3462D19F3025ULL, 0x72207C24DDFD3BFBULL,
0x4AF6B6D3E2ECE2EBULL, 0x9C994DBEC7EA08DEULL, 0x49ACE597B09A8BC4ULL, 0xB38C4766CF0797BAULL,
0x131B9373C57C2A75ULL, 0xB1822CCE61931E58ULL, 0x9D7555B909BA1C0CULL, 0x127FAFDD937D11D2ULL,
0x29DA3BADC66D92E4ULL, 0xA2C1D57154C2ECBCULL, 0x58C5134D82F6FE24ULL, 0x1C3AE3515B62274FULL,
0xE907C82E01CB8126ULL, 0xF8ED091913E37FCBULL, 0x3249D8F9C80046C9ULL, 0x80CF9BEDE388FB63ULL,
0x1881539A116CF19EULL, 0x5103F3F76BD52457ULL, 0x15B7E6F5AE47F7A8ULL, 0xDBD7C6DED47E9CCFULL,
0x44E55C410228BB1AULL, 0xB647D4255EDB4E99ULL, 0x5D11882BB8AAFC30ULL, 0xF5098BBB29D3212AULL,
0x8FB5EA14E90296B3ULL, 0x677B942157DD025AULL, 0xFB58E7C0A390ACB5ULL, 0x89D3674C83BD4A01ULL,
0x9E2DA4DF4BF3B93BULL, 0xFCC41E328CAB4829ULL, 0x03F38C96BA582C52ULL, 0xCAD1BDBD7FD85DB2ULL,
0xBBB442C16082AE83ULL, 0xB95FE86BA5DA9AB0ULL, 0xB22E04673771A93FULL, 0x845358C9493152D8ULL,
0xBE2A488697B4541EULL, 0x95A2DC2DD38E6966ULL, 0xC02C11AC923C852BULL, 0x2388B1990DF2A87BULL,
0x7C8008FA1B4F37BEULL, 0x1F70D0C84D54E503ULL, 0x5490ADEC7ECE57D4ULL, 0x002B3C27D9063A3AULL,
0x7EAEA3848030A2BFULL, 0xC602326DED2003C0ULL, 0x83A7287D69A94086ULL, 0xC57A5FCB30F57A8AULL,
0xB56844E479EBE779ULL, 0xA373B40F05DCBCE9ULL, 0xD71A786E88570EE2ULL, 0x879CBACDBDE8F6A0ULL,
0x976AD1BCC164A32FULL, 0xAB21E25E9666D78BULL, 0x901063AAE5E5C33CULL, 0x9818B34448698D90ULL,
0xE36487AE3E1E8ABBULL, 0xAFBDF931893BDCB4ULL, 0x6345A0DC5FBBD519ULL, 0x8628FE269B9465CAULL,
0x1E5D01603F9C51ECULL, 0x4DE44006A15049B7ULL, 0xBF6C70E5F776CBB1ULL, 0x411218F2EF552BEDULL,
0xCB0C0708705A36A3ULL, 0xE74D14754F986044ULL, 0xCD56D9430EA8280EULL, 0xC12591D7535F5065ULL,
0xC83223F1720AEF96ULL, 0xC3A0396F7363A51FULL };
consteval uint64_t buff_to_uint64_with_filling (const char* parStr, const uint64_t parAvailLen) {
return (
parAvailLen == 0 ?
0
:
//static_cast<uint64_t>(static_cast<uint8_t>(parStr[0])) <<
// (CHAR_BIT * (parAvailLen - 1)) bitor buff_to_uint64_with_filling(parStr + 1, parAvailLen - 1)
static_cast<uint64_t>(static_cast<uint8_t>(parStr[0])) bitor (buff_to_uint64_with_filling(parStr + 1, parAvailLen - 1) << CHAR_BIT)
);
}
consteval uint64_t buff_to_uint64_fill_ifn (const char* parStr, uint64_t parIndex, uint64_t parBuffLen, char parPad) {
return (sizeof(uint64_t) * parIndex >= parBuffLen ?
(sizeof(uint64_t) * parIndex == parBuffLen ?
static_cast<uint64_t>(static_cast<uint8_t>(parPad))
:
0
)
:
(sizeof(uint64_t) * parIndex + sizeof(uint64_t) <= parBuffLen ?
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * parIndex, sizeof(uint64_t))
:
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * parIndex, parBuffLen % sizeof(uint64_t)) bitor
static_cast<uint64_t>(static_cast<uint8_t>(parPad)) << ((parBuffLen % sizeof(uint64_t)) * CHAR_BIT)
)
);
}
struct TigerBlock {
consteval explicit TigerBlock ( const char* parStr ) :
data{
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 0, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 1, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 2, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 3, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 4, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 5, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 6, sizeof(uint64_t)),
buff_to_uint64_with_filling(parStr + sizeof(uint64_t) * 7, sizeof(uint64_t))
}
{
}
consteval TigerBlock ( const TigerBlock& ) = default;
consteval TigerBlock ( uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e, uint64_t f, uint64_t g, uint64_t h) :
data{a, b, c, d, e, f, g, h}
{
}
consteval TigerBlock ( const char* parStr, uint64_t parLen, char parPad ) :
data{
buff_to_uint64_fill_ifn(parStr, 0, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 1, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 2, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 3, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 4, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 5, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 6, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 7, parLen, parPad)
}
{
}
consteval TigerBlock ( const char* parStr, uint64_t parLen, char parPad, uint64_t parData7 ) :
data{
buff_to_uint64_fill_ifn(parStr, 0, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 1, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 2, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 3, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 4, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 5, parLen, parPad),
buff_to_uint64_fill_ifn(parStr, 6, parLen, parPad),
(parLen + 1 <= sizeof(uint64_t) * 7 ? parData7 : throw 0)
}
{
}
consteval uint64_t operator[] (std::size_t parIndex) const { return (parIndex < lengthof(data) ? data[parIndex] : throw 0); }
const uint64_t data[8];
};
consteval uint64_t gb (uint64_t r, uint64_t a) {
return (r >> (a * CHAR_BIT)) bitand 0xff;
}
consteval TigerHash round (uint64_t mul, uint64_t a, uint64_t b, uint64_t c, uint64_t x, const TigerBlock& block, const TigerHash& hash) {
return TigerHash(
a,
hash[a] - (
table[ gb(hash[c] xor block[x], 0)] xor
table[256 + gb(hash[c] xor block[x], 2)] xor
table[512 + gb(hash[c] xor block[x], 4)] xor
table[768 + gb(hash[c] xor block[x], 6)]),
b,
(hash[b] + (
table[768 + gb(hash[c] xor block[x], 1)] xor
table[512 + gb(hash[c] xor block[x], 3)] xor
table[256 + gb(hash[c] xor block[x], 5)] xor
table[ gb(hash[c] xor block[x], 7)])) * mul,
c,
hash[c] xor block[x]
);
}
consteval TigerHash pass (uint64_t a, uint64_t b, uint64_t c, uint64_t mul, const TigerBlock& block, const TigerHash& hash, uint64_t x=0) {
return (
8 == x ?
//if 0 == x
hash
: //else
pass(
b,
c,
a,
mul,
block,
round(mul, a, b, c, x, block, hash),
x + 1
)
);
}
template <uint64_t I, uint64_t S> consteval uint64_t key_sched_op (const TigerBlock& i);
template<> consteval uint64_t key_sched_op<0,1> (const TigerBlock& i) { return i[0] - (i[7] ^ 0xA5A5A5A5A5A5A5A5ULL); }
template<> consteval uint64_t key_sched_op<1,1> (const TigerBlock& i) { return i[1] ^ key_sched_op<0,1>(i); }
template<> consteval uint64_t key_sched_op<2,1> (const TigerBlock& i) { return i[2] + key_sched_op<1,1>(i); }
template<> consteval uint64_t key_sched_op<3,1> (const TigerBlock& i) { return i[3] - (key_sched_op<2,1>(i) ^ ((~key_sched_op<1,1>(i)) << 19)); }
template<> consteval uint64_t key_sched_op<4,1> (const TigerBlock& i) { return i[4] ^ key_sched_op<3,1>(i); }
template<> consteval uint64_t key_sched_op<5,1> (const TigerBlock& i) { return i[5] + key_sched_op<4,1>(i); }
template<> consteval uint64_t key_sched_op<6,1> (const TigerBlock& i) { return i[6] - (key_sched_op<5,1>(i) ^ ((~key_sched_op<4,1>(i)) >> 23)); }
template<> consteval uint64_t key_sched_op<7,1> (const TigerBlock& i) { return i[7] ^ key_sched_op<6,1>(i); }
template<> consteval uint64_t key_sched_op<0,2> (const TigerBlock& i) { return key_sched_op<0,1>(i) + key_sched_op<7,1>(i); }
template<> consteval uint64_t key_sched_op<1,2> (const TigerBlock& i) { return key_sched_op<1,1>(i) - (key_sched_op<0,2>(i) ^ ((~key_sched_op<7,1>(i)) << 19)); }
template<> consteval uint64_t key_sched_op<2,2> (const TigerBlock& i) { return key_sched_op<2,1>(i) ^ key_sched_op<1,2>(i); }
template<> consteval uint64_t key_sched_op<3,2> (const TigerBlock& i) { return key_sched_op<3,1>(i) + key_sched_op<2,2>(i); }
template<> consteval uint64_t key_sched_op<4,2> (const TigerBlock& i) { return key_sched_op<4,1>(i) - (key_sched_op<3,2>(i) ^ ((~key_sched_op<2,2>(i)) >> 23)); }
template<> consteval uint64_t key_sched_op<5,2> (const TigerBlock& i) { return key_sched_op<5,1>(i) ^ key_sched_op<4,2>(i); }
template<> consteval uint64_t key_sched_op<6,2> (const TigerBlock& i) { return key_sched_op<6,1>(i) + key_sched_op<5,2>(i); }
template<> consteval uint64_t key_sched_op<7,2> (const TigerBlock& i) { return key_sched_op<7,1>(i) - (key_sched_op<6,2>(i) ^ 0x0123456789ABCDEFULL); }
consteval TigerBlock key_sched (const TigerBlock& parBlock) {
return TigerBlock(
key_sched_op<0,2>(parBlock),
key_sched_op<1,2>(parBlock),
key_sched_op<2,2>(parBlock),
key_sched_op<3,2>(parBlock),
key_sched_op<4,2>(parBlock),
key_sched_op<5,2>(parBlock),
key_sched_op<6,2>(parBlock),
key_sched_op<7,2>(parBlock)
);
}
consteval TigerHash finalize_tiger_step (TigerHash parOriginal, TigerHash parPartial) {
return TigerHash(
parPartial.a ^ parOriginal.a,
parPartial.b - parOriginal.b,
parPartial.c + parOriginal.c
);
}
consteval TigerHash tiger_block (const TigerBlock& parBlock, TigerHash parHash) {
return finalize_tiger_step(
parHash,
pass(1, 2, 0, 9, key_sched(key_sched(parBlock)),
pass(2, 0, 1, 7, key_sched(parBlock),
pass(0, 1, 2, 5, parBlock, parHash)
)
)
);
}
consteval TigerHash tiger_block (const char* parStr, TigerHash parHash) {
return tiger_block(TigerBlock(parStr), parHash);
}
consteval TigerHash tiger_chunk (const char* parStr, uint64_t parLen, TigerHash parHash) {
return (parLen == 0 ?
//if parLen == 0
parHash
:
//else
tiger_chunk(parStr + 64, parLen - 64, tiger_block(parStr, parHash))
);
}
consteval TigerHash tiger_last_chunk (const char* parStr, uint64_t parLen, uint64_t parRealLen, TigerHash parHash, char parPad) {
return (
parLen + 1 + ((8 - parLen - 1) bitand 7) == 64 ?
tiger_block(
TigerBlock(0, 0, 0, 0, 0, 0, 0, parRealLen << uint64_t(3)),
tiger_block(TigerBlock(parStr, parLen, parPad), parHash)
)
:
tiger_block(TigerBlock(parStr, parLen, parPad, parRealLen << uint64_t(3)), parHash)
);
}
} //namespace implem
consteval TigerHash tiger (const char* parStr, uint64_t parLen, char parPad) {
return implem::tiger_last_chunk(
parStr + (parLen bitand ~static_cast<uint64_t>(0x3f)),
parLen - (parLen bitand ~static_cast<uint64_t>(0x3f)),
parLen,
implem::tiger_chunk(
parStr,
parLen bitand ~static_cast<uint64_t>(0x3f),
TigerHash{0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL, 0xF096A5B4C3B2E187ULL}
),
parPad
);
}
} //namespace dhandy::bt

View file

@ -1,149 +0,0 @@
/* Copyright 2016-2020 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id6109D5EDE99D43C4909F084A231BF2C2
#define id6109D5EDE99D43C4909F084A231BF2C2
#include <vector>
#include <cstddef>
#include <type_traits>
#include <cassert>
#if !defined(AssertNotReached)
# define AssertNotReached() assert(false)
#endif
#if !defined(AssertRelease)
# define AssertRelease(a) assert(a)
#endif
#if !defined(Assert)
# define Assert(a) assert(a)
#endif
namespace duckmem {
namespace Implem {
template <typename P>
class TreeIterator_base {
template <typename P1> friend class TreeIterator_base;
public:
explicit TreeIterator_base ( void ) {}
TreeIterator_base ( const TreeIterator_base& parOther );
template <typename P1>
explicit TreeIterator_base ( const TreeIterator_base<P1>& parOther );
~TreeIterator_base ( void ) {}
protected:
typedef std::vector<P> StackType;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
bool Exhausted ( void ) const;
StackType m_stack;
};
template <typename T, typename N, bool Const>
class TreeIterator_const_layer;
template <typename T, typename N>
class TreeIterator_const_layer<T, N, true> : protected TreeIterator_base<const N*> {
template <typename T1, typename N1, bool Const1> friend class TreeIterator_const_layer;
typedef TreeIterator_base<const N*> parent_type;
public:
typedef const T* pointer;
typedef const T* const_pointer;
typedef const T& reference;
typedef const T& const_reference;
typedef typename parent_type::size_type size_type;
typedef typename parent_type::difference_type difference_type;
typedef N NodeType;
typedef const N* NodeTypePointer;
enum { IS_CONST = 1 };
TreeIterator_const_layer ( void ) {}
TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
TreeIterator_const_layer ( TreeIterator_const_layer&& ) = default;
template <typename T1, bool C1>
explicit TreeIterator_const_layer ( const TreeIterator_const_layer<T1, N, C1>& parOther ) : parent_type(parOther) {}
const_reference operator* ( void ) const;
const_pointer operator-> ( void ) const;
const N* GetPointer ( void ) const;
protected:
typedef typename parent_type::StackType StackType;
};
template <typename T, typename N>
class TreeIterator_const_layer<T, N, false> : protected TreeIterator_base<N*> {
template <typename T1, typename N1, bool Const1> friend class TreeIterator_const_layer;
typedef TreeIterator_base<N*> parent_type;
public:
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef typename parent_type::size_type size_type;
typedef typename parent_type::difference_type difference_type;
typedef N NodeType;
typedef N* NodeTypePointer;
enum { IS_CONST = 0 };
TreeIterator_const_layer ( void ) {}
TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
template <typename T1, bool C1>
explicit TreeIterator_const_layer ( const TreeIterator_const_layer<T1, N, C1>& parOther ) : parent_type(parOther) {}
reference operator* ( void );
const_reference operator* ( void ) const;
pointer operator-> ( void );
const_pointer operator-> ( void ) const;
const N* GetPointer ( void ) const;
N* GetPointer ( void );
protected:
typedef typename parent_type::StackType StackType;
};
} //namespace Implem
template <typename T, typename N>
class TreeIterator : public Implem::TreeIterator_const_layer<T, N, std::is_const<T>::value> {
typedef Implem::TreeIterator_const_layer<T, N, std::is_const<T>::value> parent_type;
typedef typename parent_type::NodeTypePointer NodeTypePointer;
typedef typename parent_type::NodeType NodeType;
typedef typename parent_type::StackType StackType;
public:
typedef T value_type;
typedef std::forward_iterator_tag iterator_category;
typedef typename parent_type::difference_type difference_type;
typedef typename parent_type::size_type size_type;
typedef typename parent_type::pointer pointer;
typedef typename parent_type::const_pointer const_pointer;
typedef typename parent_type::reference reference;
typedef typename parent_type::const_reference const_reference;
TreeIterator ( void );
TreeIterator ( const TreeIterator& parOther );
TreeIterator ( NodeTypePointer parRoot, size_type parMaxDepthHint );
template <typename S>
TreeIterator ( S parCopyStackBottomUp, size_type parStackLen, size_type parMaxDepthHint );
template <typename T1>
TreeIterator ( const TreeIterator<T1, N>& parOther );
~TreeIterator ( void );
const TreeIterator& operator= ( const TreeIterator& parOther );
bool operator== ( const TreeIterator& parOther ) const;
bool operator!= ( const TreeIterator& parOther ) const { return not (*this == parOther); }
TreeIterator& operator++ ( void ); //pre
TreeIterator operator++ ( int ); //post
private:
void RecurseLeft ( NodeTypePointer parFrom );
};
} //namespace duckmem
#include "implem/tree_iterator.inl"
#endif

View file

@ -0,0 +1,41 @@
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstddef>
namespace dhandy::bt {
template <typename T, T... V>
struct variadic_repeat {
};
namespace detail {
template <std::size_t N, typename T, T V0, T... V>
struct VariadicRepeatBuilder;
template <typename T, T V0, T... V>
struct VariadicRepeatBuilder<0, T, V0, V...> {
typedef variadic_repeat<T, V...> type;
};
template <std::size_t N, typename T, T V0, T... V>
struct VariadicRepeatBuilder : public VariadicRepeatBuilder<N-1, T, V0, V..., V0> {
};
} //namespace detail
template <std::size_t Count, typename T, T Val=T{}>
using make_variadic_repeat = typename detail::VariadicRepeatBuilder<Count, T, Val>::type;
} //namespace dhandy::bt

View file

@ -0,0 +1,101 @@
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef id5594416333AA4792BFEC94E863E03B08
#define id5594416333AA4792BFEC94E863E03B08
#include "int_conv.hpp"
#include <cstddef>
#include <stdexcept>
namespace dhandy::bt {
template <std::size_t N>
class Version {
public:
constexpr static const std::size_t count = N;
constexpr Version (const char* const ver, bool accept_less=false);
constexpr unsigned int operator[] (std::size_t idx) const;
constexpr unsigned int major() const;
constexpr unsigned int minor() const;
constexpr unsigned int revision() const;
private:
unsigned int m_versions[N];
};
template <std::size_t N>
inline constexpr Version<N>::Version (const char* const ver, bool accept_less) :
m_versions{0}
{
std::size_t z = 0;
std::size_t s = 0;
std::size_t idx = 0;
bool commit = false;
do {
if (ver[z] >= '0' and ver[z] <= '9') {
commit = true;
}
else if (commit) {
commit = false;
m_versions[idx++] = dhandy::ary_to_int<unsigned int>(ver + s, ver + z);
s = z + 1;
}
else {
s = z + 1;
}
} while(ver[z++] and idx < N);
if (not accept_less and idx < N)
throw std::invalid_argument("Input version doesn't contain enough version numbers");
}
template <std::size_t N>
inline constexpr unsigned int Version<N>::operator[] (std::size_t idx) const {
if (idx < N)
return m_versions[idx];
else
throw std::out_of_range("Index is out of range");
}
template <std::size_t N>
inline constexpr unsigned int Version<N>::major() const {
return m_versions[0];
}
template <std::size_t N>
inline constexpr unsigned int Version<N>::minor() const {
if constexpr (N > 1)
return m_versions[1];
else
throw std::out_of_range("Not enough version entries, there is no minor number");
}
template <std::size_t N>
inline constexpr unsigned int Version<N>::revision() const {
if constexpr (N > 2)
return m_versions[2];
else
throw std::out_of_range("Not enough version entries, there is no revision number");
}
} //namespace dhandy::bt
#endif

32
include/meson.build Normal file
View file

@ -0,0 +1,32 @@
if not meson.is_subproject() and meson.version().version_compare('>=0.63.0')
install_headers(
'duckhandy/implem/IteratorOnPtr.hpp',
'duckhandy/implem/AutomemBase.hpp',
'duckhandy/implem/AutomemBase.inl',
'duckhandy/implem/int_conv.hpp',
'duckhandy/implem/reversed_sized_array_bt.hpp',
'duckhandy/version_bt.hpp',
'duckhandy/has_method.hpp',
'duckhandy/MaxSizedArray.hpp',
'duckhandy/MaxSizedArray.inl',
'duckhandy/bitfield_pack.hpp',
'duckhandy/cmake_on_off.h',
'duckhandy/compatibility.h',
'duckhandy/ducktypes.hpp',
'duckhandy/endianness.hpp',
'duckhandy/tiger_bt.hpp',
'duckhandy/infix_iterator.hpp',
'duckhandy/int_conv.hpp',
'duckhandy/int_types.hpp',
'duckhandy/lengthof.h',
'duckhandy/nomove_storage.hpp',
'duckhandy/resource_pool.hpp',
'duckhandy/tiger_bt.inl',
'duckhandy/string.hpp',
'duckhandy/string_bt.hpp',
'duckhandy/string_view.hpp',
'duckhandy/stringize.h',
'duckhandy/variadic_repeat_bt.hpp',
preserve_path: true, #meson v0.63.0
)
endif

@ -1 +0,0 @@
Subproject commit 89f5f8435176aad44624442b7f1e874a513bee67

23
meson.build Normal file
View file

@ -0,0 +1,23 @@
project('duckhandy', 'cpp',
version: '0.1.0',
meson_version: '>=0.56.0',
default_options: ['buildtype=release', 'cpp_std=gnu++20', 'b_ndebug=if-release']
)
sprout_dep = dependency('sprout', allow_fallback: true)
public_incl = include_directories('include')
duckhandy_dep = declare_dependency(
include_directories: [
public_incl,
],
dependencies: [sprout_dep],
)
meson.override_dependency(meson.project_name(), duckhandy_dep)
if get_option('build_testing')
subdir('test')
endif
subdir('include')

1
meson_options.txt Normal file
View file

@ -0,0 +1 @@
option('build_testing', type: 'boolean', value: true)

56
speed_test_int_conv.cpp Normal file
View file

@ -0,0 +1,56 @@
#include "duckhandy/int_conv.hpp"
#include <iostream>
#include <random>
#include <chrono>
#include <vector>
#include <string>
#include <algorithm>
#include <ctime>
namespace {
template <typename Conv>
void run_with_timing (
const std::string& test_name,
const std::vector<unsigned int>& src,
std::vector<std::string>& dst,
Conv&& conv_func
) {
dst.clear();
dst.resize(src.size());
std::cout << test_name << "...\n";
const std::size_t count = src.size();
const auto t0 = std::chrono::high_resolution_clock::now();
for (std::size_t z = 0; z < count; ++z) {
dst[z] = conv_func(src[z]);
}
const auto t1 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = t1 - t0;
std::cout << count << " conversions completed in " << duration.count() << " seconds\n";
}
} //unnamed namespace
int main() {
using dhandy::int_conv;
constexpr const std::size_t count = 70'000'000;
std::vector<unsigned int> nums;
std::vector<std::string> strings;
std::mt19937 gen;
std::cout << "Setting up data...\n";
nums.resize(count);
strings.reserve(count);
gen.seed(std::time(nullptr));
std::cout << "Generating " << count << " random values...\n";
std::generate(nums.begin(), nums.end(), gen);
run_with_timing("Conversions with std::to_string", nums, strings, [](unsigned int n) { return std::to_string(n); });
run_with_timing("AryConversion with dhandy::int_conv", nums, strings, [](unsigned int n) { return int_conv<std::string>(n); });
std::cout << "All done, bye!\n";
return 0;
}

7
subprojects/Catch2.wrap Normal file
View file

@ -0,0 +1,7 @@
[wrap-git]
revision = b5373dadca40b7edc8570cf9470b9b1cb1934d40
url = https://github.com/catchorg/Catch2.git
[provide]
catch2-with-main = catch2_with_main_dep
Catch2 = catch2_dep

File diff suppressed because it is too large Load diff

7
subprojects/sprout.wrap Normal file
View file

@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/bolero-MURAKAMI/Sprout.git
revision = head
patch_directory = sprout
[provide]
dependency_names = sprout-20190615

1
test/meson.build Normal file
View file

@ -0,0 +1 @@
subdir('unit')

View file

@ -1,19 +1,20 @@
project(dhandy_unit_test CXX)
add_executable(${PROJECT_NAME}
int_conv_test.cpp
main.cpp
endianness_test.cpp
int_conv_test.cpp
reversed_sized_array_test.cpp
bitfield_pack_test.cpp
resource_pool_test.cpp
scapegoat_tree_test.cpp
version_test.cpp
tiger_test.cpp
)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
target_include_directories(${PROJECT_NAME}
PRIVATE ${DUCKHANDY_SOURCE_DIR}/lib/Catch2/single_include
PRIVATE ${DUCKHANDY_SOURCE_DIR}/subprojects/Catch2/Catch2/single_include
)
target_link_libraries(${PROJECT_NAME}

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -15,7 +15,7 @@
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch.hpp"
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/bitfield_pack.hpp"
#include <cstdint>

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -15,7 +15,7 @@
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch.hpp"
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/endianness.hpp"
#include <endian.h>

View file

@ -0,0 +1,58 @@
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/infix_iterator.hpp"
#include <algorithm>
#include <sstream>
#include <vector>
TEST_CASE("infix_iterator tests", "[iterator][infix_iterator]") {
using std::vector;
using std::string;
using std::copy;
using std::ostringstream;
using dhandy::infix_ostream_iterator;
{
ostringstream oss;
vector<string> empty{};
copy(empty.begin(), empty.end(), infix_ostream_iterator<string>(oss, "lalala"));
CHECK(oss.str() == "");
}
{
ostringstream oss;
vector<string> data{"apple", "pear", "cherry", "mango"};
copy(data.begin(), data.end(), infix_ostream_iterator<string>(oss, "lalala"));
CHECK(oss.str() == "applelalalapearlalalacherrylalalamango");
}
{
ostringstream oss;
vector<int> data{1, 2, 3, 4, 5, 6, 7};
copy(data.begin(), data.end(), infix_ostream_iterator<int>(oss, ", "));
CHECK(oss.str() == "1, 2, 3, 4, 5, 6, 7");
}
{
ostringstream oss;
vector<string> data{"just one value"};
copy(data.begin(), data.end(), infix_ostream_iterator<string>(oss, ", "));
CHECK(oss.str() == "just one value");
}
}

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -15,7 +15,7 @@
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch.hpp"
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/int_conv.hpp"
#include "duckhandy/string_bt.hpp"
#include "sprout/cstring/strlen.hpp"
@ -23,20 +23,47 @@
#include <cstdint>
#include <random>
#include <string>
#include <ctime>
template <typename T> using int_info_10 = dhandy::implem::int_info<T, 10>;
template <typename T> using int_info_16 = dhandy::implem::int_info<T, 16>;
template <typename T> using int_info_2 = dhandy::implem::int_info<T, 2>;
namespace {
template <unsigned int Base>
struct ASCIITranslatorIns : public dhandy::ASCIITranslator<char> {
static const constexpr char AltLetter = 'A';
static constexpr int from_digit (char dig) {
if (dig >= FirstLetter and dig <= FirstLetter + Base - 10 - 1)
return dig - FirstLetter + 10;
else
return dig - AltLetter + 10;
}
};
template <typename T, unsigned int Base>
void AryConversionTestHelper (const std::string_view& s, T expected) {
using AryConversion = dhandy::implem::AryConversion<T, Base, dhandy::ASCIITranslator<char>>;
void AryConversionTestHelper (const std::string_view& s, T expected, bool expect_sse) {
using AryConversion = dhandy::implem::AryConversion<T, Base, dhandy::ASCIITranslator<char>, false>;
CHECK(AryConversion::is_sse == expect_sse);
CHECK(AryConversion::from_ary(s.data(), s.data() + s.size()) == expected);
}
template <typename T, unsigned int Base>
void AryConversionTestHelperUp (const std::string_view& s, T expected, bool expect_sse) {
using AryConversion = dhandy::implem::AryConversion<T, Base, dhandy::ASCIITranslatorUpcase<char>, false>;
CHECK(AryConversion::is_sse == expect_sse);
CHECK(AryConversion::from_ary(s.data(), s.data() + s.size()) == expected);
}
template <typename T, unsigned int Base>
void AryConversionTestHelperIns (const std::string_view& s, T expected, bool expect_sse) {
using AryConversion = dhandy::implem::AryConversion<T, Base, ASCIITranslatorIns<Base>, false>;
CHECK(AryConversion::is_sse == expect_sse);
CHECK(AryConversion::from_ary(s.data(), s.data() + s.size()) == expected);
}
} //unnamed namespace
TEST_CASE ("Check int to char array conversions", "[s2i][int_conv]") {
TEST_CASE ("Check int to char array conversions", "[i2s][int_conv]") {
using dhandy::int_to_ary;
using dhandy::bt::string;
using dhandy::bt::make_string;
@ -74,6 +101,7 @@ TEST_CASE ("Check int to char array conversions", "[s2i][int_conv]") {
CHECK(int_to_ary<int64_t>(-1) == "-1");
CHECK(int_to_ary<int64_t>(0x1000000000000000) == "1152921504606846976");
CHECK(int_to_ary<int64_t>(0xF000000000000000) == "-1152921504606846976");
CHECK(int_to_ary<int, 16, dhandy::ASCIITranslatorUpcase<char>>(255) == "FF");
CHECK(int_to_ary<uint16_t SPROUT_PP_COMMA() 16>(0xFFFF) == "ffff");
CHECK(int_to_ary<uint16_t SPROUT_PP_COMMA() 16>(0xCACA) == "caca");
@ -115,7 +143,7 @@ TEST_CASE ("Check int to char array conversions", "[s2i][int_conv]") {
{
//Try a random test, which should not compile as constexpr
std::mt19937 gen;
gen.seed(1234);
gen.seed(std::time(nullptr));
for (int z = 0; z < 10; ++z) {
const int num = gen();
CHECK(int_to_ary(num) == std::to_string(num));
@ -129,30 +157,137 @@ TEST_CASE ("Check int to char array conversions", "[s2i][int_conv]") {
}
}
TEST_CASE ("Check char array to int conversions", "[i2s][int_conv]") {
AryConversionTestHelper<uint32_t, 10>("0", 0);
AryConversionTestHelper<int32_t, 10>("0", 0);
AryConversionTestHelper<int16_t, 10>("0", 0);
AryConversionTestHelper<int16_t, 16>("ff", 0xff);
AryConversionTestHelper<uint8_t, 16>("ff", 0xff);
AryConversionTestHelper<uint32_t, 36>("rs", 1000);
AryConversionTestHelper<uint16_t, 8>("20", 16);
AryConversionTestHelper<int32_t, 10>("1", 1);
AryConversionTestHelper<int32_t, 10>("10", 10);
AryConversionTestHelper<int32_t, 10>("100", 100);
AryConversionTestHelper<int32_t, 10>("999", 999);
AryConversionTestHelper<int32_t, 10>("1000", 1000);
AryConversionTestHelper<int32_t, 10>("1001", 1001);
AryConversionTestHelper<int32_t, 10>("12345", 12345);
AryConversionTestHelper<int32_t, 10>("123456", 123456);
AryConversionTestHelper<int32_t, 10>("1234567", 1234567);
AryConversionTestHelper<int32_t, 10>("12345678", 12345678);
AryConversionTestHelper<int32_t, 10>("123456789", 123456789);
AryConversionTestHelper<int32_t, 10>("2147483647", 2147483647);
AryConversionTestHelper<uint64_t, 16>("ffffffffffffffff", 0xffffffffffffffff);
AryConversionTestHelper<int64_t, 16>("ffffffffffffffff", 0xffffffffffffffff);
AryConversionTestHelper<int64_t, 16>("7fffffffffffffff", 0x7fffffffffffffff);
AryConversionTestHelper<int32_t, 16>("7fffffff", 0x7fffffff);
AryConversionTestHelper<bool, 10>("1", true);
AryConversionTestHelper<bool, 10>("0", false);
TEST_CASE ("Check char array to int conversions", "[s2i][int_conv]") {
AryConversionTestHelper<std::uint32_t, 10>("0", 0, true);
AryConversionTestHelper<std::int32_t, 10>("0", 0, true);
AryConversionTestHelper<std::int16_t, 10>("0", 0, true);
AryConversionTestHelper<std::int16_t, 16>("ff", 0xff, true);
AryConversionTestHelper<std::uint8_t, 16>("ff", 0xff, true);
AryConversionTestHelper<std::uint32_t, 36>("rs", 1000, true);
AryConversionTestHelper<std::uint16_t, 8>("20", 16, true);
AryConversionTestHelper<std::int32_t, 10>("1", 1, true);
AryConversionTestHelper<std::int32_t, 10>("10", 10, true);
AryConversionTestHelper<std::int32_t, 10>("100", 100, true);
AryConversionTestHelper<std::int32_t, 10>("999", 999, true);
AryConversionTestHelper<std::int32_t, 10>("1000", 1000, true);
AryConversionTestHelper<std::int32_t, 10>("1001", 1001, true);
AryConversionTestHelper<std::int32_t, 10>("12345", 12345, true);
AryConversionTestHelper<std::int32_t, 10>("123456", 123456, true);
AryConversionTestHelper<std::int32_t, 10>("1234567", 1234567, true);
AryConversionTestHelper<std::int32_t, 10>("12345678", 12345678, true);
AryConversionTestHelper<std::int32_t, 10>("123456789", 123456789, true);
AryConversionTestHelper<std::int32_t, 10>("2147483647", 2147483647, true);
AryConversionTestHelper<std::uint64_t, 16>("ffffffffffffffff", 0xffffffffffffffff, false);
AryConversionTestHelper<std::int64_t, 16>("ffffffffffffffff", 0xffffffffffffffff, false);
AryConversionTestHelper<std::int64_t, 16>("7fffffffffffffff", 0x7fffffffffffffff, false);
AryConversionTestHelper<std::int32_t, 16>("7fffffff", 0x7fffffff, true);
AryConversionTestHelper<bool, 10>("1", true, false);
AryConversionTestHelper<bool, 10>("0", false, false);
AryConversionTestHelperUp<std::uint64_t, 16>("ABCDEF123456ABCD", 0xabcdef123456abcd, false);
AryConversionTestHelper<signed int, 10>("-1", -1, sizeof(signed int) <= sizeof(std::uint32_t));
AryConversionTestHelper<signed int, 10>("-50000", -50000, sizeof(signed int) <= sizeof(std::uint32_t));
AryConversionTestHelper<std::int64_t, 10>("-1", -1, false);
AryConversionTestHelper<std::int64_t, 10>("-510123123123", -510123123123, false);
//case insensitive SSE conversions
AryConversionTestHelperIns<std::int32_t, 16>("7FfFfFfF", 0x7fffffff, true);
AryConversionTestHelperIns<std::int32_t, 16>("AbCdEf01", 0xabcdef01, true);
AryConversionTestHelperIns<std::int32_t, 16>("aBcDeF01", 0xabcdef01, true);
AryConversionTestHelperIns<std::uint8_t, 16>("Ff", 0xff, true);
AryConversionTestHelperIns<std::int16_t, 16>("AfBe", 0xafbe, true);
AryConversionTestHelperIns<std::int32_t, 16>("aAb", 0xaab, true);
AryConversionTestHelperIns<std::int32_t, 16>("aAbBc", 0xaabbc, true);
}
TEST_CASE ("Check string_view conversions work as expected", "[s2i][int_conv]") {
using dhandy::int_conv;
using dhandy::int_conv_raw;
using std::string_view;
using std::integral_constant;
using std::string;
constexpr auto str71 = int_conv<string_view>(integral_constant<short int, 71>{});
CHECK("71" == str71);
{
//test random number to force non-constexpr
std::mt19937 gen;
gen.seed(std::time(nullptr));
const int num = gen();
const string num_str {int_conv_raw(num).to_string_view()};
CHECK(num_str == std::to_string(num));
}
const auto str123 = int_conv<string>(123);
CHECK("123" == str123);
}
TEST_CASE ("Check std::array conversion works as expected", "[i2s][int_conv]") {
using std::array;
using dhandy::int_conv;
auto arr748 = int_conv<array<char, 3>>(748);
CHECK(arr748[0] == '7');
CHECK(arr748[1] == '4');
CHECK(arr748[2] == '8');
auto arr19000 = int_conv<array<char, 5>>(19);
CHECK(arr19000[0] == '1');
CHECK(arr19000[1] == '9');
CHECK(arr19000[2] == '\0');
CHECK(arr19000[3] == '\0');
CHECK(arr19000[4] == '\0');
}
TEST_CASE ("Check upcase/downcase int to array conversions", "[i2s][int_conv]") {
using dhandy::int_conv;
using std::string_view;
using std::integral_constant;
constexpr auto bool1 = int_conv<string_view>(integral_constant<bool, true>{});
CHECK("1" == bool1);
constexpr auto bool2 = int_conv<string_view>(integral_constant<bool, false>{});
CHECK("0" == bool2);
constexpr auto int1 = int_conv<string_view>(integral_constant<int, 42>{});
CHECK("42" == int1);
constexpr auto int2 = int_conv<string_view>(integral_constant<unsigned int, 7777777>{});
CHECK("7777777" == int2);
constexpr auto int3 = int_conv<string_view>(integral_constant<int, -1234>{});
CHECK("-1234" == int3);
constexpr auto int4 = int_conv<string_view>(integral_constant<short int, -256>{});
CHECK("-256" == int4);
}
TEST_CASE ("Try int conv with non-char", "[s2i][int_conv]") {
using dhandy::buildtime_int_to_ary;
using dhandy::ASCIITranslator;
std::wstring_view exp1(L"235713");
auto val1 = buildtime_int_to_ary<int, 235713, 10, ASCIITranslator<wchar_t>>().to_string_view();
CHECK(exp1 == val1);
}
TEST_CASE ("Check some fancy conversions", "[i2s][int_conv]") {
using dhandy::int_to_ary;
using std::string;
using MyFancyTranslator = dhandy::ASCIITranslator<char, '0', 'a', '+', '-', '\0', 4>;
string str1 = int_to_ary<int, 10, MyFancyTranslator>(3).to_string();
CHECK("3" == str1);
string str2 = int_to_ary<int, 10, MyFancyTranslator>(5).to_string();
CHECK("b" == str2);
string str3 = int_to_ary<int, 10, MyFancyTranslator>(11).to_string();
CHECK("11" == str3);
string str4 = int_to_ary<int, 10, MyFancyTranslator>(537).to_string();
CHECK("b3d" == str4);
}

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -15,5 +15,5 @@
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
//#define CATCH_CONFIG_MAIN
//#include "catch2/catch_test_macros.hpp"

20
test/unit/meson.build Normal file
View file

@ -0,0 +1,20 @@
catch2_dep = dependency('catch2-with-main', version: '>=3.5.2')
unit_test_prog = executable(meson.project_name(),
'int_conv_test.cpp',
'main.cpp',
'endianness_test.cpp',
'reversed_sized_array_test.cpp',
'bitfield_pack_test.cpp',
'resource_pool_test.cpp',
'version_test.cpp',
'tiger_test.cpp',
'infix_iterator.cpp',
install: false,
dependencies: [sprout_dep, catch2_dep],
include_directories: [public_incl],
)
test('unit_' + meson.project_name(),
unit_test_prog,
)

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -15,7 +15,7 @@
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch.hpp"
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/resource_pool.hpp"
#include <cstdint>

View file

@ -1,4 +1,4 @@
/* Copyright 2016-2020 Michele Santullo
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
@ -15,7 +15,7 @@
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch.hpp"
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/implem/reversed_sized_array_bt.hpp"
TEST_CASE ("Check conversion functions in ReversedSizedArray", "[ReversedSizedArray][containers]") {

View file

@ -1,152 +0,0 @@
/* Copyright 2016-2018 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch.hpp"
#include "duckhandy/scapegoat_tree.hpp"
#include <set>
TEST_CASE ("Insert values in a ScapegoatTree", "[Scapegoat][ScapegoatTree][containers]") {
using duckmem::ScapegoatTree;
ScapegoatTree<int> tree;
{
auto it = tree.insert(25);
CHECK(it.second == true);
CHECK(it.first != tree.end());
CHECK(*it.first == 25);
CHECK(tree.size() == 1);
}
{
auto it = tree.insert(25);
CHECK(tree.size() == 1);
CHECK(it.second == false);
CHECK(it.first != tree.end());
CHECK(*it.first == 25);
}
{
auto it = tree.insert(26);
CHECK(it.second == true);
CHECK(it.first != tree.end());
CHECK(*it.first == 26);
CHECK(tree.size() == 2);
}
{
for (std::size_t z = 0; z < 100; ++z) {
const int val = static_cast<int>(z);
auto it = tree.insert(val);
if (z < 25) {
CHECK(tree.size() == z + 2 + 1);
CHECK(it.second == true);
}
else if (z < 26) {
CHECK(tree.size() == z + 1 + 1);
CHECK(it.second == false);
}
else if (z < 27) {
CHECK(tree.size() == z + 1);
CHECK(it.second == false);
}
else {
CHECK(tree.size() == z + 1);
CHECK(it.second == true);
}
CHECK(*it.first == val);
}
}
{
auto end = tree.end();
int val = 0;
for (auto it = tree.begin(); it != end; ++it, ++val) {
CHECK(val == *it);
}
CHECK(static_cast<int>(tree.size()) == val);
val = 75;
for (auto it = tree.insert(val).first; it != end; ++it, ++val) {
CHECK(val == *it);
}
CHECK(static_cast<int>(tree.size()) == val);
}
}
TEST_CASE ("Erase values from a ScapegoatTree", "[Scapegoat][ScapegoatTree][containers]") {
using duckmem::ScapegoatTree;
//auto rand_num = std::bind(std::uniform_int_distribution<int>(1, 1000), std::mt19937(std::time(0)));
ScapegoatTree<int> tree;
for (int z = 0; z < 5000; ++z) {
tree.insert(z + 1);
}
CHECK(tree.size() == 5000);
std::set<int> cpy(tree.begin(), tree.end());
CHECK(cpy.size() == 5000);
{
auto it_num = tree.find(0);
CHECK(it_num == tree.end());
}
{
auto it_num = tree.find(1);
REQUIRE(it_num != tree.end());
CHECK(*it_num == 1);
CHECK(it_num == tree.begin());
tree.erase(it_num);
cpy.erase(1);
CHECK(tree.size() == 4999);
it_num = tree.find(1);
CHECK(it_num == tree.end());
CHECK(not tree.include(1));
}
{
auto it_num = tree.find(2345);
REQUIRE(it_num != tree.end());
CHECK(*it_num == 2345);
tree.erase(it_num);
cpy.erase(2345);
CHECK(tree.size() == 4998);
it_num = tree.find(2345);
CHECK(it_num == tree.end());
CHECK(not tree.include(2345));
}
{
auto it_num = tree.find(3000);
REQUIRE(it_num != tree.end());
int test_num = 3000;
for (; it_num != tree.end(); ++it_num) {
CHECK(*it_num == test_num);
test_num++;
}
CHECK(test_num == 5001);
}
{
const ScapegoatTree<int>& ref = tree;
auto it_num = ref.find(18);
REQUIRE(it_num != ref.end());
CHECK(*it_num == 18);
CHECK(ref.include(18));
}
REQUIRE(tree.size() == cpy.size());
CHECK(std::equal(tree.begin(), tree.end(), cpy.begin()));
}

56
test/unit/tiger_test.cpp Normal file
View file

@ -0,0 +1,56 @@
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/tiger_bt.hpp"
TEST_CASE("Build-time Tiger hash tests", "[hash][bt][tiger]") {
using dhandy::bt::tiger;
using dhandy::bt::TigerHash;
using dhandy::bt::TigerPaddingV1;
using dhandy::bt::TigerPaddingV2;
constexpr TigerHash h1 = tiger("", 0, TigerPaddingV2);
CHECK(h1.a == 0x738701f675be4144);
CHECK(h1.b == 0x924b374527c206c2);
CHECK(h1.c == 0x419f91ef3f31a84a);
constexpr TigerHash h2 = tiger("", 0, TigerPaddingV1);
CHECK(h2.a == 0x24f0130c63ac9332);
CHECK(h2.b == 0x16166e76b1bb925f);
CHECK(h2.c == 0xf373de2d49584e7a);
constexpr TigerHash h3 = tiger("message digest", 14, TigerPaddingV2);
CHECK(h3.a == 0x9d25fab5a11994e2);
CHECK(h3.b == 0xea7850e77d5e00e8);
CHECK(h3.c == 0x2d465225ef42a581);
constexpr TigerHash h4 = tiger("message digest", 14, TigerPaddingV1);
CHECK(h4.a == 0x951a2078cbf881d9);
CHECK(h4.b == 0x1c441e754830cf0d);
CHECK(h4.c == 0xf6295aa51aca7f51);
constexpr TigerHash h5 = tiger("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, TigerPaddingV2);
CHECK(h5.a == 0x517bee8c22b69aea);
CHECK(h5.b == 0x8c6c06a6fc4475b7);
CHECK(h5.c == 0xcd059531e6ba5bbb);
constexpr TigerHash h6 = tiger("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, TigerPaddingV1);
CHECK(h6.a == 0xee8375a180a6ce8d);
CHECK(h6.b == 0x5186363c8aa32b50);
CHECK(h6.c == 0xcca849dcccfb0f89);
}

View file

@ -0,0 +1,94 @@
/* Copyright 2016-2024 Michele Santullo
* This file is part of "duckhandy".
*
* "duckhandy" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "duckhandy" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
*/
#include "catch2/catch_test_macros.hpp"
#include "duckhandy/version_bt.hpp"
TEST_CASE ("Version class tests", "[version][bt]") {
using dhandy::bt::Version;
{
constexpr Version<1> ver{"102"};
static_assert(ver.major() == 102, "Version error");
static_assert(ver.count == 1, "Version error");
CHECK(ver[0] == 102);
CHECK_THROWS(ver[1]);
CHECK_THROWS(ver[2]);
CHECK_THROWS(ver[3]);
CHECK_THROWS(ver[4]);
}
{
constexpr Version<3> ver{".aheud15,a.ud22,cu.sh81,.nuad.h44"};
static_assert(ver.count == 3, "Version error");
static_assert(ver.major() == 15, "Version error");
static_assert(ver.minor() == 22, "Version error");
static_assert(ver.revision() == 81, "Version error");
CHECK(ver[0] == 15);
CHECK(ver[1] == 22);
CHECK(ver[2] == 81);
CHECK_THROWS(ver[3]);
CHECK_THROWS(ver[4]);
}
{
constexpr Version<10> ver{"1.2.3.44.55.66.777.888.999.101010"};
static_assert(ver.count == 10, "Version error");
static_assert(ver.major() == 1, "Version error");
static_assert(ver.minor() == 2, "Version error");
static_assert(ver.revision() == 3, "Version error");
CHECK(ver[0] == 1);
CHECK(ver[1] == 2);
CHECK(ver[2] == 3);
CHECK(ver[3] == 44);
CHECK(ver[4] == 55);
CHECK(ver[5] == 66);
CHECK(ver[6] == 777);
CHECK(ver[7] == 888);
CHECK(ver[8] == 999);
CHECK(ver[9] == 101010);
CHECK_THROWS(ver[10]);
}
{
constexpr Version<4> ver{"1.2.3.", true};
static_assert(ver.count == 4, "Version error");
static_assert(ver.major() == 1, "Version error");
static_assert(ver.minor() == 2, "Version error");
static_assert(ver.revision() == 3, "Version error");
CHECK(ver[0] == 1);
CHECK(ver[1] == 2);
CHECK(ver[2] == 3);
CHECK(ver[3] == 0);
CHECK_THROWS(ver[10]);
}
{
constexpr Version<4> ver{"6.7.2-r1"};
static_assert(ver.count == 4, "Version error");
static_assert(ver.major() == 6, "Version error");
static_assert(ver.minor() == 7, "Version error");
static_assert(ver.revision() == 2, "Version error");
CHECK(ver[0] == 6);
CHECK(ver[1] == 7);
CHECK(ver[2] == 2);
CHECK(ver[3] == 1);
CHECK_THROWS(ver[10]);
}
CHECK_THROWS(Version<4>{"4.5"});
}