Compare commits
54 commits
scapegoat_
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
96c6ac1df3 | ||
|
a2d6944249 | ||
|
cc129eb4e2 | ||
4d904ac689 | |||
d3092f9359 | |||
cd85666005 | |||
fc5f917970 | |||
180c338901 | |||
100b1d557e | |||
df2f614642 | |||
f04eb9f5d3 | |||
82b5200857 | |||
9919f1aeb2 | |||
e1599820b4 | |||
18cdd4d9b5 | |||
180f79fae9 | |||
c9b2d36491 | |||
a171faa95d | |||
a68815b3cd | |||
e3140a3add | |||
9dbabcb5c4 | |||
420257f578 | |||
199db7640e | |||
938c8fa9a4 | |||
a675624cab | |||
094f7fc679 | |||
e8467cebe0 | |||
d068e68e75 | |||
327d93a6a4 | |||
d3731253e4 | |||
db554b8b85 | |||
1ec0e143fd | |||
d0e7ca0bee | |||
9539b5430f | |||
562eba5f68 | |||
422b475ce3 | |||
e62da38cf9 | |||
7f8f092372 | |||
29f6a56fc8 | |||
eedad0d82c | |||
5ccf4dde55 | |||
5db217c978 | |||
710cdf9f04 | |||
b52343014b | |||
1f44e74465 | |||
13bd166827 | |||
3124548314 | |||
da136cd52f | |||
93d2ad6bd0 | |||
3343b51a39 | |||
40bae9c49d | |||
1c6de14cd4 | |||
f1d6ac789e | |||
79ca881bc1 |
58 changed files with 4433 additions and 1968 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
||||||
tags
|
tags
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
.clangd
|
.clangd
|
||||||
|
.cache
|
||||||
|
subprojects/Catch2/
|
||||||
|
subprojects/sprout/
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
||||||
[submodule "lib/Catch2"]
|
|
||||||
path = lib/Catch2
|
|
||||||
url = https://github.com/catchorg/Catch2.git
|
|
|
@ -2,16 +2,15 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||||
project(duckhandy VERSION 0.1.0)
|
project(duckhandy VERSION 0.1.0)
|
||||||
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
|
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
|
||||||
|
|
||||||
include(shared_git_project)
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
find_package(Sprout REQUIRED)
|
find_package(Sprout REQUIRED)
|
||||||
|
|
||||||
set(DUCKHANDY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
set(DUCKHANDY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
if (BUILD_TESTING)
|
if (BUILD_TESTING)
|
||||||
set(BUILD_TESTS CACHE BOOL ON)
|
set(BUILD_TESTING CACHE BOOL ON)
|
||||||
else()
|
else()
|
||||||
set(BUILD_TESTS CACHE BOOL OFF)
|
set(BUILD_TESTING CACHE BOOL OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} INTERFACE)
|
add_library(${PROJECT_NAME} INTERFACE)
|
||||||
|
@ -27,7 +26,7 @@ target_compile_features(${PROJECT_NAME}
|
||||||
INTERFACE cxx_decltype_incomplete_return_types
|
INTERFACE cxx_decltype_incomplete_return_types
|
||||||
INTERFACE cxx_noexcept
|
INTERFACE cxx_noexcept
|
||||||
INTERFACE cxx_rvalue_references
|
INTERFACE cxx_rvalue_references
|
||||||
INTERFACE cxx_std_17
|
INTERFACE cxx_std_20
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME}
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
@ -42,6 +41,10 @@ target_compile_definitions(${PROJECT_NAME}
|
||||||
INTERFACE SPROUT_USE_TEMPLATE_ALIASES
|
INTERFACE SPROUT_USE_TEMPLATE_ALIASES
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_compile_options(${PROJECT_NAME}
|
||||||
|
INTERFACE -mprfchw
|
||||||
|
)
|
||||||
|
|
||||||
if (BUILD_TESTING)
|
if (BUILD_TESTING)
|
||||||
add_subdirectory(test/unit)
|
add_subdirectory(test/unit)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -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()
|
|
|
@ -1,2 +0,0 @@
|
||||||
inplace_submodules:
|
|
||||||
- Sprout
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2025 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
@ -99,7 +99,8 @@ namespace dhandy {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
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;
|
return (1 << len) - 1;
|
||||||
}
|
}
|
||||||
} //namespace implem
|
} //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, 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);
|
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;
|
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:
|
public:
|
||||||
BitfieldPack (T init=T{}) : base_type(init) {}
|
BitfieldPack (T init=T{}) : base_type(init) {}
|
||||||
};
|
};
|
||||||
|
@ -136,14 +137,15 @@ namespace dhandy {
|
||||||
const constexpr bool bleeds_into_next = reloffs + so.size > sizeof(T) * CHAR_BIT;
|
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;
|
const T bottom = static_cast<const BitfieldData<T, index + 1>&>(pack).value() >> reloffs;
|
||||||
if (bleeds_into_next) {
|
if constexpr (bleeds_into_next) {
|
||||||
const std::size_t safe_index = index + 2 - not 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 val = static_cast<const BitfieldData<T, safe_index>&>(pack).value();
|
||||||
const T top = val << (sizeof(T) * CHAR_BIT - reloffs);
|
const T top = val << (sizeof(T) * CHAR_BIT - reloffs);
|
||||||
return static_cast<T>(top | bottom) & make_mask<T>(so.size);
|
return static_cast<T>(top | bottom) & make_mask<T>(so.size);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
return bottom & make_mask<T>(so.size);
|
return bottom & make_mask<T>(so.size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t Idx, typename T, typename V, std::size_t... Sizes>
|
template <std::size_t Idx, typename T, typename V, std::size_t... Sizes>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
@ -18,11 +18,13 @@
|
||||||
#ifndef id4754A95F12BE4ADEA65642A056A51907
|
#ifndef id4754A95F12BE4ADEA65642A056A51907
|
||||||
#define 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/log10.hpp>
|
||||||
#include <sprout/math/abs.hpp>
|
#include <sprout/math/abs.hpp>
|
||||||
#include <sprout/math/ceil.hpp>
|
#include <sprout/math/ceil.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
# include <string_view>
|
# include <string_view>
|
||||||
# include <string>
|
# include <string>
|
||||||
#endif
|
#endif
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace dhandy {
|
namespace dhandy {
|
||||||
namespace implem {
|
namespace implem {
|
||||||
|
@ -49,6 +52,14 @@ namespace dhandy {
|
||||||
}
|
}
|
||||||
} //unnamed namespace
|
} //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>
|
template <typename T, typename C, unsigned int Base, typename Tr>
|
||||||
T to_integer_sse (const C* s, std::size_t l);
|
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;
|
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>
|
template <typename I, unsigned int Base, bool Signed=int_info<I, Base>::is_signed>
|
||||||
struct IsNegative { static constexpr bool check (I) { return false; } };
|
struct IsNegative { static constexpr bool check (I) { return false; } };
|
||||||
template <typename I, unsigned int Base>
|
template <typename I, unsigned int Base>
|
||||||
|
@ -90,21 +104,35 @@ namespace dhandy {
|
||||||
|
|
||||||
template <typename L>
|
template <typename L>
|
||||||
[[gnu::pure,gnu::always_inline]]
|
[[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]]
|
[[gnu::pure,gnu::always_inline]]
|
||||||
static constexpr CastedType cast (I in) { return static_cast<CastedType>(in); }
|
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>
|
template <typename I, unsigned int Base, typename Tr, typename=void>
|
||||||
struct IntConversion {
|
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) {
|
static constexpr RevArray<I, Base, Tr> 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>;
|
|
||||||
using Num = implem::NumberAdaptation<I, Base>;
|
using Num = implem::NumberAdaptation<I, Base>;
|
||||||
|
|
||||||
const bool was_negative = implem::is_negative<I, Base>(in);
|
const bool was_negative = implem::is_negative<I, Base>(in);
|
||||||
|
|
||||||
RetType arr;
|
RevArray<I, Base, Tr> arr;
|
||||||
arr.push_front('\0');
|
arr.push_front(Tr::NullChar);
|
||||||
do {
|
do {
|
||||||
arr.push_front(Tr::to_digit(static_cast<int>(Num::abs(Num::cast(in)) % Base)));
|
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));
|
in = static_cast<I>(Num::cast(in) / static_cast<I>(Base));
|
||||||
|
@ -117,11 +145,9 @@ namespace dhandy {
|
||||||
|
|
||||||
template <unsigned int Base, typename Tr>
|
template <unsigned int Base, typename Tr>
|
||||||
struct IntConversion<bool, Base, Tr, void> {
|
struct IntConversion<bool, Base, Tr, void> {
|
||||||
static constexpr ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, 2> to_ary (bool in) {
|
static constexpr ReversedSizedArray<typename Tr::char_type, 2> to_ary (bool in) {
|
||||||
using RetType = ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, 2>;
|
ReversedSizedArray<typename Tr::char_type, 2> arr;
|
||||||
|
arr.push_front(Tr::NullChar);
|
||||||
RetType arr;
|
|
||||||
arr.push_front('\0');
|
|
||||||
arr.push_front(in ? Tr::to_digit(1) : Tr::to_digit(0));
|
arr.push_front(in ? Tr::to_digit(1) : Tr::to_digit(0));
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
@ -129,34 +155,40 @@ namespace dhandy {
|
||||||
|
|
||||||
template <typename I, typename Tr>
|
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> {
|
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) {
|
private:
|
||||||
using RetType = ReversedSizedArray<std::decay_t<decltype(std::declval<Tr>().to_digit(1))>, implem::int_info<I, 10>::max_len + 1>;
|
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,
|
||||||
|
4,5,4,6,4,7,4,8,4,9,5,0,5,1,5,2,5,3,5,4,5,5,5,6,5,7,5,8,5,9,
|
||||||
|
6,0,6,1,6,2,6,3,6,4,6,5,6,6,6,7,6,8,6,9,7,0,7,1,7,2,7,3,7,4,
|
||||||
|
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>;
|
using Num = implem::NumberAdaptation<I, 10>;
|
||||||
|
|
||||||
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,
|
|
||||||
4,5,4,6,4,7,4,8,4,9,5,0,5,1,5,2,5,3,5,4,5,5,5,6,5,7,5,8,5,9,
|
|
||||||
6,0,6,1,6,2,6,3,6,4,6,5,6,6,6,7,6,8,6,9,7,0,7,1,7,2,7,3,7,4,
|
|
||||||
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
|
|
||||||
};
|
|
||||||
const bool was_negative = implem::is_negative<I, 10>(in);
|
const bool was_negative = implem::is_negative<I, 10>(in);
|
||||||
|
|
||||||
RetType arr;
|
RetType arr;
|
||||||
arr.push_front('\0');
|
if (not std::is_constant_evaluated())
|
||||||
while (Num::abs(in) >= static_cast<I>(100)) {
|
__builtin_prefetch(arr.base_ptr(), 1, 3);
|
||||||
const auto index = (Num::abs(in) % 100) * 2;
|
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 + 1])));
|
||||||
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
|
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
|
||||||
in = static_cast<I>(in / static_cast<I>(100));
|
in = static_cast<I>(in / static_cast<I>(100));
|
||||||
};
|
};
|
||||||
if (Num::abs(in) < static_cast<I>(10)) {
|
if (in < static_cast<I>(10)) {
|
||||||
arr.push_front(Tr::to_digit(static_cast<int>(Num::abs(in))));
|
arr.push_front(Tr::to_digit(static_cast<int>(in)));
|
||||||
}
|
}
|
||||||
else {
|
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 + 1])));
|
||||||
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
|
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 {
|
struct AryConversion {
|
||||||
|
constexpr static const bool is_sse = false;
|
||||||
|
|
||||||
template <typename C>
|
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 retval = 0;
|
||||||
I factor = 1;
|
I factor = 1;
|
||||||
std::size_t i = end - beg;
|
std::size_t i = end - beg;
|
||||||
|
@ -183,34 +227,26 @@ namespace dhandy {
|
||||||
retval += Tr::from_digit(beg[i]) * factor;
|
retval += Tr::from_digit(beg[i]) * factor;
|
||||||
factor *= Base;
|
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>
|
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 <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>
|
template <unsigned int Base, typename Tr, bool Constexpr>
|
||||||
struct AryConversion<bool, Base, Tr> {
|
struct AryConversion<bool, Base, Tr, Constexpr> {
|
||||||
template <typename C> static bool from_ary (C* beg, C* end) {
|
constexpr static const bool is_sse = false;
|
||||||
|
template <typename C> constexpr static bool from_ary (C* beg, C* end) {
|
||||||
if (end == beg)
|
if (end == beg)
|
||||||
return false;
|
return false;
|
||||||
return (Tr::from_digit(*beg) ? true : 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>
|
template <typename T, typename C, unsigned int Base, typename Tr>
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
T to_integer_sse (const C* s, std::size_t l) {
|
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 factor = _mm_set_epi32(base3, base2, base1, 1);
|
||||||
__m128i res = _mm_set1_epi32(0);
|
__m128i res = _mm_set1_epi32(0);
|
||||||
const __m128i char_0 = _mm_set1_epi32(Tr::FirstDigit);
|
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;
|
std::size_t idx = 0;
|
||||||
const std::size_t cap = l bitand -4;
|
const std::size_t cap = l bitand -4;
|
||||||
do {
|
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 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);
|
__m128i mask = _mm_and_si128(_mm_cmpgt_epi32(digits, char_befo_a), _mm_cmplt_epi32(digits, char_past_f));
|
||||||
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 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));
|
res = _mm_add_epi32(res, muly(_mm_sub_epi32(digits, addend), factor));
|
||||||
factor = muly(factor, _mm_set1_epi32(base4));
|
factor = muly(factor, _mm_set1_epi32(base4));
|
||||||
idx += 4;
|
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, 8));
|
||||||
res = _mm_add_epi32(res, _mm_srli_si128(res, 4));
|
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);
|
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
|
} //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 {
|
struct ASCIITranslator {
|
||||||
static const constexpr bool BehavesLikeASCII = true;
|
typedef C char_type;
|
||||||
static const constexpr C FirstDigit = FDigit;
|
static const constexpr C FirstDigit = FDigit;
|
||||||
static const constexpr C FirstLetter = FLetter;
|
static const constexpr C FirstLetter = FLetter;
|
||||||
|
//static const constexpr C AltLetter = FAltLetter;
|
||||||
static const constexpr C Plus = CPlus;
|
static const constexpr C Plus = CPlus;
|
||||||
static const constexpr C Minus = CMinus;
|
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) {
|
static constexpr C to_digit (unsigned int num) {
|
||||||
return (num <= 9 ?
|
constexpr const C ret[2] = {FirstDigit, FirstLetter - DigitCount};
|
||||||
static_cast<C>(num + FirstDigit) :
|
#if 0
|
||||||
static_cast<C>(num + FirstLetter - 10)
|
//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) {
|
static constexpr int from_digit (C dig) {
|
||||||
return (dig < FirstLetter ?
|
//return (dig < FirstLetter ? dig - FirstDigit : dig - FirstLetter + DigitCount);
|
||||||
dig - FirstDigit :
|
typedef typename std::make_unsigned<C>::type UC;
|
||||||
dig - FirstLetter + 10
|
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>
|
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>>
|
template <typename I, unsigned int Base=10, typename Tr=ASCIITranslator<char>>
|
||||||
constexpr inline auto int_to_ary (I in) {
|
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>>
|
template <typename R, typename C, unsigned int Base=10, typename Tr=ASCIITranslator<C>>
|
||||||
inline R ary_to_int (const C* beg, const C* end) {
|
constexpr inline R ary_to_int (const C* beg, const C* end) {
|
||||||
return implem::AryConversion<R, Base, Tr>::from_ary(beg, 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)
|
#if !defined(INT_CONV_WITHOUT_HELPERS)
|
||||||
|
@ -304,8 +369,9 @@ namespace dhandy {
|
||||||
return std::string(int_to_ary(num).to_string_view());
|
return std::string(int_to_ary(num).to_string_view());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t S>
|
template <typename C, std::size_t S>
|
||||||
std::string operator+ (std::string a, const ReversedSizedArray<char, S>& b) {
|
inline
|
||||||
|
std::basic_string<C> operator+ (std::basic_string<C> a, const ReversedSizedArray<C, S>& b) {
|
||||||
a.append(b.data(), b.size() - 1);
|
a.append(b.data(), b.size() - 1);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
#ifndef idFC25566D624140559C54B39FFFE52F04
|
#ifndef idFC25566D624140559C54B39FFFE52F04
|
||||||
#define idFC25566D624140559C54B39FFFE52F04
|
#define idFC25566D624140559C54B39FFFE52F04
|
||||||
|
|
||||||
#include <array>
|
#include "../variadic_repeat_bt.hpp"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#if !defined(INT_CONV_WITHOUT_HELPERS)
|
#if !defined(INT_CONV_WITHOUT_HELPERS)
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
# include <string>
|
# include <string>
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
#endif
|
#endif
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace dhandy {
|
namespace dhandy {
|
||||||
template <typename T, std::size_t S>
|
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(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");
|
static_assert(std::is_trivial<T>::value, "Only use this container with trivial types");
|
||||||
public:
|
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() = default;
|
||||||
|
constexpr ReversedSizedArray (const ReversedSizedArray&) = default;
|
||||||
|
constexpr ReversedSizedArray (ReversedSizedArray&&) = default;
|
||||||
|
template <typename... Items> constexpr explicit ReversedSizedArray (Items&&... items);
|
||||||
~ReversedSizedArray() = default;
|
~ReversedSizedArray() = default;
|
||||||
|
|
||||||
constexpr std::size_t size() const { return S - (m_curr + 1); }
|
constexpr std::size_t size() const { return S - (m_curr + 1); }
|
||||||
constexpr bool empty() const { return m_curr + 1 == S; }
|
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 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 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 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 const T* data() const { return m_data + m_curr + 1; }
|
||||||
constexpr iterator begin() { return m_data.begin() + m_curr + 1; }
|
constexpr const T* base_ptr() const { return m_data; }
|
||||||
constexpr iterator end() { return m_data.end(); }
|
constexpr iterator begin() { return m_data + m_curr + 1; }
|
||||||
constexpr const T& back() const { return *(m_data.data() + S - 1); }
|
constexpr iterator end() { return m_data + S; }
|
||||||
|
constexpr const T& back() const { return *(m_data + S - 1); }
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
constexpr V to() const { return V(data(), size() - (not empty() and not back() ? 1 : 0)); }
|
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)
|
#if !defined(INT_CONV_WITHOUT_HELPERS)
|
||||||
constexpr std::basic_string_view<T> to_string_view() const { return to<std::basic_string_view<T>>(); }
|
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 to_string_view() == other; }
|
||||||
bool operator!= (const std::basic_string_view<T>& other) const { return not operator==(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::basic_string<T>& 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 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 to_string_view() == std::basic_string_view<T>(other); }
|
||||||
bool operator!= (const T* other) const { return not operator==(other); }
|
bool operator!= (const T* other) const { return not operator==(other); }
|
||||||
|
|
||||||
|
std::string to_string() const { return to<std::basic_string<T>>(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
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};
|
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)
|
#if !defined(INT_CONV_WITHOUT_HELPERS)
|
||||||
template <typename T, std::size_t S>
|
template <typename T, std::size_t S>
|
||||||
inline
|
inline
|
||||||
|
@ -72,14 +110,12 @@ namespace dhandy {
|
||||||
stream << arr.to_string_view();
|
stream << arr.to_string_view();
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T, std::size_t S>
|
template <typename T, std::size_t S>
|
||||||
inline
|
constexpr auto ReversedSizedArray<T, S>::to_tuple() const {
|
||||||
std::basic_string<T> operator+ (std::basic_string<T>&& a, const ReversedSizedArray<T, S>& b) {
|
return implem::elements_or_empty_to_tuple(m_data, m_curr + 1, std::make_index_sequence<S>{});
|
||||||
a.insert(a.end(), b.begin(), b.end());
|
|
||||||
return a;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
} //namespace dhandy
|
} //namespace dhandy
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -5,12 +5,12 @@
|
||||||
#if !defined(INFIX_ITERATOR_H_)
|
#if !defined(INFIX_ITERATOR_H_)
|
||||||
#define INFIX_ITERATOR_H_
|
#define INFIX_ITERATOR_H_
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <iterator>
|
|
||||||
|
namespace dhandy {
|
||||||
template <class T,
|
template <class T,
|
||||||
class charT=char,
|
class charT=char,
|
||||||
class traits=std::char_traits<charT> >
|
class traits=std::char_traits<charT> >
|
||||||
class infix_ostream_iterator :
|
class infix_ostream_iterator
|
||||||
public std::iterator<std::output_iterator_tag,void,void,void,void>
|
|
||||||
{
|
{
|
||||||
std::basic_ostream<charT,traits> *os;
|
std::basic_ostream<charT,traits> *os;
|
||||||
charT const* delimiter;
|
charT const* delimiter;
|
||||||
|
@ -19,6 +19,13 @@ public:
|
||||||
typedef charT char_type;
|
typedef charT char_type;
|
||||||
typedef traits traits_type;
|
typedef traits traits_type;
|
||||||
typedef std::basic_ostream<charT,traits> ostream_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)
|
infix_ostream_iterator(ostream_type& s)
|
||||||
: os(&s),delimiter(0), first_elem(true)
|
: os(&s),delimiter(0), first_elem(true)
|
||||||
{}
|
{}
|
||||||
|
@ -45,4 +52,5 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} //namespace dhandy
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
@ -22,36 +22,96 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#define DHANDY_INTCONV_USE_STDSTRING
|
||||||
|
|
||||||
namespace dhandy {
|
namespace dhandy {
|
||||||
namespace implem {
|
namespace implem {
|
||||||
template <typename T, typename F>
|
template <typename T, typename F, typename Tr, bool FromInt=std::is_integral_v<F>>
|
||||||
struct IntConv;
|
struct IntConv;
|
||||||
|
|
||||||
template <typename F>
|
template <typename Tr>
|
||||||
struct IntConv<std::enable_if_t<std::is_integral_v<F>, std::string>, F> {
|
using IntConvString = std::basic_string<typename Tr::char_type>;
|
||||||
static std::string conv (const F& in) {
|
|
||||||
auto retval = dhandy::int_to_ary(in);
|
template <typename Tr>
|
||||||
return std::string(retval.begin(), retval.end() - 1);
|
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>
|
#if defined(DHANDY_INTCONV_USE_STDSTRING)
|
||||||
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, std::string>> {
|
template <typename F, typename C>
|
||||||
static T conv (const std::string& in) {
|
struct IntConv<IntConvString<ASCIITranslator<C>>, F, ASCIITranslator<C>, true> {
|
||||||
return dhandy::ary_to_int<T>(in.data(), in.data() + in.size());
|
static IntConvString<ASCIITranslator<C>> conv (const F& in) {
|
||||||
|
return std::to_string(in);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename T>
|
#endif
|
||||||
struct IntConv<T, std::enable_if_t<std::is_integral_v<T>, std::string_view>> {
|
template <typename F, typename Tr>
|
||||||
static T conv (const std::string_view& in) {
|
struct IntConv<IntConvStringView<Tr>, F, Tr, true> {
|
||||||
return dhandy::ary_to_int<T>(in.data(), in.data() + in.size());
|
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
|
} //namespace implem
|
||||||
|
|
||||||
template <typename To, typename From>
|
template <typename To, typename From, bool AllCaps=false>
|
||||||
inline To int_conv (const From& from) {
|
constexpr inline To int_conv (const From& from, std::integral_constant<bool, AllCaps> = std::integral_constant<bool, AllCaps>{}) {
|
||||||
return implem::IntConv<To, From>::conv(from);
|
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
|
} //namespace dhandy
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -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
|
|
194
include/duckhandy/packed_pointer.hpp
Normal file
194
include/duckhandy/packed_pointer.hpp
Normal 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
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
#ifndef id170B0E6C34D14EBA9B92A35977BDBFB3
|
#ifndef id170B0E6C34D14EBA9B92A35977BDBFB3
|
||||||
#define id170B0E6C34D14EBA9B92A35977BDBFB3
|
#define id170B0E6C34D14EBA9B92A35977BDBFB3
|
||||||
|
|
||||||
#include "sequence_bt.hpp"
|
#include <utility>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -58,14 +58,19 @@ namespace dhandy {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <std::size_t... I>
|
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];
|
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 {
|
namespace implem {
|
||||||
template <std::size_t S, std::size_t S2, std::size_t... I>
|
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>(
|
return string<S + S2 - 1>(
|
||||||
(I < S - 1 ? parLeft[I] : (I < S + S2 - 2 ? parRight[I - (S - 1)] : '\0'))...
|
(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 S, typename Ch>
|
||||||
template <std::size_t... I>
|
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]...}
|
m_data{parString[I]...}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t S, typename Ch>
|
template <std::size_t S, typename Ch>
|
||||||
inline constexpr string<S, Ch>::string (const value_type* parString) :
|
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 S, typename Ch>
|
||||||
template <std::size_t S2>
|
template <std::size_t S2>
|
||||||
constexpr inline string<S + S2 - 1, Ch> string<S, Ch>::operator+ (const string<S2, Ch>& parOther) const {
|
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>
|
template <std::size_t S, typename Ch>
|
||||||
|
@ -108,11 +113,6 @@ namespace dhandy {
|
||||||
return parStream;
|
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>
|
template <std::size_t S, typename Ch>
|
||||||
constexpr string<S, Ch> make_string (const Ch (&parData)[S]) {
|
constexpr string<S, Ch> make_string (const Ch (&parData)[S]) {
|
||||||
return string<S>(parData);
|
return string<S>(parData);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "duckhandy" is free software: you can redistribute it and/or modify
|
||||||
|
|
61
include/duckhandy/tiger_bt.hpp
Normal file
61
include/duckhandy/tiger_bt.hpp
Normal 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
|
488
include/duckhandy/tiger_bt.inl
Normal file
488
include/duckhandy/tiger_bt.inl
Normal 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
|
|
@ -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
|
|
41
include/duckhandy/variadic_repeat_bt.hpp
Normal file
41
include/duckhandy/variadic_repeat_bt.hpp
Normal 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
|
101
include/duckhandy/version_bt.hpp
Normal file
101
include/duckhandy/version_bt.hpp
Normal 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
32
include/meson.build
Normal 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
23
meson.build
Normal 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
1
meson_options.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
option('build_testing', type: 'boolean', value: true)
|
56
speed_test_int_conv.cpp
Normal file
56
speed_test_int_conv.cpp
Normal 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
7
subprojects/Catch2.wrap
Normal 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
|
2694
subprojects/packagefiles/sprout/meson.build
Normal file
2694
subprojects/packagefiles/sprout/meson.build
Normal file
File diff suppressed because it is too large
Load diff
7
subprojects/sprout.wrap
Normal file
7
subprojects/sprout.wrap
Normal 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
1
test/meson.build
Normal file
|
@ -0,0 +1 @@
|
||||||
|
subdir('unit')
|
|
@ -1,19 +1,20 @@
|
||||||
project(dhandy_unit_test CXX)
|
project(dhandy_unit_test CXX)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
|
int_conv_test.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
endianness_test.cpp
|
endianness_test.cpp
|
||||||
int_conv_test.cpp
|
|
||||||
reversed_sized_array_test.cpp
|
reversed_sized_array_test.cpp
|
||||||
bitfield_pack_test.cpp
|
bitfield_pack_test.cpp
|
||||||
resource_pool_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 17)
|
||||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME}
|
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}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "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/>.
|
* 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 "duckhandy/bitfield_pack.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "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/>.
|
* 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 "duckhandy/endianness.hpp"
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
|
|
||||||
|
|
58
test/unit/infix_iterator.cpp
Normal file
58
test/unit/infix_iterator.cpp
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "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/>.
|
* 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/int_conv.hpp"
|
||||||
#include "duckhandy/string_bt.hpp"
|
#include "duckhandy/string_bt.hpp"
|
||||||
#include "sprout/cstring/strlen.hpp"
|
#include "sprout/cstring/strlen.hpp"
|
||||||
|
@ -23,20 +23,47 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
template <typename T> using int_info_10 = dhandy::implem::int_info<T, 10>;
|
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_16 = dhandy::implem::int_info<T, 16>;
|
||||||
template <typename T> using int_info_2 = dhandy::implem::int_info<T, 2>;
|
template <typename T> using int_info_2 = dhandy::implem::int_info<T, 2>;
|
||||||
|
|
||||||
namespace {
|
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>
|
template <typename T, unsigned int Base>
|
||||||
void AryConversionTestHelper (const std::string_view& s, T expected) {
|
void AryConversionTestHelper (const std::string_view& s, T expected, bool expect_sse) {
|
||||||
using AryConversion = dhandy::implem::AryConversion<T, Base, dhandy::ASCIITranslator<char>>;
|
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);
|
CHECK(AryConversion::from_ary(s.data(), s.data() + s.size()) == expected);
|
||||||
}
|
}
|
||||||
} //unnamed namespace
|
} //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::int_to_ary;
|
||||||
using dhandy::bt::string;
|
using dhandy::bt::string;
|
||||||
using dhandy::bt::make_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>(-1) == "-1");
|
||||||
CHECK(int_to_ary<int64_t>(0x1000000000000000) == "1152921504606846976");
|
CHECK(int_to_ary<int64_t>(0x1000000000000000) == "1152921504606846976");
|
||||||
CHECK(int_to_ary<int64_t>(0xF000000000000000) == "-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>(0xFFFF) == "ffff");
|
||||||
CHECK(int_to_ary<uint16_t SPROUT_PP_COMMA() 16>(0xCACA) == "caca");
|
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
|
//Try a random test, which should not compile as constexpr
|
||||||
std::mt19937 gen;
|
std::mt19937 gen;
|
||||||
gen.seed(1234);
|
gen.seed(std::time(nullptr));
|
||||||
for (int z = 0; z < 10; ++z) {
|
for (int z = 0; z < 10; ++z) {
|
||||||
const int num = gen();
|
const int num = gen();
|
||||||
CHECK(int_to_ary(num) == std::to_string(num));
|
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]") {
|
TEST_CASE ("Check char array to int conversions", "[s2i][int_conv]") {
|
||||||
AryConversionTestHelper<uint32_t, 10>("0", 0);
|
AryConversionTestHelper<std::uint32_t, 10>("0", 0, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("0", 0);
|
AryConversionTestHelper<std::int32_t, 10>("0", 0, true);
|
||||||
AryConversionTestHelper<int16_t, 10>("0", 0);
|
AryConversionTestHelper<std::int16_t, 10>("0", 0, true);
|
||||||
AryConversionTestHelper<int16_t, 16>("ff", 0xff);
|
AryConversionTestHelper<std::int16_t, 16>("ff", 0xff, true);
|
||||||
AryConversionTestHelper<uint8_t, 16>("ff", 0xff);
|
AryConversionTestHelper<std::uint8_t, 16>("ff", 0xff, true);
|
||||||
AryConversionTestHelper<uint32_t, 36>("rs", 1000);
|
AryConversionTestHelper<std::uint32_t, 36>("rs", 1000, true);
|
||||||
AryConversionTestHelper<uint16_t, 8>("20", 16);
|
AryConversionTestHelper<std::uint16_t, 8>("20", 16, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("1", 1);
|
AryConversionTestHelper<std::int32_t, 10>("1", 1, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("10", 10);
|
AryConversionTestHelper<std::int32_t, 10>("10", 10, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("100", 100);
|
AryConversionTestHelper<std::int32_t, 10>("100", 100, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("999", 999);
|
AryConversionTestHelper<std::int32_t, 10>("999", 999, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("1000", 1000);
|
AryConversionTestHelper<std::int32_t, 10>("1000", 1000, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("1001", 1001);
|
AryConversionTestHelper<std::int32_t, 10>("1001", 1001, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("12345", 12345);
|
AryConversionTestHelper<std::int32_t, 10>("12345", 12345, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("123456", 123456);
|
AryConversionTestHelper<std::int32_t, 10>("123456", 123456, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("1234567", 1234567);
|
AryConversionTestHelper<std::int32_t, 10>("1234567", 1234567, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("12345678", 12345678);
|
AryConversionTestHelper<std::int32_t, 10>("12345678", 12345678, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("123456789", 123456789);
|
AryConversionTestHelper<std::int32_t, 10>("123456789", 123456789, true);
|
||||||
AryConversionTestHelper<int32_t, 10>("2147483647", 2147483647);
|
AryConversionTestHelper<std::int32_t, 10>("2147483647", 2147483647, true);
|
||||||
AryConversionTestHelper<uint64_t, 16>("ffffffffffffffff", 0xffffffffffffffff);
|
AryConversionTestHelper<std::uint64_t, 16>("ffffffffffffffff", 0xffffffffffffffff, false);
|
||||||
AryConversionTestHelper<int64_t, 16>("ffffffffffffffff", 0xffffffffffffffff);
|
AryConversionTestHelper<std::int64_t, 16>("ffffffffffffffff", 0xffffffffffffffff, false);
|
||||||
AryConversionTestHelper<int64_t, 16>("7fffffffffffffff", 0x7fffffffffffffff);
|
AryConversionTestHelper<std::int64_t, 16>("7fffffffffffffff", 0x7fffffffffffffff, false);
|
||||||
AryConversionTestHelper<int32_t, 16>("7fffffff", 0x7fffffff);
|
AryConversionTestHelper<std::int32_t, 16>("7fffffff", 0x7fffffff, true);
|
||||||
AryConversionTestHelper<bool, 10>("1", true);
|
AryConversionTestHelper<bool, 10>("1", true, false);
|
||||||
AryConversionTestHelper<bool, 10>("0", 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "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/>.
|
* along with "duckhandy". If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CATCH_CONFIG_MAIN
|
//#define CATCH_CONFIG_MAIN
|
||||||
#include "catch2/catch.hpp"
|
//#include "catch2/catch_test_macros.hpp"
|
||||||
|
|
20
test/unit/meson.build
Normal file
20
test/unit/meson.build
Normal 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,
|
||||||
|
)
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "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/>.
|
* 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 "duckhandy/resource_pool.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright 2016-2020 Michele Santullo
|
/* Copyright 2016-2024 Michele Santullo
|
||||||
* This file is part of "duckhandy".
|
* This file is part of "duckhandy".
|
||||||
*
|
*
|
||||||
* "duckhandy" is free software: you can redistribute it and/or modify
|
* "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/>.
|
* 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"
|
#include "duckhandy/implem/reversed_sized_array_bt.hpp"
|
||||||
|
|
||||||
TEST_CASE ("Check conversion functions in ReversedSizedArray", "[ReversedSizedArray][containers]") {
|
TEST_CASE ("Check conversion functions in ReversedSizedArray", "[ReversedSizedArray][containers]") {
|
||||||
|
|
|
@ -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
56
test/unit/tiger_test.cpp
Normal 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);
|
||||||
|
}
|
94
test/unit/version_test.cpp
Normal file
94
test/unit/version_test.cpp
Normal 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"});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue