Compare commits
48 Commits
6b47133c22
...
release-d2
Author | SHA1 | Date | |
---|---|---|---|
889fe04255 | |||
eed115b287 | |||
7233da75ea | |||
30797c710b | |||
e8041121d0 | |||
d054528e49 | |||
09d840cfd0 | |||
aeb1ef3b12 | |||
b66f61c217 | |||
b089bf460b | |||
cd60c4abaf | |||
d1845448c3 | |||
c4f6ee0026 | |||
17f28d43d1 | |||
043df533b7 | |||
bec75d2eba | |||
f624c720f9 | |||
204e5bbff4 | |||
1ecf197a9e | |||
74a8a7d751 | |||
331f721292 | |||
63486c23d4 | |||
47a6a410c4 | |||
d82c082256 | |||
227f3cd9f5 | |||
20ff0f89fe | |||
4061b8314e | |||
18bb50626d | |||
6a4b48221f | |||
d2a3cfa72e | |||
7c4e2a6564 | |||
e30ebce4c0 | |||
7163947efd | |||
0a0a6e306d | |||
97bc9332d3 | |||
9caf7099b6 | |||
fda1280d29 | |||
59aa4ad21a | |||
1a8afa1a98 | |||
cdbc2d6cc8 | |||
acd93337d4 | |||
cebd3b0a0f | |||
43e2e2155b | |||
be1f90955b | |||
0f2c18d554 | |||
0c0ccd1a69 | |||
1b629da8fc | |||
32e4702dc7 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@
|
|||||||
.stfolder
|
.stfolder
|
||||||
.stignore
|
.stignore
|
||||||
scripts/__pycache__
|
scripts/__pycache__
|
||||||
|
pyenv
|
||||||
CMakeLists.txt.user
|
CMakeLists.txt.user
|
||||||
ROM.oxfs
|
ROM.oxfs
|
||||||
Session.vim
|
Session.vim
|
||||||
|
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
22
.idea/codeStyles/Project.xml
generated
22
.idea/codeStyles/Project.xml
generated
@ -1,22 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<Objective-C>
|
|
||||||
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
|
|
||||||
<option name="INDENT_CLASS_MEMBERS" value="8" />
|
|
||||||
<option name="INDENT_VISIBILITY_KEYWORDS" value="4" />
|
|
||||||
</Objective-C>
|
|
||||||
<Objective-C-extensions>
|
|
||||||
<extensions>
|
|
||||||
<pair source="cpp" header="hpp" fileNamingConvention="LOWERCASE" />
|
|
||||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
|
||||||
<pair source="cu" header="cuh" fileNamingConvention="NONE" />
|
|
||||||
</extensions>
|
|
||||||
</Objective-C-extensions>
|
|
||||||
<codeStyleSettings language="ObjectiveC">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="DrinkingTea" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
17
.idea/fileTemplates/internal/C++ Class Header.h
generated
17
.idea/fileTemplates/internal/C++ Class Header.h
generated
@ -1,17 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 - 2021 gary@drinkingtea.net
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[[#pragma]]# once
|
|
||||||
|
|
||||||
${NAMESPACES_OPEN}
|
|
||||||
|
|
||||||
class ${NAME} {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
${NAMESPACES_CLOSE}
|
|
13
.idea/fileTemplates/internal/C++ Class.cc
generated
13
.idea/fileTemplates/internal/C++ Class.cc
generated
@ -1,13 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 - 2021 gary@drinkingtea.net
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[[#include]]# "${HEADER_FILENAME}"
|
|
||||||
|
|
||||||
${NAMESPACES_OPEN}
|
|
||||||
|
|
||||||
${NAMESPACES_CLOSE}
|
|
24
.idea/inspectionProfiles/Project_Default.xml
generated
24
.idea/inspectionProfiles/Project_Default.xml
generated
@ -1,24 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="ClangTidy" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="clangTidyChecks" value="-*,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-member-init,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-use-anyofallof,cert-*,misc-*,readability-duplicate-include,-misc-non-private-member-variables-in-classes,-misc-no-recursion,bugprone-*,clang-analyzer-*,modernize-*,portability-*,-modernize-use-trailing-return-type,-bugprone-easily-swappable-parameters" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="Clazy" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="ConstantConditionsOC" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="ConstantFunctionResult" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="ConstantParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="DanglingPointers" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="EndlessLoop" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="InfiniteRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="LocalValueEscapesScope" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="LoopDoesntUseConditionVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="NullDereference" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="NullDereferences" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="UnreachableCallsOfFunction" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="UnreachableCode" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="UnusedValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
17
.idea/misc.xml
generated
17
.idea/misc.xml
generated
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompDBSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<CompDBProjectSettings>
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</CompDBProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="CompDBWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
</project>
|
|
8
.idea/nostalgia.iml
generated
8
.idea/nostalgia.iml
generated
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module version="4">
|
|
||||||
<component name="FacetManager">
|
|
||||||
<facet type="Python" name="Python facet">
|
|
||||||
<configuration sdkName="Python 3.8" />
|
|
||||||
</facet>
|
|
||||||
</component>
|
|
||||||
</module>
|
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
3
deps/buildcore/scripts/pybb.py
vendored
3
deps/buildcore/scripts/pybb.py
vendored
@ -98,6 +98,9 @@ def debug(paths: List[str]) -> int:
|
|||||||
args = ['gdb', '--args']
|
args = ['gdb', '--args']
|
||||||
elif shutil.which('lldb') is not None:
|
elif shutil.which('lldb') is not None:
|
||||||
args = ['lldb', '--']
|
args = ['lldb', '--']
|
||||||
|
else:
|
||||||
|
sys.stderr.write('debug: could not find a supported debugger\n')
|
||||||
|
return 1
|
||||||
args.extend(paths)
|
args.extend(paths)
|
||||||
return subprocess.run(args).returncode
|
return subprocess.run(args).returncode
|
||||||
|
|
||||||
|
1
deps/ox/CMakeLists.txt
vendored
1
deps/ox/CMakeLists.txt
vendored
@ -82,4 +82,5 @@ if(OX_USE_STDLIB)
|
|||||||
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
|
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
|
||||||
add_subdirectory(deps/jsoncpp)
|
add_subdirectory(deps/jsoncpp)
|
||||||
endif()
|
endif()
|
||||||
|
add_subdirectory(deps/cityhash)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
30
deps/ox/deps/cityhash/CMakeLists.txt
vendored
Normal file
30
deps/ox/deps/cityhash/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
|
||||||
|
|
||||||
|
project(CityHash CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
set(NOSTALGIA_BUILD_PLAYER OFF)
|
||||||
|
set(NOSTALGIA_BUILD_STUDIO_APP OFF)
|
||||||
|
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(CMAKE_MACOSX_RPATH OFF)
|
||||||
|
else()
|
||||||
|
if(UNIX)
|
||||||
|
set(BUILD_SHARED_LIBS ON)
|
||||||
|
endif()
|
||||||
|
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
|
||||||
|
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(CityHash INTERFACE)
|
||||||
|
target_include_directories(CityHash INTERFACE include)
|
674
deps/ox/deps/cityhash/include/cityhash/city.h
vendored
Normal file
674
deps/ox/deps/cityhash/include/cityhash/city.h
vendored
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
// Copyright (c) 2011 Google, Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// CityHash, by Geoff Pike and Jyrki Alakuijala
|
||||||
|
//
|
||||||
|
// http://code.google.com/p/cityhash/
|
||||||
|
//
|
||||||
|
// This file provides a few functions for hashing strings. All of them are
|
||||||
|
// high-quality functions in the sense that they pass standard tests such
|
||||||
|
// as Austin Appleby's SMHasher. They are also fast.
|
||||||
|
//
|
||||||
|
// For 64-bit x86 code, on short strings, we don't know of anything faster than
|
||||||
|
// CityHash64 that is of comparable quality. We believe our nearest competitor
|
||||||
|
// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
|
||||||
|
// tables and most other hashing (excluding cryptography).
|
||||||
|
//
|
||||||
|
// For 64-bit x86 code, on long strings, the picture is more complicated.
|
||||||
|
// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
|
||||||
|
// CityHashCrc128 appears to be faster than all competitors of comparable
|
||||||
|
// quality. CityHash128 is also good but not quite as fast. We believe our
|
||||||
|
// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
|
||||||
|
// other 64-bit CPUs, but for long strings we know that Spooky is slightly
|
||||||
|
// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
|
||||||
|
// Note that CityHashCrc128 is declared in citycrc.h.
|
||||||
|
//
|
||||||
|
// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
|
||||||
|
// is of comparable quality. We believe our nearest competitor is Murmur3A.
|
||||||
|
// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
|
||||||
|
//
|
||||||
|
// Functions in the CityHash family are not suitable for cryptography.
|
||||||
|
//
|
||||||
|
// Please see CityHash's README file for more details on our performance
|
||||||
|
// measurements and so on.
|
||||||
|
//
|
||||||
|
// WARNING: This code has been only lightly tested on big-endian platforms!
|
||||||
|
// It is known to work well on little-endian platforms that have a small penalty
|
||||||
|
// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
|
||||||
|
// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
|
||||||
|
// bug reports are welcome.
|
||||||
|
//
|
||||||
|
// By the way, for some hash functions, given strings a and b, the hash
|
||||||
|
// of a+b is easily derived from the hashes of a and b. This property
|
||||||
|
// doesn't hold for any hash functions in this file.
|
||||||
|
|
||||||
|
#ifndef CITY_HASH_H_
|
||||||
|
#define CITY_HASH_H_
|
||||||
|
|
||||||
|
#if __has_include(<cstdint>)
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned uint_t;
|
||||||
|
#if defined(__arm__) || defined(__ppc__)
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
typedef __INTMAX_TYPE__ intmax_t;
|
||||||
|
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||||
|
#else
|
||||||
|
typedef long int64_t;
|
||||||
|
typedef unsigned long uint64_t;
|
||||||
|
typedef int64_t intmax_t;
|
||||||
|
typedef uint64_t uintmax_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_LP64) || defined(__ppc64__) || defined(__aarch64__)
|
||||||
|
typedef long intptr_t;
|
||||||
|
typedef unsigned long uintptr_t;
|
||||||
|
#elif defined(_WIN64)
|
||||||
|
typedef int64_t intptr_t;
|
||||||
|
typedef uint64_t uintptr_t;
|
||||||
|
#elif defined(_LP32) || defined(__ppc__) || defined(_WIN32) || defined(__arm__)
|
||||||
|
typedef int32_t intptr_t;
|
||||||
|
typedef uint32_t uintptr_t;
|
||||||
|
#else
|
||||||
|
#error intptr_t, and uintptr_t undefined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using size_t = decltype(alignof(int));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace cityhash::detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct remove_reference {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct remove_reference<T&> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct remove_reference<T&&> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using remove_reference_t = typename remove_reference<T>::type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr remove_reference_t<T> &&move(T &&t) noexcept {
|
||||||
|
return static_cast<remove_reference_t<T>&&>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using remove_reference_t = typename remove_reference<T>::type;
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
struct pair {
|
||||||
|
T1 first{};
|
||||||
|
T2 second{};
|
||||||
|
constexpr pair() noexcept = default;
|
||||||
|
constexpr pair(T1 a, T2 b) noexcept: first(detail::move(a)), second(detail::move(b)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr void swap(T &a, T &b) noexcept {
|
||||||
|
auto temp = detail::move(a);
|
||||||
|
a = detail::move(b);
|
||||||
|
b = detail::move(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cityhash {
|
||||||
|
|
||||||
|
using uint128 = cityhash::detail::pair<uint64_t, uint64_t>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr T byteSwap(T i) noexcept {
|
||||||
|
if constexpr(sizeof(T) == 1) {
|
||||||
|
return i;
|
||||||
|
} else if constexpr(sizeof(T) == 2) {
|
||||||
|
return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
|
||||||
|
} else if constexpr(sizeof(T) == 4) {
|
||||||
|
return ((i >> 24) & 0x000000ff) |
|
||||||
|
((i >> 8) & 0x0000ff00) |
|
||||||
|
((i << 8) & 0x00ff0000) |
|
||||||
|
((i << 24) & 0xff000000);
|
||||||
|
} else if constexpr(sizeof(T) == 8) {
|
||||||
|
return ((i >> 56) & 0x00000000000000ff) |
|
||||||
|
((i >> 40) & 0x000000000000ff00) |
|
||||||
|
((i >> 24) & 0x0000000000ff0000) |
|
||||||
|
((i >> 8) & 0x00000000ff000000) |
|
||||||
|
((i << 8) & 0x000000ff00000000) |
|
||||||
|
((i << 24) & 0x0000ff0000000000) |
|
||||||
|
((i << 40) & 0x00ff000000000000) |
|
||||||
|
((i << 56) & 0xff00000000000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t Uint128Low64(const uint128& x) noexcept { return x.first; }
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t Uint128High64(const uint128& x) noexcept { return x.second; }
|
||||||
|
|
||||||
|
// Hash 128 input bits down to 64 bits of output.
|
||||||
|
// This is intended to be a reasonably good hash function.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t Hash128to64(const uint128& x) noexcept {
|
||||||
|
// Murmur-inspired hashing.
|
||||||
|
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||||
|
uint64_t a = (detail::Uint128Low64(x) ^ detail::Uint128High64(x)) * kMul;
|
||||||
|
a ^= (a >> 47);
|
||||||
|
uint64_t b = (detail::Uint128High64(x) ^ a) * kMul;
|
||||||
|
b ^= (b >> 47);
|
||||||
|
b *= kMul;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t UNALIGNED_LOAD64(const char *p) noexcept {
|
||||||
|
uint64_t result{};
|
||||||
|
result |= static_cast<uint64_t>(p[0]);
|
||||||
|
result |= static_cast<uint64_t>(p[1]) << 8;
|
||||||
|
result |= static_cast<uint64_t>(p[2]) << 16;
|
||||||
|
result |= static_cast<uint64_t>(p[3]) << 24;
|
||||||
|
result |= static_cast<uint64_t>(p[4]) << 32;
|
||||||
|
result |= static_cast<uint64_t>(p[5]) << 40;
|
||||||
|
result |= static_cast<uint64_t>(p[6]) << 48;
|
||||||
|
result |= static_cast<uint64_t>(p[7]) << 56;
|
||||||
|
//memcpy(&result, p, sizeof(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t UNALIGNED_LOAD32(const char *p) noexcept {
|
||||||
|
uint32_t result{};
|
||||||
|
result |= static_cast<uint32_t>(p[0]);
|
||||||
|
result |= static_cast<uint32_t>(p[1]) << 8;
|
||||||
|
result |= static_cast<uint32_t>(p[2]) << 16;
|
||||||
|
result |= static_cast<uint32_t>(p[3]) << 24;
|
||||||
|
//memcpy(&result, p, sizeof(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
#define uint32_in_expected_order(x) (detail::byteSwap<uint32_t>(x))
|
||||||
|
#define uint64_in_expected_order(x) (detail::byteSwap<uint64_t>(x))
|
||||||
|
#else
|
||||||
|
#define uint32_in_expected_order(x) (x)
|
||||||
|
#define uint64_in_expected_order(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LIKELY)
|
||||||
|
#if HAVE_BUILTIN_EXPECT
|
||||||
|
#define LIKELY(x) (__builtin_expect(!!(x), 1))
|
||||||
|
#else
|
||||||
|
#define LIKELY(x) (x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t Fetch64(const char *p) noexcept {
|
||||||
|
return uint64_in_expected_order(UNALIGNED_LOAD64(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t Fetch32(const char *p) noexcept {
|
||||||
|
return uint32_in_expected_order(UNALIGNED_LOAD32(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some primes between 2^63 and 2^64 for various uses.
|
||||||
|
constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
|
||||||
|
constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
|
||||||
|
constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
|
||||||
|
|
||||||
|
// Magic numbers for 32-bit hashing. Copied from Murmur3.
|
||||||
|
constexpr uint32_t c1 = 0xcc9e2d51;
|
||||||
|
constexpr uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
// A 32-bit to 32-bit integer hash copied from Murmur3.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t fmix(uint32_t h) noexcept {
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6b;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35;
|
||||||
|
h ^= h >> 16;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t Rotate32(uint32_t val, int shift) noexcept {
|
||||||
|
// Avoid shifting by 32: doing so yields an undefined result.
|
||||||
|
return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef PERMUTE3
|
||||||
|
#define PERMUTE3(a, b, c) do { detail::swap(a, b); detail::swap(a, c); } while (0)
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t Mur(uint32_t a, uint32_t h) noexcept {
|
||||||
|
// Helper from Murmur3 for combining two 32-bit values.
|
||||||
|
a *= detail::c1;
|
||||||
|
a = Rotate32(a, 17);
|
||||||
|
a *= detail::c2;
|
||||||
|
h ^= a;
|
||||||
|
h = Rotate32(h, 19);
|
||||||
|
return h * 5 + 0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t Hash32Len13to24(const char *s, size_t len) noexcept {
|
||||||
|
uint32_t a = Fetch32(s - 4 + (len >> 1));
|
||||||
|
uint32_t b = Fetch32(s + 4);
|
||||||
|
uint32_t c = Fetch32(s + len - 8);
|
||||||
|
uint32_t d = Fetch32(s + (len >> 1));
|
||||||
|
uint32_t e = Fetch32(s);
|
||||||
|
uint32_t f = Fetch32(s + len - 4);
|
||||||
|
uint32_t h = static_cast<uint32_t>(len);
|
||||||
|
|
||||||
|
return detail::fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t Hash32Len0to4(const char *s, size_t len) noexcept {
|
||||||
|
uint32_t b = 0;
|
||||||
|
uint32_t c = 9;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
auto const v = static_cast<signed char>(s[i]);
|
||||||
|
b = b * detail::c1 + static_cast<uint32_t>(v);
|
||||||
|
c ^= b;
|
||||||
|
}
|
||||||
|
return detail::fmix(Mur(b, Mur(static_cast<uint32_t>(len), c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t Hash32Len5to12(const char *s, size_t len) noexcept {
|
||||||
|
uint32_t a = static_cast<uint32_t>(len), b = a * 5, c = 9, d = b;
|
||||||
|
a += Fetch32(s);
|
||||||
|
b += Fetch32(s + len - 4);
|
||||||
|
c += Fetch32(s + ((len >> 1) & 4));
|
||||||
|
return detail::fmix(Mur(c, Mur(b, Mur(a, d))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitwise right rotate. Normally this will compile to a single
|
||||||
|
// instruction, especially if the shift is a manifest constant.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t Rotate(uint64_t val, int shift) noexcept {
|
||||||
|
// Avoid shifting by 64: doing so yields an undefined result.
|
||||||
|
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t ShiftMix(uint64_t val) noexcept {
|
||||||
|
return val ^ (val >> 47);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t HashLen16(uint64_t u, uint64_t v) noexcept {
|
||||||
|
return Hash128to64(uint128(u, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) noexcept {
|
||||||
|
// Murmur-inspired hashing.
|
||||||
|
uint64_t a = (u ^ v) * mul;
|
||||||
|
a ^= (a >> 47);
|
||||||
|
uint64_t b = (v ^ a) * mul;
|
||||||
|
b ^= (b >> 47);
|
||||||
|
b *= mul;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t HashLen0to16(const char *s, size_t len) noexcept {
|
||||||
|
if (len >= 8) {
|
||||||
|
uint64_t mul = detail::k2 + len * 2;
|
||||||
|
uint64_t a = detail::Fetch64(s) + detail::k2;
|
||||||
|
uint64_t b = detail::Fetch64(s + len - 8);
|
||||||
|
uint64_t c = detail::Rotate(b, 37) * mul + a;
|
||||||
|
uint64_t d = (detail::Rotate(a, 25) + b) * mul;
|
||||||
|
return HashLen16(c, d, mul);
|
||||||
|
}
|
||||||
|
if (len >= 4) {
|
||||||
|
uint64_t mul = detail::k2 + len * 2;
|
||||||
|
uint64_t a = Fetch32(s);
|
||||||
|
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
uint8_t a = static_cast<uint8_t>(s[0]);
|
||||||
|
uint8_t b = static_cast<uint8_t>(s[len >> 1]);
|
||||||
|
uint8_t c = static_cast<uint8_t>(s[len - 1]);
|
||||||
|
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
|
||||||
|
uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
|
||||||
|
return ShiftMix(y * detail::k2 ^ z * detail::k0) * detail::k2;
|
||||||
|
}
|
||||||
|
return detail::k2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This probably works well for 16-byte strings as well, but it may be overkill
|
||||||
|
// in that case.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t HashLen17to32(const char *s, size_t len) noexcept {
|
||||||
|
uint64_t mul = detail::k2 + len * 2;
|
||||||
|
uint64_t a = detail::Fetch64(s) * detail::k1;
|
||||||
|
uint64_t b = detail::Fetch64(s + 8);
|
||||||
|
uint64_t c = detail::Fetch64(s + len - 8) * mul;
|
||||||
|
uint64_t d = detail::Fetch64(s + len - 16) * detail::k2;
|
||||||
|
return HashLen16(detail::Rotate(a + b, 43) + detail::Rotate(c, 30) + d,
|
||||||
|
a + detail::Rotate(b + detail::k2, 18) + c, mul);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||||
|
// Callers do best to use "random-looking" values for a and b.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr detail::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
|
||||||
|
uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) noexcept {
|
||||||
|
a += w;
|
||||||
|
b = detail::Rotate(b + a + z, 21);
|
||||||
|
uint64_t c = a;
|
||||||
|
a += x;
|
||||||
|
a += y;
|
||||||
|
b += detail::Rotate(a, 44);
|
||||||
|
return detail::pair(a + z, b + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr detail::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
|
||||||
|
const char* s, uint64_t a, uint64_t b) noexcept {
|
||||||
|
return WeakHashLen32WithSeeds(detail::Fetch64(s),
|
||||||
|
detail::Fetch64(s + 8),
|
||||||
|
detail::Fetch64(s + 16),
|
||||||
|
detail::Fetch64(s + 24),
|
||||||
|
a,
|
||||||
|
b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an 8-byte hash for 33 to 64 bytes.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t HashLen33to64(const char *s, size_t len) noexcept {
|
||||||
|
uint64_t mul = detail::k2 + len * 2;
|
||||||
|
uint64_t a = detail::Fetch64(s) * detail::k2;
|
||||||
|
uint64_t b = detail::Fetch64(s + 8);
|
||||||
|
uint64_t c = detail::Fetch64(s + len - 24);
|
||||||
|
uint64_t d = detail::Fetch64(s + len - 32);
|
||||||
|
uint64_t e = detail::Fetch64(s + 16) * detail::k2;
|
||||||
|
uint64_t f = detail::Fetch64(s + 24) * 9;
|
||||||
|
uint64_t g = detail::Fetch64(s + len - 8);
|
||||||
|
uint64_t h = detail::Fetch64(s + len - 16) * mul;
|
||||||
|
uint64_t u = detail::Rotate(a + g, 43) + (detail::Rotate(b, 30) + c) * 9;
|
||||||
|
uint64_t v = ((a + g) ^ d) + f + 1;
|
||||||
|
uint64_t w = detail::byteSwap((u + v) * mul) + h;
|
||||||
|
uint64_t x = detail::Rotate(e + f, 42) + c;
|
||||||
|
uint64_t y = (detail::byteSwap((v + w) * mul) + g) * mul;
|
||||||
|
uint64_t z = e + f + c;
|
||||||
|
a = detail::byteSwap((x + z) * mul + y) + b;
|
||||||
|
b = ShiftMix((z + a) * mul + d + h) * mul;
|
||||||
|
return b + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
|
||||||
|
// of any length representable in signed long. Based on City and Murmur.
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint128 CityMurmur(const char *s, size_t len, uint128 seed) noexcept {
|
||||||
|
uint64_t a = detail::Uint128Low64(seed);
|
||||||
|
uint64_t b = detail::Uint128High64(seed);
|
||||||
|
uint64_t c = 0;
|
||||||
|
uint64_t d = 0;
|
||||||
|
if (len <= 16) {
|
||||||
|
a = ShiftMix(a * detail::k1) * detail::k1;
|
||||||
|
c = b * detail::k1 + HashLen0to16(s, len);
|
||||||
|
d = ShiftMix(a + (len >= 8 ? detail::Fetch64(s) : c));
|
||||||
|
} else {
|
||||||
|
c = HashLen16(detail::Fetch64(s + len - 8) + detail::k1, a);
|
||||||
|
d = HashLen16(b + len, c + detail::Fetch64(s + len - 16));
|
||||||
|
a += d;
|
||||||
|
// len > 16 here, so do...while is safe
|
||||||
|
do {
|
||||||
|
a ^= ShiftMix(detail::Fetch64(s) * detail::k1) * detail::k1;
|
||||||
|
a *= detail::k1;
|
||||||
|
b ^= a;
|
||||||
|
c ^= ShiftMix(detail::Fetch64(s + 8) * detail::k1) * detail::k1;
|
||||||
|
c *= detail::k1;
|
||||||
|
d ^= c;
|
||||||
|
s += 16;
|
||||||
|
len -= 16;
|
||||||
|
} while (len > 16);
|
||||||
|
}
|
||||||
|
a = HashLen16(a, c);
|
||||||
|
b = HashLen16(d, b);
|
||||||
|
return uint128(a ^ b, HashLen16(b, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint32_t CityHash32(const char *s, size_t len) noexcept {
|
||||||
|
if (len <= 24) {
|
||||||
|
return len <= 12 ?
|
||||||
|
(len <= 4 ? detail::Hash32Len0to4(s, len) : detail::Hash32Len5to12(s, len)) :
|
||||||
|
detail::Hash32Len13to24(s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// len > 24
|
||||||
|
uint32_t h = static_cast<uint32_t>(len), g = detail::c1 * h, f = g;
|
||||||
|
uint32_t a0 = detail::Rotate32(detail::Fetch32(s + len - 4) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a1 = detail::Rotate32(detail::Fetch32(s + len - 8) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a2 = detail::Rotate32(detail::Fetch32(s + len - 16) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a3 = detail::Rotate32(detail::Fetch32(s + len - 12) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a4 = detail::Rotate32(detail::Fetch32(s + len - 20) * detail::c1, 17) * detail::c2;
|
||||||
|
h ^= a0;
|
||||||
|
h = detail::Rotate32(h, 19);
|
||||||
|
h = h * 5 + 0xe6546b64;
|
||||||
|
h ^= a2;
|
||||||
|
h = detail::Rotate32(h, 19);
|
||||||
|
h = h * 5 + 0xe6546b64;
|
||||||
|
g ^= a1;
|
||||||
|
g = detail::Rotate32(g, 19);
|
||||||
|
g = g * 5 + 0xe6546b64;
|
||||||
|
g ^= a3;
|
||||||
|
g = detail::Rotate32(g, 19);
|
||||||
|
g = g * 5 + 0xe6546b64;
|
||||||
|
f += a4;
|
||||||
|
f = detail::Rotate32(f, 19);
|
||||||
|
f = f * 5 + 0xe6546b64;
|
||||||
|
size_t iters = (len - 1) / 20;
|
||||||
|
do {
|
||||||
|
uint32_t a0 = detail::Rotate32(detail::Fetch32(s) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a1 = detail::Fetch32(s + 4);
|
||||||
|
uint32_t a2 = detail::Rotate32(detail::Fetch32(s + 8) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a3 = detail::Rotate32(detail::Fetch32(s + 12) * detail::c1, 17) * detail::c2;
|
||||||
|
uint32_t a4 = detail::Fetch32(s + 16);
|
||||||
|
h ^= a0;
|
||||||
|
h = detail::Rotate32(h, 18);
|
||||||
|
h = h * 5 + 0xe6546b64;
|
||||||
|
f += a1;
|
||||||
|
f = detail::Rotate32(f, 19);
|
||||||
|
f = f * detail::c1;
|
||||||
|
g += a2;
|
||||||
|
g = detail::Rotate32(g, 18);
|
||||||
|
g = g * 5 + 0xe6546b64;
|
||||||
|
h ^= a3 + a1;
|
||||||
|
h = detail::Rotate32(h, 19);
|
||||||
|
h = h * 5 + 0xe6546b64;
|
||||||
|
g ^= a4;
|
||||||
|
g = detail::byteSwap(g) * 5;
|
||||||
|
h += a4 * 5;
|
||||||
|
h = detail::byteSwap(h);
|
||||||
|
f += a0;
|
||||||
|
PERMUTE3(f, h, g);
|
||||||
|
s += 20;
|
||||||
|
} while (--iters != 0);
|
||||||
|
g = detail::Rotate32(g, 11) * detail::c1;
|
||||||
|
g = detail::Rotate32(g, 17) * detail::c1;
|
||||||
|
f = detail::Rotate32(f, 11) * detail::c1;
|
||||||
|
f = detail::Rotate32(f, 17) * detail::c1;
|
||||||
|
h = detail::Rotate32(h + g, 19);
|
||||||
|
h = h * 5 + 0xe6546b64;
|
||||||
|
h = detail::Rotate32(h, 17) * detail::c1;
|
||||||
|
h = detail::Rotate32(h + f, 19);
|
||||||
|
h = h * 5 + 0xe6546b64;
|
||||||
|
h = detail::Rotate32(h, 17) * detail::c1;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t CityHash64(const char *s, size_t len) noexcept {
|
||||||
|
if (len <= 32) {
|
||||||
|
if (len <= 16) {
|
||||||
|
return detail::HashLen0to16(s, len);
|
||||||
|
} else {
|
||||||
|
return detail::HashLen17to32(s, len);
|
||||||
|
}
|
||||||
|
} else if (len <= 64) {
|
||||||
|
return detail::HashLen33to64(s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For strings over 64 bytes we hash the end first, and then as we
|
||||||
|
// loop we keep 56 bytes of state: v, w, x, y, and z.
|
||||||
|
uint64_t x = detail::Fetch64(s + len - 40);
|
||||||
|
uint64_t y = detail::Fetch64(s + len - 16) + detail::Fetch64(s + len - 56);
|
||||||
|
uint64_t z = detail::HashLen16(detail::Fetch64(s + len - 48) + len, detail::Fetch64(s + len - 24));
|
||||||
|
detail::pair<uint64_t, uint64_t> v = detail::WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||||
|
detail::pair<uint64_t, uint64_t> w = detail::WeakHashLen32WithSeeds(s + len - 32, y + detail::k1, x);
|
||||||
|
x = x * detail::k1 + detail::Fetch64(s);
|
||||||
|
|
||||||
|
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
||||||
|
len = (len - 1) & ~static_cast<size_t>(63);
|
||||||
|
do {
|
||||||
|
x = detail::Rotate(x + y + v.first + detail::Fetch64(s + 8), 37) * detail::k1;
|
||||||
|
y = detail::Rotate(y + v.second + detail::Fetch64(s + 48), 42) * detail::k1;
|
||||||
|
x ^= w.second;
|
||||||
|
y += v.first + detail::Fetch64(s + 40);
|
||||||
|
z = detail::Rotate(z + w.first, 33) * detail::k1;
|
||||||
|
v = detail::WeakHashLen32WithSeeds(s, v.second * detail::k1, x + w.first);
|
||||||
|
w = detail::WeakHashLen32WithSeeds(s + 32, z + w.second, y + detail::Fetch64(s + 16));
|
||||||
|
detail::swap(z, x);
|
||||||
|
s += 64;
|
||||||
|
len -= 64;
|
||||||
|
} while (len != 0);
|
||||||
|
return detail::HashLen16(detail::HashLen16(v.first, w.first) + detail::ShiftMix(y) * detail::k1 + z,
|
||||||
|
detail::HashLen16(v.second, w.second) + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t CityHash64WithSeeds(const char *s, size_t len,
|
||||||
|
uint64_t seed0, uint64_t seed1) noexcept {
|
||||||
|
return detail::HashLen16(CityHash64(s, len) - seed0, seed1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed) noexcept {
|
||||||
|
return CityHash64WithSeeds(s, len, detail::k2, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) noexcept {
|
||||||
|
if (len < 128) {
|
||||||
|
return detail::CityMurmur(s, len, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
||||||
|
// v, w, x, y, and z.
|
||||||
|
detail::pair<uint64_t, uint64_t> v, w;
|
||||||
|
uint64_t x = detail::Uint128Low64(seed);
|
||||||
|
uint64_t y = detail::Uint128High64(seed);
|
||||||
|
uint64_t z = len * detail::k1;
|
||||||
|
v.first = detail::Rotate(y ^ detail::k1, 49) * detail::k1 + detail::Fetch64(s);
|
||||||
|
v.second = detail::Rotate(v.first, 42) * detail::k1 + detail::Fetch64(s + 8);
|
||||||
|
w.first = detail::Rotate(y + z, 35) * detail::k1 + x;
|
||||||
|
w.second = detail::Rotate(x + detail::Fetch64(s + 88), 53) * detail::k1;
|
||||||
|
|
||||||
|
// This is the same inner loop as CityHash64(), manually unrolled.
|
||||||
|
do {
|
||||||
|
x = detail::Rotate(x + y + v.first + detail::Fetch64(s + 8), 37) * detail::k1;
|
||||||
|
y = detail::Rotate(y + v.second + detail::Fetch64(s + 48), 42) * detail::k1;
|
||||||
|
x ^= w.second;
|
||||||
|
y += v.first + detail::Fetch64(s + 40);
|
||||||
|
z = detail::Rotate(z + w.first, 33) * detail::k1;
|
||||||
|
v = detail::WeakHashLen32WithSeeds(s, v.second * detail::k1, x + w.first);
|
||||||
|
w = detail::WeakHashLen32WithSeeds(s + 32, z + w.second, y + detail::Fetch64(s + 16));
|
||||||
|
detail::swap(z, x);
|
||||||
|
s += 64;
|
||||||
|
x = detail::Rotate(x + y + v.first + detail::Fetch64(s + 8), 37) * detail::k1;
|
||||||
|
y = detail::Rotate(y + v.second + detail::Fetch64(s + 48), 42) * detail::k1;
|
||||||
|
x ^= w.second;
|
||||||
|
y += v.first + detail::Fetch64(s + 40);
|
||||||
|
z = detail::Rotate(z + w.first, 33) * detail::k1;
|
||||||
|
v = detail::WeakHashLen32WithSeeds(s, v.second * detail::k1, x + w.first);
|
||||||
|
w = detail::WeakHashLen32WithSeeds(s + 32, z + w.second, y + detail::Fetch64(s + 16));
|
||||||
|
detail::swap(z, x);
|
||||||
|
s += 64;
|
||||||
|
len -= 128;
|
||||||
|
} while (LIKELY(len >= 128));
|
||||||
|
x += detail::Rotate(v.first + z, 49) * detail::k0;
|
||||||
|
y = y * detail::k0 + detail::Rotate(w.second, 37);
|
||||||
|
z = z * detail::k0 + detail::Rotate(w.first, 27);
|
||||||
|
w.first *= 9;
|
||||||
|
v.first *= detail::k0;
|
||||||
|
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
|
||||||
|
for (size_t tail_done = 0; tail_done < len; ) {
|
||||||
|
tail_done += 32;
|
||||||
|
y = detail::Rotate(x + y, 42) * detail::k0 + v.second;
|
||||||
|
w.first += detail::Fetch64(s + len - tail_done + 16);
|
||||||
|
x = x * detail::k0 + w.first;
|
||||||
|
z += w.second + detail::Fetch64(s + len - tail_done);
|
||||||
|
w.second += v.first;
|
||||||
|
v = detail::WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
|
||||||
|
v.first *= detail::k0;
|
||||||
|
}
|
||||||
|
// At this point our 56 bytes of state should contain more than
|
||||||
|
// enough information for a strong 128-bit hash. We use two
|
||||||
|
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
|
||||||
|
x = detail::HashLen16(x, v.first);
|
||||||
|
y = detail::HashLen16(y + z, w.first);
|
||||||
|
return uint128(detail::HashLen16(x + v.second, w.second) + y,
|
||||||
|
detail::HashLen16(x + w.second, y + v.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr uint128 CityHash128(const char *s, size_t len) noexcept {
|
||||||
|
return len >= 16 ?
|
||||||
|
CityHash128WithSeed(s + 16, len - 16,
|
||||||
|
uint128(detail::Fetch64(s), detail::Fetch64(s + 8) + detail::k0)) :
|
||||||
|
CityHash128WithSeed(s, len, uint128(detail::k0, detail::k1));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CITY_HASH_H_
|
4
deps/ox/src/ox/clargs/clargs.cpp
vendored
4
deps/ox/src/ox/clargs/clargs.cpp
vendored
@ -42,9 +42,9 @@ bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
|
|||||||
return !err ? *value : defaultValue;
|
return !err ? *value : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ClArgs::getString(ox::CRStringView arg, const char *defaultValue) const noexcept {
|
String ClArgs::getString(ox::CRStringView arg, ox::StringView defaultValue) const noexcept {
|
||||||
auto [value, err] = m_strings.at(arg);
|
auto [value, err] = m_strings.at(arg);
|
||||||
return !err ? ox::String(std::move(*value)) : ox::String(defaultValue);
|
return !err ? ox::String(*value) : ox::String(defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {
|
int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {
|
||||||
|
2
deps/ox/src/ox/clargs/clargs.hpp
vendored
2
deps/ox/src/ox/clargs/clargs.hpp
vendored
@ -26,7 +26,7 @@ class ClArgs {
|
|||||||
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
|
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
String getString(ox::CRStringView argName, const char *defaultValue) const noexcept;
|
String getString(ox::CRStringView argName, ox::StringView defaultValue) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int getInt(ox::CRStringView arg, int defaultValue) const noexcept;
|
int getInt(ox::CRStringView arg, int defaultValue) const noexcept;
|
||||||
|
105
deps/ox/src/ox/claw/read.cpp
vendored
105
deps/ox/src/ox/claw/read.cpp
vendored
@ -12,34 +12,66 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept {
|
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
|
||||||
const auto s1End = ox::strchr(buff, ';', buffLen);
|
auto buffRaw = buff.data();
|
||||||
|
auto buffLen = buff.size();
|
||||||
|
size_t outSz{};
|
||||||
|
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
|
||||||
if (!s1End) {
|
if (!s1End) {
|
||||||
return OxError(1, "Could not read Claw header");
|
return OxError(1, "Could not read Claw header");
|
||||||
}
|
}
|
||||||
const auto s1Size = static_cast<std::size_t>(s1End - buff);
|
auto const fmtSz = static_cast<std::size_t>(s1End - buffRaw) + 1;
|
||||||
const String fmt(buff, s1Size);
|
buffRaw += fmtSz;
|
||||||
buff += s1Size + 1;
|
buffLen -= fmtSz;
|
||||||
buffLen -= s1Size + 1;
|
outSz += fmtSz;
|
||||||
|
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
|
||||||
const auto s2End = ox::strchr(buff, ';', buffLen);
|
|
||||||
if (!s2End) {
|
if (!s2End) {
|
||||||
return OxError(2, "Could not read Claw header");
|
return OxError(2, "Could not read Claw header");
|
||||||
}
|
}
|
||||||
const auto s2Size = static_cast<std::size_t>(s2End - buff);
|
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw) + 1;
|
||||||
const String typeName(buff, s2Size);
|
buffRaw += s2Size;
|
||||||
buff += s2Size + 1;
|
buffLen -= s2Size;
|
||||||
buffLen -= s2Size + 1;
|
outSz += s2Size;
|
||||||
|
auto const s3End = ox::strchr(buffRaw, ';', buffLen) + 1;
|
||||||
const auto s3End = ox::strchr(buff, ';', buffLen);
|
|
||||||
if (!s3End) {
|
if (!s3End) {
|
||||||
return OxError(3, "Could not read Claw header");
|
return OxError(3, "Could not read Claw header");
|
||||||
}
|
}
|
||||||
const auto s3Size = static_cast<std::size_t>(s3End - buff);
|
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
|
||||||
const String versionStr(buff, s3Size);
|
buffRaw += s3Size;
|
||||||
buff += s3Size + 1;
|
buffLen -= s3Size;
|
||||||
buffLen -= s3Size + 1;
|
outSz += s3Size;
|
||||||
|
return {{buff.data() + fmtSz, outSz - fmtSz - 1}};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
|
||||||
|
auto buffRaw = buff.data();
|
||||||
|
auto buffLen = buff.size();
|
||||||
|
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
|
||||||
|
if (!s1End) {
|
||||||
|
return OxError(1, "Could not read Claw header");
|
||||||
|
}
|
||||||
|
auto const s1Size = static_cast<std::size_t>(s1End - buffRaw);
|
||||||
|
StringView const fmt(buffRaw, s1Size);
|
||||||
|
buffRaw += s1Size + 1;
|
||||||
|
buffLen -= s1Size + 1;
|
||||||
|
|
||||||
|
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
|
||||||
|
if (!s2End) {
|
||||||
|
return OxError(2, "Could not read Claw header");
|
||||||
|
}
|
||||||
|
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw);
|
||||||
|
StringView const typeName(buffRaw, s2Size);
|
||||||
|
buffRaw += s2Size + 1;
|
||||||
|
buffLen -= s2Size + 1;
|
||||||
|
|
||||||
|
auto const s3End = ox::strchr(buffRaw, ';', buffLen);
|
||||||
|
if (!s3End) {
|
||||||
|
return OxError(3, "Could not read Claw header");
|
||||||
|
}
|
||||||
|
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
|
||||||
|
StringView const versionStr(buffRaw, s3Size);
|
||||||
|
buffRaw += s3Size + 1;
|
||||||
|
buffLen -= s3Size + 1;
|
||||||
ClawHeader hdr;
|
ClawHeader hdr;
|
||||||
if (fmt == "M2") {
|
if (fmt == "M2") {
|
||||||
hdr.fmt = ClawFormat::Metal;
|
hdr.fmt = ClawFormat::Metal;
|
||||||
@ -49,32 +81,21 @@ Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcep
|
|||||||
return OxError(4, "Claw format does not match any supported format/version combo");
|
return OxError(4, "Claw format does not match any supported format/version combo");
|
||||||
}
|
}
|
||||||
hdr.typeName = typeName;
|
hdr.typeName = typeName;
|
||||||
if (auto r = ox::atoi(versionStr.c_str()); r.error == 0) {
|
std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
|
||||||
hdr.typeVersion = r.value;
|
hdr.data = buffRaw;
|
||||||
}
|
|
||||||
hdr.data = buff;
|
|
||||||
hdr.dataSize = buffLen;
|
hdr.dataSize = buffLen;
|
||||||
return hdr;
|
return hdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ClawHeader> readClawHeader(const ox::Buffer &buff) noexcept {
|
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
|
||||||
return readClawHeader(buff.data(), buff.size());
|
oxRequire(header, readClawHeader(buff));
|
||||||
|
return {{header.data, header.dataSize}};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Buffer> stripClawHeader(const char *buff, std::size_t buffLen) noexcept {
|
Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
|
||||||
oxRequire(header, readClawHeader(buff, buffLen));
|
oxRequire(header, readClawHeader(buff));
|
||||||
Buffer out(header.dataSize);
|
auto const [t, tdErr] = ts.getLoad(
|
||||||
ox::listcpy(out.data(), header.data, out.size());
|
header.typeName, header.typeVersion, header.typeParams);
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
|
|
||||||
return stripClawHeader(buff.data(), buff.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz) noexcept {
|
|
||||||
oxRequire(header, readClawHeader(buff, buffSz));
|
|
||||||
auto const [t, tdErr] = ts.getLoad(header.typeName, header.typeVersion, header.typeParams);
|
|
||||||
if (tdErr) {
|
if (tdErr) {
|
||||||
return OxError(3, "Could not load type descriptor");
|
return OxError(3, "Could not load type descriptor");
|
||||||
}
|
}
|
||||||
@ -83,7 +104,7 @@ Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz
|
|||||||
switch (header.fmt) {
|
switch (header.fmt) {
|
||||||
case ClawFormat::Metal:
|
case ClawFormat::Metal:
|
||||||
{
|
{
|
||||||
ox::BufferReader br(header.data, header.dataSize);
|
ox::BufferReader br({header.data, header.dataSize});
|
||||||
MetalClawReader reader(br);
|
MetalClawReader reader(br);
|
||||||
ModelHandlerInterface handler(&reader);
|
ModelHandlerInterface handler(&reader);
|
||||||
oxReturnError(model(&handler, &obj));
|
oxReturnError(model(&handler, &obj));
|
||||||
@ -92,7 +113,7 @@ Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz
|
|||||||
case ClawFormat::Organic:
|
case ClawFormat::Organic:
|
||||||
{
|
{
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
OrganicClawReader reader(header.data, header.dataSize);
|
OrganicClawReader reader({header.data, header.dataSize});
|
||||||
ModelHandlerInterface handler(&reader);
|
ModelHandlerInterface handler(&reader);
|
||||||
oxReturnError(model(&handler, &obj));
|
oxReturnError(model(&handler, &obj));
|
||||||
return obj;
|
return obj;
|
||||||
@ -106,8 +127,4 @@ Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz
|
|||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ModelObject> readClaw(TypeStore &ts, const Buffer &buff) noexcept {
|
|
||||||
return readClaw(ts, buff.data(), buff.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
39
deps/ox/src/ox/claw/read.hpp
vendored
39
deps/ox/src/ox/claw/read.hpp
vendored
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/std/span.hpp>
|
||||||
#include <ox/mc/read.hpp>
|
#include <ox/mc/read.hpp>
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
#include <ox/oc/read.hpp>
|
#include <ox/oc/read.hpp>
|
||||||
@ -31,17 +32,15 @@ struct ClawHeader {
|
|||||||
std::size_t dataSize = 0;
|
std::size_t dataSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept;
|
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
Result<ClawHeader> readClawHeader(const ox::Buffer &buff) noexcept;
|
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
Result<Buffer> stripClawHeader(const char *buff, std::size_t buffLen) noexcept;
|
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept;
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Error readClaw(const char *buff, std::size_t buffLen, T *val) {
|
Error readClaw(ox::BufferView buff, T &val) {
|
||||||
oxRequire(header, readClawHeader(buff, buffLen));
|
oxRequire(header, readClawHeader(buff));
|
||||||
if (header.typeName != getModelTypeName<T>()) {
|
if (header.typeName != getModelTypeName<T>()) {
|
||||||
return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
|
return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
|
||||||
}
|
}
|
||||||
@ -51,16 +50,16 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
|
|||||||
switch (header.fmt) {
|
switch (header.fmt) {
|
||||||
case ClawFormat::Metal:
|
case ClawFormat::Metal:
|
||||||
{
|
{
|
||||||
ox::BufferReader br(header.data, header.dataSize);
|
ox::BufferReader br({header.data, header.dataSize});
|
||||||
MetalClawReader reader(br);
|
MetalClawReader reader(br);
|
||||||
ModelHandlerInterface handler(&reader);
|
ModelHandlerInterface handler(&reader);
|
||||||
return model(&handler, val);
|
return model(&handler, &val);
|
||||||
}
|
}
|
||||||
case ClawFormat::Organic:
|
case ClawFormat::Organic:
|
||||||
{
|
{
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
OrganicClawReader reader(header.data, header.dataSize);
|
OrganicClawReader reader(header.data, header.dataSize);
|
||||||
return model(&reader, val);
|
return model(&reader, &val);
|
||||||
#else
|
#else
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -72,24 +71,12 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result<T> readClaw(const char *buff, std::size_t buffLen) {
|
Result<T> readClaw(ox::BufferView buff) {
|
||||||
T val;
|
Result<T> val;
|
||||||
oxReturnError(readClaw(buff, buffLen, &val));
|
oxReturnError(readClaw(buff, val.value));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept;
|
||||||
Error readClaw(const Buffer &buff, T *val) {
|
|
||||||
return readClaw<T>(buff.data(), buff.size(), val);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Result<T> readClaw(const Buffer &buff) {
|
|
||||||
return readClaw<T>(buff.data(), buff.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz) noexcept;
|
|
||||||
|
|
||||||
Result<ModelObject> readClaw(TypeStore &ts, const Buffer &buff) noexcept;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
1
deps/ox/src/ox/claw/test/CMakeLists.txt
vendored
1
deps/ox/src/ox/claw/test/CMakeLists.txt
vendored
@ -10,5 +10,6 @@ target_link_libraries(
|
|||||||
|
|
||||||
add_test("[ox/claw] ClawHeaderReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader)
|
add_test("[ox/claw] ClawHeaderReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader)
|
||||||
add_test("[ox/claw] ClawHeaderReader2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader2)
|
add_test("[ox/claw] ClawHeaderReader2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader2)
|
||||||
|
add_test("[ox/claw] ClawHeaderReadTypeId" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReadTypeId)
|
||||||
add_test("[ox/claw] ClawWriter" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawWriter)
|
add_test("[ox/claw] ClawWriter" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawWriter)
|
||||||
add_test("[ox/claw] ClawReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawReader)
|
add_test("[ox/claw] ClawReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawReader)
|
||||||
|
16
deps/ox/src/ox/claw/test/tests.cpp
vendored
16
deps/ox/src/ox/claw/test/tests.cpp
vendored
@ -109,7 +109,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
"ClawHeaderReader",
|
"ClawHeaderReader",
|
||||||
[] {
|
[] {
|
||||||
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
|
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
|
||||||
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
|
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
|
||||||
oxAssert(err, "Error parsing header");
|
oxAssert(err, "Error parsing header");
|
||||||
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
|
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
|
||||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
|
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
|
||||||
@ -121,7 +121,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
"ClawHeaderReader2",
|
"ClawHeaderReader2",
|
||||||
[] {
|
[] {
|
||||||
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
|
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
|
||||||
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
|
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
|
||||||
oxAssert(err, "Error parsing header");
|
oxAssert(err, "Error parsing header");
|
||||||
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
|
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
|
||||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
|
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
|
||||||
@ -129,6 +129,16 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ClawHeaderReadTypeId",
|
||||||
|
[] {
|
||||||
|
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
|
||||||
|
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
|
||||||
|
oxRequire(actual, ox::readClawTypeId({hdr.data(), hdr.len() + 1}));
|
||||||
|
oxExpect(actual, expected);
|
||||||
|
return ox::Error{};
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ClawWriter",
|
"ClawWriter",
|
||||||
[] {
|
[] {
|
||||||
@ -156,7 +166,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
testIn.Struct.String = "Test String 2";
|
testIn.Struct.String = "Test String 2";
|
||||||
const auto [buff, err] = ox::writeMC(testIn);
|
const auto [buff, err] = ox::writeMC(testIn);
|
||||||
oxAssert(err, "writeClaw failed");
|
oxAssert(err, "writeClaw failed");
|
||||||
oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readClaw failed");
|
oxAssert(ox::readMC(buff, testOut), "readClaw failed");
|
||||||
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
||||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||||
|
10
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
10
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
@ -159,7 +159,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
|
|||||||
|
|
||||||
// determine if already exists
|
// determine if already exists
|
||||||
auto name = nameBuff;
|
auto name = nameBuff;
|
||||||
oxReturnError(path.get(name));
|
oxReturnError(path.get(*name));
|
||||||
auto childInode = find(PathIterator(*name));
|
auto childInode = find(PathIterator(*name));
|
||||||
if (!childInode.ok()) {
|
if (!childInode.ok()) {
|
||||||
// if this is not the last item in the path and parents is disabled,
|
// if this is not the last item in the path and parents is disabled,
|
||||||
@ -203,7 +203,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
|
|||||||
auto name = nameBuff;
|
auto name = nameBuff;
|
||||||
|
|
||||||
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
|
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
|
||||||
oxReturnError(path.get(name));
|
oxReturnError(path.get(*name));
|
||||||
oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}",
|
oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}",
|
||||||
*name, path.fullPath());
|
*name, path.fullPath());
|
||||||
oxRequire(nextChild, findEntry(*name));
|
oxRequire(nextChild, findEntry(*name));
|
||||||
@ -222,7 +222,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
|
|||||||
// insert the new entry on this directory
|
// insert the new entry on this directory
|
||||||
|
|
||||||
// get the name
|
// get the name
|
||||||
oxReturnError(path.next(name));
|
oxReturnError(path.next(*name));
|
||||||
|
|
||||||
// find existing version of directory
|
// find existing version of directory
|
||||||
oxTracef("ox.fs.Directory.write", "Searching for directory inode {}", m_inodeId);
|
oxTracef("ox.fs.Directory.write", "Searching for directory inode {}", m_inodeId);
|
||||||
@ -263,7 +263,7 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
|
|||||||
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
|
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
|
||||||
}
|
}
|
||||||
auto &name = *nameBuff;
|
auto &name = *nameBuff;
|
||||||
oxReturnError(path.get(&name));
|
oxReturnError(path.get(name));
|
||||||
|
|
||||||
oxTrace("ox.fs.Directory.remove", name);
|
oxTrace("ox.fs.Directory.remove", name);
|
||||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||||
@ -343,7 +343,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(Path
|
|||||||
|
|
||||||
// determine if already exists
|
// determine if already exists
|
||||||
auto name = nameBuff;
|
auto name = nameBuff;
|
||||||
oxReturnError(path.get(name));
|
oxReturnError(path.get(*name));
|
||||||
|
|
||||||
oxRequire(v, findEntry(*name));
|
oxRequire(v, findEntry(*name));
|
||||||
// recurse if not at end of path
|
// recurse if not at end of path
|
||||||
|
43
deps/ox/src/ox/fs/filesystem/pathiterator.cpp
vendored
43
deps/ox/src/ox/fs/filesystem/pathiterator.cpp
vendored
@ -61,8 +61,9 @@ Error PathIterator::fileName(char *out, std::size_t outSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gets the get item in the path
|
// Gets the get item in the path
|
||||||
Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
|
Error PathIterator::get(IString<MaxFileNameLength> &fileName) {
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
|
std::ignore = fileName.resize(MaxFileNameLength);
|
||||||
if (m_iterator >= m_maxSize) {
|
if (m_iterator >= m_maxSize) {
|
||||||
oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
|
oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
@ -84,22 +85,25 @@ Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
|
|||||||
const auto end = static_cast<size_t>(substr - m_path);
|
const auto end = static_cast<size_t>(substr - m_path);
|
||||||
size = end - start;
|
size = end - start;
|
||||||
// cannot fit the output in the output parameter
|
// cannot fit the output in the output parameter
|
||||||
if (size >= pathOutSize || size == 0) {
|
if (size >= MaxFileNameLength || size == 0) {
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
ox::memcpy(pathOut, &m_path[start], size);
|
ox::memcpy(fileName.data(), &m_path[start], size);
|
||||||
// truncate trailing /
|
// truncate trailing /
|
||||||
if (size && pathOut[size - 1] == '/') {
|
if (size && fileName[size - 1] == '/') {
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
pathOut[size] = 0; // end with null terminator
|
oxReturnError(fileName.resize(size));
|
||||||
return OxError(0);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the get item in the path
|
/**
|
||||||
Error PathIterator::next(char *pathOut, std::size_t pathOutSize) {
|
* @return 0 if no error
|
||||||
|
*/
|
||||||
|
Error PathIterator::next(IString<MaxFileNameLength> &fileName) {
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
auto retval = OxError(1);
|
auto retval = OxError(1);
|
||||||
|
std::ignore = fileName.resize(MaxFileNameLength);
|
||||||
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
|
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
|
||||||
retval = OxError(0);
|
retval = OxError(0);
|
||||||
if (m_path[m_iterator] == '/') {
|
if (m_path[m_iterator] == '/') {
|
||||||
@ -115,34 +119,21 @@ Error PathIterator::next(char *pathOut, std::size_t pathOutSize) {
|
|||||||
const auto end = static_cast<size_t>(substr - m_path);
|
const auto end = static_cast<size_t>(substr - m_path);
|
||||||
size = end - start;
|
size = end - start;
|
||||||
// cannot fit the output in the output parameter
|
// cannot fit the output in the output parameter
|
||||||
if (size >= pathOutSize) {
|
if (size >= MaxFileNameLength) {
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
ox::memcpy(pathOut, &m_path[start], size);
|
ox::memcpy(fileName.data(), &m_path[start], size);
|
||||||
}
|
}
|
||||||
// truncate trailing /
|
// truncate trailing /
|
||||||
if (size && pathOut[size - 1] == '/') {
|
if (size && fileName[size - 1] == '/') {
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
pathOut[size] = 0; // end with null terminator
|
fileName[size] = 0; // end with null terminator
|
||||||
|
oxReturnError(fileName.resize(size));
|
||||||
m_iterator += size;
|
m_iterator += size;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 0 if no error
|
|
||||||
*/
|
|
||||||
Error PathIterator::get(IString<MaxFileNameLength> *fileName) {
|
|
||||||
return get(fileName->data(), fileName->cap());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 0 if no error
|
|
||||||
*/
|
|
||||||
Error PathIterator::next(IString<MaxFileNameLength> *fileName) {
|
|
||||||
return next(fileName->data(), fileName->cap());
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<std::size_t> PathIterator::nextSize() const {
|
Result<std::size_t> PathIterator::nextSize() const {
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
auto retval = OxError(1);
|
auto retval = OxError(1);
|
||||||
|
14
deps/ox/src/ox/fs/filesystem/pathiterator.hpp
vendored
14
deps/ox/src/ox/fs/filesystem/pathiterator.hpp
vendored
@ -41,22 +41,12 @@ class PathIterator {
|
|||||||
/**
|
/**
|
||||||
* @return 0 if no error
|
* @return 0 if no error
|
||||||
*/
|
*/
|
||||||
Error next(char *pathOut, std::size_t pathOutSize);
|
Error next(FileName &fileName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 0 if no error
|
* @return 0 if no error
|
||||||
*/
|
*/
|
||||||
Error get(char *pathOut, std::size_t pathOutSize);
|
Error get(FileName &fileName);
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 0 if no error
|
|
||||||
*/
|
|
||||||
Error next(FileName *fileName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 0 if no error
|
|
||||||
*/
|
|
||||||
Error get(FileName *fileName);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 0 if no error
|
* @return 0 if no error
|
||||||
|
37
deps/ox/src/ox/fs/test/tests.cpp
vendored
37
deps/ox/src/ox/fs/test/tests.cpp
vendored
@ -60,10 +60,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
|||||||
[](ox::StringView) {
|
[](ox::StringView) {
|
||||||
auto const path = ox::String("/usr/share/charset.gbag");
|
auto const path = ox::String("/usr/share/charset.gbag");
|
||||||
ox::PathIterator it(path.c_str(), path.len());
|
ox::PathIterator it(path.c_str(), path.len());
|
||||||
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
|
ox::FileName buff;
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -72,9 +72,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
|||||||
[](ox::StringView) {
|
[](ox::StringView) {
|
||||||
auto const path = ox::String("/usr/share/");
|
auto const path = ox::String("/usr/share/");
|
||||||
ox::PathIterator it(path.c_str(), path.len());
|
ox::PathIterator it(path.c_str(), path.len());
|
||||||
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
|
ox::FileName buff;
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -83,8 +83,8 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
|||||||
[](ox::StringView) {
|
[](ox::StringView) {
|
||||||
auto const path = ox::String("/");
|
auto const path = ox::String("/");
|
||||||
ox::PathIterator it(path.c_str(), path.len());
|
ox::PathIterator it(path.c_str(), path.len());
|
||||||
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
|
ox::FileName buff;
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -93,10 +93,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
|||||||
[](ox::StringView) {
|
[](ox::StringView) {
|
||||||
auto const path = ox::String("usr/share/charset.gbag");
|
auto const path = ox::String("usr/share/charset.gbag");
|
||||||
ox::PathIterator it(path.c_str(), path.len());
|
ox::PathIterator it(path.c_str(), path.len());
|
||||||
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
|
ox::FileName buff;
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -105,9 +105,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
|||||||
[](ox::StringView) {
|
[](ox::StringView) {
|
||||||
auto const path = ox::String("usr/share/");
|
auto const path = ox::String("usr/share/");
|
||||||
ox::PathIterator it(path.c_str(), path.len());
|
ox::PathIterator it(path.c_str(), path.len());
|
||||||
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
|
ox::FileName buff;
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
|
||||||
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -237,8 +237,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, const char **args) {
|
int main(int argc, const char **args) {
|
||||||
if (argc < 3) {
|
if (argc < 2) {
|
||||||
oxError("Must specify test to run and test argument");
|
oxError("Must specify test to run");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
ox::StringView const testName = args[1];
|
ox::StringView const testName = args[1];
|
||||||
ox::StringView const testArg = args[2] ? args[2] : nullptr;
|
ox::StringView const testArg = args[2] ? args[2] : nullptr;
|
||||||
|
2
deps/ox/src/ox/mc/intops.hpp
vendored
2
deps/ox/src/ox/mc/intops.hpp
vendored
@ -185,7 +185,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
|
|||||||
template<typename I>
|
template<typename I>
|
||||||
Result<I> decodeInteger(McInt m) noexcept {
|
Result<I> decodeInteger(McInt m) noexcept {
|
||||||
std::size_t bytesRead{};
|
std::size_t bytesRead{};
|
||||||
BufferReader br(reinterpret_cast<const char*>(m.data), 9);
|
BufferReader br({reinterpret_cast<const char*>(m.data), 9});
|
||||||
return decodeInteger<I>(br, &bytesRead);
|
return decodeInteger<I>(br, &bytesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
deps/ox/src/ox/mc/read.hpp
vendored
39
deps/ox/src/ox/mc/read.hpp
vendored
@ -322,9 +322,6 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
|
|||||||
*val = BasicString<SmallStringSize>(cap);
|
*val = BasicString<SmallStringSize>(cap);
|
||||||
auto data = val->data();
|
auto data = val->data();
|
||||||
// read the string
|
// read the string
|
||||||
if (static_cast<StringLength>(cap) < size) {
|
|
||||||
return OxError(McOutputBuffEnded);
|
|
||||||
}
|
|
||||||
oxReturnError(m_reader.read(data, size));
|
oxReturnError(m_reader.read(data, size));
|
||||||
} else {
|
} else {
|
||||||
*val = "";
|
*val = "";
|
||||||
@ -336,8 +333,23 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
|
|||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
template<std::size_t L>
|
template<std::size_t L>
|
||||||
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, IString<L> *val) noexcept {
|
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept {
|
||||||
return fieldCString(name, val->data(), val->cap());
|
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
|
||||||
|
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
|
||||||
|
// read the length
|
||||||
|
std::size_t bytesRead = 0;
|
||||||
|
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
|
||||||
|
*val = IString<L>();
|
||||||
|
oxReturnError(val->resize(size));
|
||||||
|
auto const data = val->data();
|
||||||
|
// read the string
|
||||||
|
oxReturnError(m_reader.read(data, size));
|
||||||
|
} else {
|
||||||
|
*val = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++m_field;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Reader_c Reader>
|
template<Reader_c Reader>
|
||||||
@ -524,25 +536,20 @@ constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
|
|||||||
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
|
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept {
|
Error readMC(ox::BufferView buff, T &val) noexcept {
|
||||||
BufferReader br(buff, buffLen);
|
BufferReader br(buff);
|
||||||
MetalClawReader reader(br);
|
MetalClawReader reader(br);
|
||||||
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
|
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
|
||||||
return model(&handler, val);
|
return model(&handler, &val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result<T> readMC(const char *buff, std::size_t buffLen) noexcept {
|
Result<T> readMC(ox::BufferView buff) noexcept {
|
||||||
T val;
|
Result<T> val;
|
||||||
oxReturnError(readMC(buff, buffLen, &val));
|
oxReturnError(readMC(buff, val.value));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Result<T> readMC(const Buffer &buff) noexcept {
|
|
||||||
return readMC<T>(buff.data(), buff.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
extern template class ModelHandlerInterface<MetalClawReaderTemplate<BufferReader>>;
|
extern template class ModelHandlerInterface<MetalClawReaderTemplate<BufferReader>>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
9
deps/ox/src/ox/mc/test/tests.cpp
vendored
9
deps/ox/src/ox/mc/test/tests.cpp
vendored
@ -143,7 +143,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
// run tests
|
// run tests
|
||||||
const auto [buff, err] = ox::writeMC(testIn);
|
const auto [buff, err] = ox::writeMC(testIn);
|
||||||
oxAssert(err, "writeMC failed");
|
oxAssert(err, "writeMC failed");
|
||||||
oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readMC failed");
|
oxAssert(ox::readMC(buff, testOut), "readMC failed");
|
||||||
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
||||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||||
@ -157,7 +157,8 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||||
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
||||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||||
oxAssert(testIn.IString == testOut.IString, "IString value mismatch");
|
oxDebugf("{}", testOut.IString.len());
|
||||||
|
oxExpect(testIn.IString, testOut.IString);
|
||||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||||
@ -319,7 +320,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
oxAssert(typeErr, "Descriptor write failed");
|
oxAssert(typeErr, "Descriptor write failed");
|
||||||
ox::ModelObject testOut;
|
ox::ModelObject testOut;
|
||||||
oxReturnError(testOut.setType(type));
|
oxReturnError(testOut.setType(type));
|
||||||
oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
|
oxAssert(ox::readMC(dataBuff, testOut), "Data read failed");
|
||||||
oxAssert(testOut.at("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
|
oxAssert(testOut.at("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
|
||||||
oxAssert(testOut.at("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
|
oxAssert(testOut.at("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
|
||||||
oxAssert(testOut.at("IString").unwrap()->get<ox::String>() == testIn.IString.c_str(), "testOut.String failed");
|
oxAssert(testOut.at("IString").unwrap()->get<ox::String>() == testIn.IString.c_str(), "testOut.String failed");
|
||||||
@ -369,7 +370,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
ox::TypeStore typeStore;
|
ox::TypeStore typeStore;
|
||||||
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
|
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
|
||||||
oxAssert(typeErr, "Descriptor write failed");
|
oxAssert(typeErr, "Descriptor write failed");
|
||||||
ox::BufferReader br(dataBuff, dataBuffLen);
|
ox::BufferReader br({dataBuff, dataBuffLen});
|
||||||
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, br,
|
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, br,
|
||||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
|
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
|
||||||
//std::cout << f.fieldName.c_str() << '\n';
|
//std::cout << f.fieldName.c_str() << '\n';
|
||||||
|
2
deps/ox/src/ox/mc/write.hpp
vendored
2
deps/ox/src/ox/mc/write.hpp
vendored
@ -207,7 +207,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
|
|||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
template<std::size_t L>
|
template<std::size_t L>
|
||||||
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
|
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
|
||||||
return fieldCString(name, val->data(), val->cap());
|
return fieldCString(name, val->data(), val->len());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Writer_c Writer>
|
template<Writer_c Writer>
|
||||||
|
4
deps/ox/src/ox/model/desctypes.hpp
vendored
4
deps/ox/src/ox/model/desctypes.hpp
vendored
@ -37,12 +37,12 @@ constexpr auto buildTypeId() noexcept {
|
|||||||
static constexpr auto buildTypeId(CRStringView name, int version,
|
static constexpr auto buildTypeId(CRStringView name, int version,
|
||||||
const TypeParamPack &typeParams = {}) noexcept {
|
const TypeParamPack &typeParams = {}) noexcept {
|
||||||
String tp;
|
String tp;
|
||||||
if (typeParams.size()) {
|
if (!typeParams.empty()) {
|
||||||
tp = "#";
|
tp = "#";
|
||||||
for (const auto &p : typeParams) {
|
for (const auto &p : typeParams) {
|
||||||
tp += p + ",";
|
tp += p + ",";
|
||||||
}
|
}
|
||||||
tp = tp.substr(0, tp.len() - 1);
|
tp.resize(tp.len() - 1);
|
||||||
tp += "#";
|
tp += "#";
|
||||||
}
|
}
|
||||||
return ox::sfmt("{}{};{}", name, tp, version);
|
return ox::sfmt("{}{};{}", name, tp, version);
|
||||||
|
14
deps/ox/src/ox/model/typenamecatcher.hpp
vendored
14
deps/ox/src/ox/model/typenamecatcher.hpp
vendored
@ -97,6 +97,7 @@ struct TypeInfoCatcher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
[[nodiscard]]
|
||||||
constexpr int getModelTypeVersion(T *val) noexcept {
|
constexpr int getModelTypeVersion(T *val) noexcept {
|
||||||
TypeInfoCatcher nc;
|
TypeInfoCatcher nc;
|
||||||
std::ignore = model(&nc, val);
|
std::ignore = model(&nc, val);
|
||||||
@ -104,6 +105,7 @@ constexpr int getModelTypeVersion(T *val) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
[[nodiscard]]
|
||||||
constexpr int getModelTypeVersion() noexcept {
|
constexpr int getModelTypeVersion() noexcept {
|
||||||
std::allocator<T> a;
|
std::allocator<T> a;
|
||||||
const auto t = a.allocate(1);
|
const auto t = a.allocate(1);
|
||||||
@ -113,6 +115,7 @@ constexpr int getModelTypeVersion() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
[[nodiscard]]
|
||||||
consteval int requireModelTypeVersion() noexcept {
|
consteval int requireModelTypeVersion() noexcept {
|
||||||
constexpr auto version = getModelTypeVersion<T>();
|
constexpr auto version = getModelTypeVersion<T>();
|
||||||
static_assert(version != 0, "TypeVersion is required");
|
static_assert(version != 0, "TypeVersion is required");
|
||||||
@ -120,6 +123,7 @@ consteval int requireModelTypeVersion() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Str = const char*>
|
template<typename T, typename Str = const char*>
|
||||||
|
[[nodiscard]]
|
||||||
constexpr Str getModelTypeName(T *val) noexcept {
|
constexpr Str getModelTypeName(T *val) noexcept {
|
||||||
TypeNameCatcher nc;
|
TypeNameCatcher nc;
|
||||||
std::ignore = model(&nc, val);
|
std::ignore = model(&nc, val);
|
||||||
@ -127,6 +131,7 @@ constexpr Str getModelTypeName(T *val) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Str = const char*>
|
template<typename T, typename Str = const char*>
|
||||||
|
[[nodiscard]]
|
||||||
constexpr Str getModelTypeName() noexcept {
|
constexpr Str getModelTypeName() noexcept {
|
||||||
std::allocator<T> a;
|
std::allocator<T> a;
|
||||||
auto t = a.allocate(1);
|
auto t = a.allocate(1);
|
||||||
@ -136,8 +141,10 @@ constexpr Str getModelTypeName() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
[[nodiscard]]
|
||||||
consteval auto requireModelTypeName() noexcept {
|
consteval auto requireModelTypeName() noexcept {
|
||||||
constexpr auto name = getModelTypeName<T>();
|
constexpr auto name = getModelTypeName<T>();
|
||||||
|
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,13 +154,6 @@ constexpr auto ModelTypeName_v = getModelTypeName<T, Str>();
|
|||||||
template<typename T, typename Str = const char*>
|
template<typename T, typename Str = const char*>
|
||||||
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
|
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
|
||||||
|
|
||||||
template<typename T, typename Str = const char*>
|
|
||||||
constexpr auto ModelTypeVersionStr_v = [] {
|
|
||||||
constexpr auto version = ModelTypeVersion_v<T>;
|
|
||||||
constexpr auto versionStr = ox::sfmt("{}", version);
|
|
||||||
return ox::IString<versionStr.len()>{versionStr};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr auto ModelTypeId_v = [] {
|
constexpr auto ModelTypeId_v = [] {
|
||||||
constexpr auto name = ModelTypeName_v<T, ox::StringView>;
|
constexpr auto name = ModelTypeName_v<T, ox::StringView>;
|
||||||
|
2
deps/ox/src/ox/model/typestore.hpp
vendored
2
deps/ox/src/ox/model/typestore.hpp
vendored
@ -101,7 +101,7 @@ class TypeStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::CRStringView) noexcept {
|
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
deps/ox/src/ox/model/walk.hpp
vendored
2
deps/ox/src/ox/model/walk.hpp
vendored
@ -64,7 +64,7 @@ constexpr Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rd
|
|||||||
|
|
||||||
template<typename Reader, typename T>
|
template<typename Reader, typename T>
|
||||||
constexpr void DataWalker<Reader, T>::pushNamePath(const FieldName &fn) noexcept {
|
constexpr void DataWalker<Reader, T>::pushNamePath(const FieldName &fn) noexcept {
|
||||||
m_path.push_back(fn);
|
m_path.emplace_back(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Reader, typename T>
|
template<typename Reader, typename T>
|
||||||
|
37
deps/ox/src/ox/oc/read.hpp
vendored
37
deps/ox/src/ox/oc/read.hpp
vendored
@ -207,7 +207,19 @@ Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
|
|||||||
|
|
||||||
template<std::size_t L>
|
template<std::size_t L>
|
||||||
Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept {
|
Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept {
|
||||||
return fieldCString(key, val->data(), val->cap());
|
auto err = OxError(0);
|
||||||
|
if (targetValid()) {
|
||||||
|
const auto &jv = value(key);
|
||||||
|
if (jv.empty()) {
|
||||||
|
*val = IString<L>{};
|
||||||
|
} else if (jv.isString()) {
|
||||||
|
*val = jv.asString().c_str();
|
||||||
|
} else {
|
||||||
|
err = OxError(1, "Type mismatch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++m_fieldIt;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// array handler
|
// array handler
|
||||||
@ -246,18 +258,18 @@ Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcep
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error readOC(const char *buff, std::size_t buffSize, auto *val) noexcept {
|
Error readOC(BufferView buff, auto &val) noexcept {
|
||||||
// OrganicClawReader constructor can throw, but readOC should return its errors.
|
// OrganicClawReader constructor can throw, but readOC should return its errors.
|
||||||
try {
|
try {
|
||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::CharReaderBuilder parserBuilder;
|
Json::CharReaderBuilder parserBuilder;
|
||||||
auto parser = UniquePtr<Json::CharReader>(parserBuilder.newCharReader());
|
auto parser = UniquePtr<Json::CharReader>(parserBuilder.newCharReader());
|
||||||
if (!parser->parse(buff, buff + buffSize, &doc, nullptr)) {
|
if (!parser->parse(buff.data(), buff.data() + buff.size(), &doc, nullptr)) {
|
||||||
return OxError(1, "Could not parse JSON");
|
return OxError(1, "Could not parse JSON");
|
||||||
}
|
}
|
||||||
OrganicClawReader reader(buff, buffSize);
|
OrganicClawReader reader(buff.data(), buff.size());
|
||||||
ModelHandlerInterface handler(&reader);
|
ModelHandlerInterface handler(&reader);
|
||||||
return model(&handler, val);
|
return model(&handler, &val);
|
||||||
} catch (const Error &err) {
|
} catch (const Error &err) {
|
||||||
return err;
|
return err;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -266,20 +278,15 @@ Error readOC(const char *buff, std::size_t buffSize, auto *val) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result<T> readOC(const char *json, std::size_t jsonLen) noexcept {
|
Result<T> readOC(BufferView buff) noexcept {
|
||||||
T val;
|
Result<T> val;
|
||||||
oxReturnError(readOC(json, jsonLen, &val));
|
oxReturnError(readOC(buff, val.value));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result<T> readOC(const char *json) noexcept {
|
Result<T> readOC(ox::StringView json) noexcept {
|
||||||
return readOC<T>(json, ox::strlen(json));
|
return readOC<T>(ox::BufferView{json.data(), json.len()});
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Result<T> readOC(const Buffer &buff) noexcept {
|
|
||||||
return readOC<T>(buff.data(), buff.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
2
deps/ox/src/ox/oc/test/tests.cpp
vendored
2
deps/ox/src/ox/oc/test/tests.cpp
vendored
@ -211,7 +211,7 @@ const std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
oxAssert(type.error, "Descriptor write failed");
|
oxAssert(type.error, "Descriptor write failed");
|
||||||
ox::ModelObject testOut;
|
ox::ModelObject testOut;
|
||||||
oxReturnError(testOut.setType(type.value));
|
oxReturnError(testOut.setType(type.value));
|
||||||
oxAssert(ox::readOC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
|
oxAssert(ox::readOC(dataBuff, testOut), "Data read failed");
|
||||||
oxAssert(testOut.get("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
|
oxAssert(testOut.get("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
|
||||||
oxAssert(testOut.get("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
|
oxAssert(testOut.get("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
|
||||||
oxAssert(testOut.get("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
|
oxAssert(testOut.get("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
|
||||||
|
5
deps/ox/src/ox/std/CMakeLists.txt
vendored
5
deps/ox/src/ox/std/CMakeLists.txt
vendored
@ -45,7 +45,7 @@ add_library(
|
|||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
target_compile_options(OxStd PRIVATE -Wsign-conversion)
|
target_compile_options(OxStd PRIVATE -Wsign-conversion)
|
||||||
target_compile_options(OxStd PRIVATE -Wconversion)
|
target_compile_options(OxStd PRIVATE -Wconversion)
|
||||||
if(${OX_OS_LINUX})
|
if(${OX_OS_LINUX} AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
target_compile_options(OxStd PUBLIC -export-dynamic)
|
target_compile_options(OxStd PUBLIC -export-dynamic)
|
||||||
#target_link_options(OxStd PUBLIC -W1,-E)
|
#target_link_options(OxStd PUBLIC -W1,-E)
|
||||||
elseif(${OX_OS_FREEBSD})
|
elseif(${OX_OS_FREEBSD})
|
||||||
@ -81,6 +81,7 @@ target_link_libraries(
|
|||||||
OxStd PUBLIC
|
OxStd PUBLIC
|
||||||
$<$<CXX_COMPILER_ID:GNU>:gcc>
|
$<$<CXX_COMPILER_ID:GNU>:gcc>
|
||||||
OxTraceHook
|
OxTraceHook
|
||||||
|
CityHash
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
@ -116,6 +117,7 @@ install(
|
|||||||
ranges.hpp
|
ranges.hpp
|
||||||
serialize.hpp
|
serialize.hpp
|
||||||
size.hpp
|
size.hpp
|
||||||
|
smallmap.hpp
|
||||||
stacktrace.hpp
|
stacktrace.hpp
|
||||||
std.hpp
|
std.hpp
|
||||||
stddef.hpp
|
stddef.hpp
|
||||||
@ -123,6 +125,7 @@ install(
|
|||||||
stringliteral.hpp
|
stringliteral.hpp
|
||||||
stringview.hpp
|
stringview.hpp
|
||||||
strongint.hpp
|
strongint.hpp
|
||||||
|
strconv.hpp
|
||||||
strops.hpp
|
strops.hpp
|
||||||
trace.hpp
|
trace.hpp
|
||||||
typeinfo.hpp
|
typeinfo.hpp
|
||||||
|
4
deps/ox/src/ox/std/array.hpp
vendored
4
deps/ox/src/ox/std/array.hpp
vendored
@ -137,12 +137,16 @@ constexpr Array<T, ArraySize>::Array(Array &&other) noexcept {
|
|||||||
|
|
||||||
template<typename T, std::size_t ArraySize>
|
template<typename T, std::size_t ArraySize>
|
||||||
constexpr bool Array<T, ArraySize>::operator==(const Array &other) const {
|
constexpr bool Array<T, ArraySize>::operator==(const Array &other) const {
|
||||||
|
if (std::is_constant_evaluated()) {
|
||||||
for (std::size_t i = 0; i < ArraySize; i++) {
|
for (std::size_t i = 0; i < ArraySize; i++) {
|
||||||
if (!(m_items[i] == other.m_items[i])) {
|
if (!(m_items[i] == other.m_items[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return memcmp(this, &other, sizeof(*this)) == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, std::size_t ArraySize>
|
template<typename T, std::size_t ArraySize>
|
||||||
|
7
deps/ox/src/ox/std/buffer.hpp
vendored
7
deps/ox/src/ox/std/buffer.hpp
vendored
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
#include "reader.hpp"
|
#include "reader.hpp"
|
||||||
|
#include "span.hpp"
|
||||||
#include "vector.hpp"
|
#include "vector.hpp"
|
||||||
#include "writer.hpp"
|
#include "writer.hpp"
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ namespace ox {
|
|||||||
extern template class Vector<char>;
|
extern template class Vector<char>;
|
||||||
|
|
||||||
using Buffer = Vector<char>;
|
using Buffer = Vector<char>;
|
||||||
|
using BufferView = SpanView<char>;
|
||||||
|
|
||||||
class BufferWriter {
|
class BufferWriter {
|
||||||
private:
|
private:
|
||||||
@ -174,10 +176,7 @@ class BufferReader {
|
|||||||
char const* m_buff = nullptr;
|
char const* m_buff = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr explicit BufferReader(char const*buff, std::size_t sz) noexcept:
|
constexpr explicit BufferReader(ox::BufferView buffer) noexcept:
|
||||||
m_size(sz), m_buff(buff) {}
|
|
||||||
|
|
||||||
constexpr explicit BufferReader(ox::Buffer const&buffer) noexcept:
|
|
||||||
m_size(buffer.size()), m_buff(buffer.data()) {}
|
m_size(buffer.size()), m_buff(buffer.data()) {}
|
||||||
|
|
||||||
constexpr ox::Result<char> peek() const noexcept {
|
constexpr ox::Result<char> peek() const noexcept {
|
||||||
|
34
deps/ox/src/ox/std/cstrops.hpp
vendored
34
deps/ox/src/ox/std/cstrops.hpp
vendored
@ -112,38 +112,4 @@ constexpr int lastIndexOf(const auto &str, int character, std::size_t maxLen = 0
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Integer, typename T>
|
|
||||||
constexpr T itoa(Integer v, T str) noexcept {
|
|
||||||
if (v) {
|
|
||||||
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
|
|
||||||
ox::ResizedInt_t<Integer, 64> val = v;
|
|
||||||
constexpr auto base = 10;
|
|
||||||
auto it = 0;
|
|
||||||
if (val < 0) {
|
|
||||||
str[static_cast<std::size_t>(it)] = '-';
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
while (mod) {
|
|
||||||
auto digit = val / mod;
|
|
||||||
val %= mod;
|
|
||||||
mod /= base;
|
|
||||||
if (it || digit) {
|
|
||||||
ox::ResizedInt_t<Integer, 64> start = '0';
|
|
||||||
if (digit >= 10) {
|
|
||||||
start = 'a';
|
|
||||||
digit -= 10;
|
|
||||||
}
|
|
||||||
str[static_cast<std::size_t>(it)] = static_cast<typename ox::remove_reference<decltype(str[0])>::type>(start + digit);
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
str[static_cast<std::size_t>(it)] = 0;
|
|
||||||
} else {
|
|
||||||
// 0 is a special case
|
|
||||||
str[0] = '0';
|
|
||||||
str[1] = 0;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
16
deps/ox/src/ox/std/error.hpp
vendored
16
deps/ox/src/ox/std/error.hpp
vendored
@ -234,6 +234,22 @@ struct [[nodiscard]] Result {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
constexpr ox::Result<U> to() & noexcept {
|
||||||
|
if (error) [[unlikely]] {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return U(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U = T>
|
||||||
|
constexpr ox::Result<U> to() && noexcept {
|
||||||
|
if (error) [[unlikely]] {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return U(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
constexpr ox::Result<U> to(auto const&f) & noexcept {
|
constexpr ox::Result<U> to(auto const&f) & noexcept {
|
||||||
if (error) [[unlikely]] {
|
if (error) [[unlikely]] {
|
||||||
|
20
deps/ox/src/ox/std/fmt.hpp
vendored
20
deps/ox/src/ox/std/fmt.hpp
vendored
@ -40,12 +40,17 @@ constexpr StringView toStringView(const char *s) noexcept {
|
|||||||
|
|
||||||
template<bool force = false, std::size_t size>
|
template<bool force = false, std::size_t size>
|
||||||
constexpr StringView toStringView(const IString<size> &s) noexcept {
|
constexpr StringView toStringView(const IString<size> &s) noexcept {
|
||||||
return s.c_str();
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool force = false>
|
||||||
|
constexpr StringView toStringView(ox::StringLiteral s) noexcept {
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool force = false, std::size_t size>
|
template<bool force = false, std::size_t size>
|
||||||
constexpr StringView toStringView(const BasicString<size> &s) noexcept {
|
constexpr StringView toStringView(const BasicString<size> &s) noexcept {
|
||||||
return s.c_str();
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __has_include(<string>)
|
#if __has_include(<string>)
|
||||||
@ -75,14 +80,17 @@ constexpr StringView toStringView(const auto&) noexcept requires(force) {
|
|||||||
class FmtArg {
|
class FmtArg {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char dataStr[10] = {};
|
static constexpr auto DataSz = 23;
|
||||||
|
char dataStr[DataSz] = {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr StringView sv(const T &v, char *dataStr) noexcept {
|
constexpr StringView sv(const T &v, char *dataStr) noexcept {
|
||||||
if constexpr(is_bool_v<T>) {
|
if constexpr(is_bool_v<T>) {
|
||||||
return v ? "true" : "false";
|
return v ? "true" : "false";
|
||||||
} else if constexpr(is_integer_v<T>) {
|
} else if constexpr(is_integer_v<T>) {
|
||||||
return ox::itoa(v, dataStr);
|
ox::CharBuffWriter w(dataStr, DataSz);
|
||||||
|
std::ignore = ox::writeItoa(v, w);
|
||||||
|
return dataStr;
|
||||||
} else {
|
} else {
|
||||||
return toStringView(v);
|
return toStringView(v);
|
||||||
}
|
}
|
||||||
@ -195,7 +203,7 @@ constexpr StringType sfmt(StringView fmt, Args&&... args) noexcept {
|
|||||||
std::ignore = out.append(firstSegment.str, firstSegment.length);
|
std::ignore = out.append(firstSegment.str, firstSegment.length);
|
||||||
const detail::FmtArg elements[sizeof...(args)] = {args...};
|
const detail::FmtArg elements[sizeof...(args)] = {args...};
|
||||||
for (size_t i = 0; i < fmtSegments.size - 1; ++i) {
|
for (size_t i = 0; i < fmtSegments.size - 1; ++i) {
|
||||||
out += elements[i].out;
|
std::ignore = out.append(elements[i].out);
|
||||||
const auto &s = fmtSegments.segments[i + 1];
|
const auto &s = fmtSegments.segments[i + 1];
|
||||||
std::ignore = out.append(s.str, s.length);
|
std::ignore = out.append(s.str, s.length);
|
||||||
}
|
}
|
||||||
@ -203,7 +211,7 @@ constexpr StringType sfmt(StringView fmt, Args&&... args) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T = String>
|
template<typename T = String>
|
||||||
constexpr Result<T> join(auto d, const auto &list) {
|
constexpr Result<T> join(auto const&d, auto const&list) {
|
||||||
if (!list.size()) {
|
if (!list.size()) {
|
||||||
return T("");
|
return T("");
|
||||||
}
|
}
|
||||||
|
170
deps/ox/src/ox/std/hash.hpp
vendored
Normal file
170
deps/ox/src/ox/std/hash.hpp
vendored
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2024 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if __has_include(<functional>)
|
||||||
|
#include <functional>
|
||||||
|
#else
|
||||||
|
namespace std {
|
||||||
|
template<typename T>
|
||||||
|
struct hash;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cityhash/city.h>
|
||||||
|
|
||||||
|
#include "istring.hpp"
|
||||||
|
#include "string.hpp"
|
||||||
|
#include "stringview.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct hash {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(T const&v) const noexcept {
|
||||||
|
return std::hash<T>{}(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<bool> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(bool v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<char> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(char v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<short> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(short v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<int> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(int v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<long> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(long v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<long long> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(long long v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<unsigned char> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(unsigned char v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<unsigned short> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(unsigned short v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<unsigned int> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(unsigned int v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<unsigned long> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(unsigned long v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<unsigned long long> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(unsigned long long v) const noexcept {
|
||||||
|
return static_cast<size_t>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto hashString(ox::StringView const&v) noexcept {
|
||||||
|
if constexpr(sizeof(void*) == 8) {
|
||||||
|
return cityhash::CityHash64(v.data(), v.bytes());
|
||||||
|
} else {
|
||||||
|
return cityhash::CityHash32(v.data(), v.bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<ox::StringView> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(ox::StringView v) const noexcept {
|
||||||
|
return hashString(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<ox::String> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(ox::StringView v) const noexcept {
|
||||||
|
return hashString(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t sz>
|
||||||
|
struct hash<ox::IString<sz>> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(ox::StringView v) const noexcept {
|
||||||
|
return hashString(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<const char*> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(ox::StringView v) const noexcept {
|
||||||
|
return hashString(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
54
deps/ox/src/ox/std/hashmap.hpp
vendored
54
deps/ox/src/ox/std/hashmap.hpp
vendored
@ -9,6 +9,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "algorithm.hpp"
|
#include "algorithm.hpp"
|
||||||
|
#include "hash.hpp"
|
||||||
#include "ignore.hpp"
|
#include "ignore.hpp"
|
||||||
#include "stringview.hpp"
|
#include "stringview.hpp"
|
||||||
#include "strops.hpp"
|
#include "strops.hpp"
|
||||||
@ -32,7 +33,7 @@ class HashMap {
|
|||||||
Vector<Pair*> m_pairs;
|
Vector<Pair*> m_pairs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit constexpr HashMap(std::size_t size = 100);
|
explicit constexpr HashMap(std::size_t size = 127);
|
||||||
|
|
||||||
constexpr HashMap(HashMap const&other);
|
constexpr HashMap(HashMap const&other);
|
||||||
|
|
||||||
@ -68,10 +69,6 @@ class HashMap {
|
|||||||
private:
|
private:
|
||||||
constexpr void expand();
|
constexpr void expand();
|
||||||
|
|
||||||
constexpr static uint64_t hash(Integral_c auto) noexcept;
|
|
||||||
|
|
||||||
constexpr static uint64_t hash(StringView const&) noexcept;
|
|
||||||
|
|
||||||
template<typename KK>
|
template<typename KK>
|
||||||
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
|
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
|
||||||
|
|
||||||
@ -136,17 +133,18 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) noexcep
|
|||||||
|
|
||||||
template<typename K, typename T>
|
template<typename K, typename T>
|
||||||
constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const&k) {
|
constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const&k) {
|
||||||
auto &p = access(m_pairs, k);
|
auto p = &access(m_pairs, k);
|
||||||
if (p == nullptr) {
|
if (*p == nullptr) {
|
||||||
if (static_cast<double>(m_pairs.size()) * 0.7 <
|
if (static_cast<double>(m_pairs.size()) * 0.7 <
|
||||||
static_cast<double>(m_keys.size())) {
|
static_cast<double>(m_keys.size())) {
|
||||||
expand();
|
expand();
|
||||||
|
p = &access(m_pairs, k);
|
||||||
}
|
}
|
||||||
p = new Pair;
|
*p = new Pair;
|
||||||
p->key = k;
|
(*p)->key = k;
|
||||||
m_keys.emplace_back(k);
|
m_keys.emplace_back(k);
|
||||||
}
|
}
|
||||||
return p->value;
|
return (*p)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename T>
|
template<typename K, typename T>
|
||||||
@ -172,14 +170,14 @@ constexpr void HashMap<K, T>::erase(MaybeView_t<K> const&k) {
|
|||||||
if (!contains(k)) {
|
if (!contains(k)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto h = hash(k) % m_pairs.size();
|
auto h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
|
||||||
while (true) {
|
while (true) {
|
||||||
const auto &p = m_pairs[h];
|
const auto &p = m_pairs[h];
|
||||||
if (p == nullptr || p->key == k) {
|
if (p == nullptr || p->key == k) {
|
||||||
std::ignore = m_pairs.erase(h);
|
std::ignore = m_pairs.erase(h);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
h = hash(h) % m_pairs.size();
|
h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k));
|
std::ignore = m_keys.erase(ox::find(m_keys.begin(), m_keys.end(), k));
|
||||||
@ -206,12 +204,12 @@ constexpr void HashMap<K, T>::clear() {
|
|||||||
delete m_pairs[i];
|
delete m_pairs[i];
|
||||||
}
|
}
|
||||||
m_pairs.clear();
|
m_pairs.clear();
|
||||||
m_pairs.resize(100);
|
m_pairs.resize(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename T>
|
template<typename K, typename T>
|
||||||
constexpr void HashMap<K, T>::expand() {
|
constexpr void HashMap<K, T>::expand() {
|
||||||
Vector<Pair*> r;
|
Vector<Pair*> r(m_pairs.size() * 2);
|
||||||
for (std::size_t i = 0; i < m_keys.size(); ++i) {
|
for (std::size_t i = 0; i < m_keys.size(); ++i) {
|
||||||
auto const&k = m_keys[i];
|
auto const&k = m_keys[i];
|
||||||
access(r, k) = std::move(access(m_pairs, k));
|
access(r, k) = std::move(access(m_pairs, k));
|
||||||
@ -219,32 +217,12 @@ constexpr void HashMap<K, T>::expand() {
|
|||||||
m_pairs = std::move(r);
|
m_pairs = std::move(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename T>
|
|
||||||
constexpr uint64_t HashMap<K, T>::hash(Integral_c auto k) noexcept {
|
|
||||||
uint64_t sum = 1;
|
|
||||||
for (auto i = 0u; i < sizeof(K); ++i) {
|
|
||||||
const auto shift = i * 8;
|
|
||||||
const auto v = static_cast<uint64_t>(k >> shift & 0xff);
|
|
||||||
sum += (sum + v) * 7 * sum;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename K, typename T>
|
|
||||||
constexpr uint64_t HashMap<K, T>::hash(StringView const&k) noexcept {
|
|
||||||
uint64_t sum = 1;
|
|
||||||
for (auto i = 0u; i < k.len(); ++i) {
|
|
||||||
sum += ((sum + static_cast<uint64_t>(k[i])) * 7) * sum;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename K, typename T>
|
template<typename K, typename T>
|
||||||
template<typename KK>
|
template<typename KK>
|
||||||
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*> const&pairs, KK const&k) const {
|
constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*> const&pairs, KK const&k) const {
|
||||||
auto h = static_cast<std::size_t>(hash(k) % pairs.size());
|
auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
|
||||||
while (true) {
|
while (true) {
|
||||||
const auto &p = pairs[h];
|
auto const&p = *pairs.at(h).unwrap();
|
||||||
if (p == nullptr || p->key == k) {
|
if (p == nullptr || p->key == k) {
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
@ -256,9 +234,9 @@ constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*
|
|||||||
template<typename K, typename T>
|
template<typename K, typename T>
|
||||||
template<typename KK>
|
template<typename KK>
|
||||||
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, KK const&k) {
|
constexpr typename HashMap<K, T>::Pair *&HashMap<K, T>::access(Vector<Pair*> &pairs, KK const&k) {
|
||||||
auto h = static_cast<std::size_t>(hash(k) % pairs.size());
|
auto h = static_cast<std::size_t>(ox::hash<KK>{}(k) % pairs.size());
|
||||||
while (true) {
|
while (true) {
|
||||||
auto &p = pairs[h];
|
auto &p = *pairs.at(h).unwrap();
|
||||||
if (p == nullptr || p->key == k) {
|
if (p == nullptr || p->key == k) {
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
|
239
deps/ox/src/ox/std/istring.hpp
vendored
239
deps/ox/src/ox/std/istring.hpp
vendored
@ -8,20 +8,25 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ignore.hpp"
|
#include "array.hpp"
|
||||||
|
#include "concepts.hpp"
|
||||||
|
#include "cstrops.hpp"
|
||||||
#include "memops.hpp"
|
#include "memops.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
#include "buffer.hpp"
|
||||||
|
#include "ignore.hpp"
|
||||||
#include "stringview.hpp"
|
#include "stringview.hpp"
|
||||||
#include "strops.hpp"
|
|
||||||
#include "typetraits.hpp"
|
#include "typetraits.hpp"
|
||||||
|
#include "strconv.hpp"
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
// Inline String
|
// Inline String
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
class IString {
|
class IString {
|
||||||
private:
|
private:
|
||||||
char m_buff[buffLen + 1];
|
|
||||||
size_t m_size{};
|
size_t m_size{};
|
||||||
|
ox::Array<char, StrCap + 1> m_buff;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr IString() noexcept;
|
constexpr IString() noexcept;
|
||||||
@ -34,23 +39,8 @@ class IString {
|
|||||||
|
|
||||||
constexpr IString &operator=(const char *str) noexcept;
|
constexpr IString &operator=(const char *str) noexcept;
|
||||||
|
|
||||||
constexpr IString &operator=(char *str) noexcept;
|
|
||||||
|
|
||||||
constexpr IString &operator=(Integer_c auto i) noexcept;
|
constexpr IString &operator=(Integer_c auto i) noexcept;
|
||||||
|
|
||||||
constexpr IString &operator+=(const char *str) noexcept;
|
|
||||||
|
|
||||||
constexpr IString &operator+=(char *str) noexcept;
|
|
||||||
|
|
||||||
constexpr IString &operator+=(Integer_c auto i) noexcept;
|
|
||||||
|
|
||||||
constexpr IString &operator+=(StringView s) noexcept;
|
|
||||||
|
|
||||||
constexpr IString operator+(const char *str) const noexcept;
|
|
||||||
|
|
||||||
constexpr IString operator+(char *str) const noexcept;
|
|
||||||
|
|
||||||
constexpr IString operator+(Integer_c auto i) const noexcept;
|
|
||||||
|
|
||||||
constexpr bool operator==(const char *other) const noexcept;
|
constexpr bool operator==(const char *other) const noexcept;
|
||||||
|
|
||||||
@ -66,6 +56,8 @@ class IString {
|
|||||||
|
|
||||||
constexpr Error append(const char *str, std::size_t strLen) noexcept;
|
constexpr Error append(const char *str, std::size_t strLen) noexcept;
|
||||||
|
|
||||||
|
constexpr Error append(ox::StringView str) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr const char *data() const noexcept;
|
constexpr const char *data() const noexcept;
|
||||||
|
|
||||||
@ -87,11 +79,15 @@ class IString {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr std::size_t bytes() const noexcept;
|
constexpr std::size_t bytes() const noexcept;
|
||||||
|
|
||||||
|
constexpr ox::Error resize(size_t sz) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the capacity of bytes for this string.
|
* Returns the capacity of bytes for this string.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr std::size_t cap() const noexcept;
|
constexpr static std::size_t cap() noexcept {
|
||||||
|
return StrCap;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<std::size_t size>
|
template<std::size_t size>
|
||||||
@ -110,19 +106,21 @@ constexpr IString<size>::IString(const char *str) noexcept: m_buff{{0}} {
|
|||||||
|
|
||||||
template<std::size_t size>
|
template<std::size_t size>
|
||||||
constexpr IString<size> &IString<size>::operator=(Integer_c auto i) noexcept {
|
constexpr IString<size> &IString<size>::operator=(Integer_c auto i) noexcept {
|
||||||
char str[65] = {};
|
ox::Array<char, 22> s;
|
||||||
ox::itoa(i, str);
|
ox::CharBuffWriter w(s);
|
||||||
return this->operator=(str);
|
std::ignore = ox::writeItoa(i, w);
|
||||||
|
this->operator=({s.data(), w.tellp()});
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t size>
|
template<std::size_t size>
|
||||||
constexpr IString<size> &IString<size>::operator=(ox::CRStringView str) noexcept {
|
constexpr IString<size> &IString<size>::operator=(ox::CRStringView str) noexcept {
|
||||||
std::size_t strLen = str.bytes() + 1;
|
std::size_t strLen = str.len();
|
||||||
if (cap() < strLen) {
|
if (cap() < strLen) {
|
||||||
strLen = cap();
|
strLen = cap();
|
||||||
}
|
}
|
||||||
m_size = strLen;
|
m_size = strLen;
|
||||||
ox::listcpy(m_buff, str.data(), strLen);
|
ox::listcpy(m_buff.data(), str.data(), strLen);
|
||||||
// make sure last element is a null terminator
|
// make sure last element is a null terminator
|
||||||
m_buff[strLen] = 0;
|
m_buff[strLen] = 0;
|
||||||
return *this;
|
return *this;
|
||||||
@ -130,156 +128,127 @@ constexpr IString<size> &IString<size>::operator=(ox::CRStringView str) noexcept
|
|||||||
|
|
||||||
template<std::size_t size>
|
template<std::size_t size>
|
||||||
constexpr IString<size> &IString<size>::operator=(const char *str) noexcept {
|
constexpr IString<size> &IString<size>::operator=(const char *str) noexcept {
|
||||||
std::size_t strLen = ox::strlen(str) + 1;
|
operator=(ox::StringView{str});
|
||||||
if (cap() < strLen) {
|
|
||||||
strLen = cap();
|
|
||||||
}
|
|
||||||
m_size = strLen;
|
|
||||||
ox::listcpy(m_buff, str, strLen);
|
|
||||||
// make sure last element is a null terminator
|
|
||||||
m_buff[cap()] = 0;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t size>
|
template<std::size_t StrCap>
|
||||||
constexpr IString<size> &IString<size>::operator=(char *str) noexcept {
|
constexpr bool IString<StrCap>::operator==(const char *other) const noexcept {
|
||||||
return *this = static_cast<const char*>(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> &IString<size>::operator+=(const char *str) noexcept {
|
|
||||||
std::size_t strLen = ox::strlen(str) + 1;
|
|
||||||
std::ignore = append(str, strLen);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> &IString<size>::operator+=(char *str) noexcept {
|
|
||||||
return *this += static_cast<const char*>(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> &IString<size>::operator+=(Integer_c auto i) noexcept {
|
|
||||||
char str[65] = {};
|
|
||||||
ox::itoa(i, str);
|
|
||||||
return this->operator+=(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> &IString<size>::operator+=(StringView s) noexcept {
|
|
||||||
std::size_t strLen = s.bytes();
|
|
||||||
std::ignore = append(s.data(), strLen);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> IString<size>::operator+(const char *str) const noexcept {
|
|
||||||
auto out = *this;
|
|
||||||
std::size_t strLen = ox::strlen(str) + 1;
|
|
||||||
std::ignore = out.append(str, strLen);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> IString<size>::operator+(char *str) const noexcept {
|
|
||||||
return *this + static_cast<const char*>(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t size>
|
|
||||||
constexpr IString<size> IString<size>::operator+(Integer_c auto i) const noexcept {
|
|
||||||
char str[65] = {};
|
|
||||||
ox::itoa(i, str);
|
|
||||||
return this->operator+(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
|
||||||
constexpr bool IString<buffLen>::operator==(const char *other) const noexcept {
|
|
||||||
return ox::StringView(*this) == other;
|
return ox::StringView(*this) == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr bool IString<buffLen>::operator==(const OxString_c auto &other) const noexcept {
|
constexpr bool IString<StrCap>::operator==(const OxString_c auto &other) const noexcept {
|
||||||
return ox::StringView(*this) == ox::StringView(other);
|
return ox::StringView(*this) == ox::StringView(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr bool IString<buffLen>::operator!=(const char *other) const noexcept {
|
constexpr bool IString<StrCap>::operator!=(const char *other) const noexcept {
|
||||||
return !operator==(other);
|
return !operator==(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr bool IString<buffLen>::operator!=(const OxString_c auto &other) noexcept {
|
constexpr bool IString<StrCap>::operator!=(const OxString_c auto &other) noexcept {
|
||||||
return !operator==(other);
|
return !operator==(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr char IString<buffLen>::operator[](std::size_t i) const noexcept {
|
constexpr char IString<StrCap>::operator[](std::size_t i) const noexcept {
|
||||||
return m_buff[i];
|
return m_buff[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr char &IString<buffLen>::operator[](std::size_t i) noexcept {
|
constexpr char &IString<StrCap>::operator[](std::size_t i) noexcept {
|
||||||
return m_buff[i];
|
return m_buff[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr Error IString<buffLen>::append(const char *str, std::size_t strLen) noexcept {
|
constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noexcept {
|
||||||
Error err;
|
Error err{};
|
||||||
auto currentLen = len();
|
auto const currentLen = len();
|
||||||
if (cap() < currentLen + strLen + 1) {
|
if (cap() < currentLen + strLen) {
|
||||||
strLen = cap() - currentLen;
|
strLen = cap() - currentLen;
|
||||||
err = OxError(1, "Insufficient space for full string");
|
err = OxError(1, "Insufficient space for full string");
|
||||||
}
|
}
|
||||||
ox::strncpy(m_buff + currentLen, str, strLen);
|
ox::strncpy(m_buff.data() + currentLen, str, strLen);
|
||||||
// make sure last element is a null terminator
|
// make sure last element is a null terminator
|
||||||
m_buff[currentLen + strLen] = 0;
|
m_buff[currentLen + strLen] = 0;
|
||||||
|
m_size += strLen;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr const char *IString<buffLen>::data() const noexcept {
|
constexpr Error IString<StrCap>::append(ox::StringView str) noexcept {
|
||||||
return static_cast<const char*>(m_buff);
|
return append(str.data(), str.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr char *IString<buffLen>::data() noexcept {
|
constexpr const char *IString<StrCap>::data() const noexcept {
|
||||||
return static_cast<char*>(m_buff);
|
return static_cast<const char*>(m_buff.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr const char *IString<buffLen>::c_str() const noexcept {
|
constexpr char *IString<StrCap>::data() noexcept {
|
||||||
return static_cast<const char*>(m_buff);
|
return static_cast<char*>(m_buff.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t StrCap>
|
||||||
|
constexpr const char *IString<StrCap>::c_str() const noexcept {
|
||||||
|
return static_cast<const char*>(m_buff.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr std::size_t IString<buffLen>::len() const noexcept {
|
constexpr std::size_t IString<StrCap>::len() const noexcept {
|
||||||
std::size_t length = 0;
|
return m_size;
|
||||||
for (std::size_t i = 0; i < buffLen; i++) {
|
|
||||||
uint8_t b = static_cast<uint8_t>(m_buff[i]);
|
|
||||||
if (b) {
|
|
||||||
const auto asciiChar = (b & 128) == 0;
|
|
||||||
const auto utf8Char = (b & (256 << 6)) == (256 << 6);
|
|
||||||
if (asciiChar || utf8Char) {
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr std::size_t IString<buffLen>::bytes() const noexcept {
|
constexpr std::size_t IString<StrCap>::bytes() const noexcept {
|
||||||
std::size_t i = 0;
|
return m_size + 1;
|
||||||
for (i = 0; i < buffLen && m_buff[i]; i++);
|
|
||||||
return i + 1; // add one for null terminator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t StrCap>
|
||||||
constexpr std::size_t IString<buffLen>::cap() const noexcept {
|
constexpr ox::Error IString<StrCap>::resize(size_t sz) noexcept {
|
||||||
return buffLen;
|
if (sz > StrCap) [[unlikely]] {
|
||||||
|
return OxError(1, "Trying to extend IString beyond its cap");
|
||||||
|
}
|
||||||
|
for (auto i = m_size; i < sz; ++i) {
|
||||||
|
m_buff[i] = 0;
|
||||||
|
}
|
||||||
|
m_size = sz;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t sz>
|
||||||
|
struct MaybeView<ox::IString<sz>> {
|
||||||
|
using type = ox::StringView;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<Integer_c Integer>
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr auto itoa(Integer v) noexcept {
|
||||||
|
constexpr auto Cap = [] {
|
||||||
|
auto out = 0;
|
||||||
|
switch (sizeof(Integer)) {
|
||||||
|
case 1:
|
||||||
|
out = 3;
|
||||||
|
case 2:
|
||||||
|
out = 5;
|
||||||
|
case 4:
|
||||||
|
out = 10;
|
||||||
|
case 8:
|
||||||
|
out = 21;
|
||||||
|
}
|
||||||
|
return out + ox::is_signed_v<Integer>;
|
||||||
|
}();
|
||||||
|
ox::IString<Cap> out;
|
||||||
|
std::ignore = out.resize(out.cap());
|
||||||
|
ox::CharBuffWriter w(out.data(), out.cap());
|
||||||
|
std::ignore = writeItoa(v, w);
|
||||||
|
std::ignore = out.resize(w.tellp());
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
6
deps/ox/src/ox/std/math.hpp
vendored
6
deps/ox/src/ox/std/math.hpp
vendored
@ -48,11 +48,11 @@ constexpr const T &clamp(const T &v, const T &lo, const T &hi) noexcept requires
|
|||||||
return min(ox::max(v, lo), hi);
|
return min(ox::max(v, lo), hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename I>
|
template<typename I, typename E>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr I pow(I v, int e) noexcept {
|
constexpr I pow(I v, E e) noexcept {
|
||||||
I out = 1;
|
I out = 1;
|
||||||
for (I i = 0; i < e; i++) {
|
for (E i = 0; i < e; ++i) {
|
||||||
out *= v;
|
out *= v;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
14
deps/ox/src/ox/std/maybeview.hpp
vendored
14
deps/ox/src/ox/std/maybeview.hpp
vendored
@ -8,14 +8,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "typetraits.hpp"
|
#if __has_include(<string>)
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
// Maybe StringView. If T is a string type, MaybeType::type/MaybeView_t is a
|
// Maybe StringView. If T is a string type, MaybeType::type/MaybeView_t is a
|
||||||
// StringView. This avoids creating unnecessary Strings when taking a
|
// StringView. This avoids creating unnecessary Strings when taking a
|
||||||
// StringView or C string as a function argument.
|
// StringView or C string as a function argument.
|
||||||
template<typename T, bool isStr = isOxString_v<T>>
|
template<typename T>
|
||||||
struct MaybeView {
|
struct MaybeView {
|
||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
@ -23,4 +26,11 @@ struct MaybeView {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using MaybeView_t = typename MaybeView<T>::type;
|
using MaybeView_t = typename MaybeView<T>::type;
|
||||||
|
|
||||||
|
#if __has_include(<string>)
|
||||||
|
template<typename CharT, typename Traits, typename Allocator>
|
||||||
|
struct MaybeView<std::basic_string<CharT, Traits, Allocator>> {
|
||||||
|
using type = std::basic_string_view<CharT, Traits>;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
2
deps/ox/src/ox/std/memops.hpp
vendored
2
deps/ox/src/ox/std/memops.hpp
vendored
@ -33,7 +33,7 @@ template<typename T1, typename T2>
|
|||||||
constexpr T1 *listcpy(T1 *dest, T2 *src, std::size_t maxLen) noexcept {
|
constexpr T1 *listcpy(T1 *dest, T2 *src, std::size_t maxLen) noexcept {
|
||||||
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
|
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
while (i < maxLen && src[i]) {
|
while (i < maxLen) {
|
||||||
dest[i] = static_cast<T1Type>(src[i]);
|
dest[i] = static_cast<T1Type>(src[i]);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
4
deps/ox/src/ox/std/memory.hpp
vendored
4
deps/ox/src/ox/std/memory.hpp
vendored
@ -51,12 +51,12 @@ namespace ox {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void safeDelete(T *val) requires(sizeof(T) >= 1) {
|
constexpr void safeDelete(T *val) requires(sizeof(T) >= 1) {
|
||||||
delete val;
|
delete val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void safeDeleteArray(T *val) requires(sizeof(T) >= 1) {
|
constexpr void safeDeleteArray(T *val) requires(sizeof(T) >= 1) {
|
||||||
delete[] val;
|
delete[] val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
deps/ox/src/ox/std/serialize.hpp
vendored
7
deps/ox/src/ox/std/serialize.hpp
vendored
@ -19,7 +19,6 @@ namespace ox {
|
|||||||
template<typename PlatSpec>
|
template<typename PlatSpec>
|
||||||
struct VectorMemMap {
|
struct VectorMemMap {
|
||||||
const std::size_t smallVecSize = 0; // not a map value
|
const std::size_t smallVecSize = 0; // not a map value
|
||||||
uint8_t allocator = 0;
|
|
||||||
typename PlatSpec::size_t size = 0;
|
typename PlatSpec::size_t size = 0;
|
||||||
typename PlatSpec::size_t cap = 0;
|
typename PlatSpec::size_t cap = 0;
|
||||||
typename PlatSpec::PtrType items = 0;
|
typename PlatSpec::PtrType items = 0;
|
||||||
@ -34,10 +33,8 @@ constexpr auto sizeOf(const VectorMemMap<PlatSpec> *t) noexcept {
|
|||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
if (t->smallVecSize) {
|
if (t->smallVecSize) {
|
||||||
size += t->smallVecSize;
|
size += t->smallVecSize;
|
||||||
size += padding(size, PlatSpec::alignOf(t->allocator));
|
|
||||||
}
|
|
||||||
size += sizeof(t->allocator);
|
|
||||||
size += padding(size, PlatSpec::alignOf(t->size));
|
size += padding(size, PlatSpec::alignOf(t->size));
|
||||||
|
}
|
||||||
size += sizeof(t->size);
|
size += sizeof(t->size);
|
||||||
size += padding(size, PlatSpec::alignOf(t->cap));
|
size += padding(size, PlatSpec::alignOf(t->cap));
|
||||||
size += sizeof(t->cap);
|
size += sizeof(t->cap);
|
||||||
@ -67,8 +64,6 @@ constexpr ox::Error pad(Writer_c auto &w, const T *v) noexcept {
|
|||||||
template<typename PlatSpec>
|
template<typename PlatSpec>
|
||||||
constexpr ox::Error serialize(Writer_c auto &w, const VectorMemMap<PlatSpec> &vm) noexcept {
|
constexpr ox::Error serialize(Writer_c auto &w, const VectorMemMap<PlatSpec> &vm) noexcept {
|
||||||
oxReturnError(w.write(nullptr, vm.smallVecSize));
|
oxReturnError(w.write(nullptr, vm.smallVecSize));
|
||||||
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.allocator)));
|
|
||||||
oxReturnError(pad<PlatSpec>(w, &vm.size));
|
|
||||||
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.size)));
|
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.size)));
|
||||||
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.cap)));
|
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.cap)));
|
||||||
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.items)));
|
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.items)));
|
||||||
|
249
deps/ox/src/ox/std/smallmap.hpp
vendored
Normal file
249
deps/ox/src/ox/std/smallmap.hpp
vendored
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2024 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "algorithm.hpp"
|
||||||
|
#include "hash.hpp"
|
||||||
|
#include "ignore.hpp"
|
||||||
|
#include "stringview.hpp"
|
||||||
|
#include "strops.hpp"
|
||||||
|
#include "vector.hpp"
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz = 0>
|
||||||
|
class SmallMap {
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_t = K;
|
||||||
|
using value_t = T;
|
||||||
|
struct Pair {
|
||||||
|
K key = {};
|
||||||
|
T value{};
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
using PairVector = Vector<Pair, SmallSz>;
|
||||||
|
PairVector m_pairs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr SmallMap() = default;
|
||||||
|
|
||||||
|
constexpr SmallMap(SmallMap const&other);
|
||||||
|
|
||||||
|
constexpr SmallMap(SmallMap &&other) noexcept;
|
||||||
|
|
||||||
|
constexpr ~SmallMap();
|
||||||
|
|
||||||
|
constexpr bool operator==(SmallMap const&other) const;
|
||||||
|
|
||||||
|
constexpr SmallMap &operator=(SmallMap const&other);
|
||||||
|
|
||||||
|
constexpr SmallMap &operator=(SmallMap &&other) noexcept;
|
||||||
|
|
||||||
|
constexpr T &operator[](MaybeView_t<K> const&key);
|
||||||
|
|
||||||
|
constexpr Result<T*> at(MaybeView_t<K> const&key) noexcept;
|
||||||
|
|
||||||
|
constexpr Result<const T*> at(MaybeView_t<K> const&key) const noexcept;
|
||||||
|
|
||||||
|
constexpr void erase(MaybeView_t<K> const&key);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr bool contains(MaybeView_t<K> const&key) const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr std::size_t size() const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr Vector<K> keys() const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr K const&key(size_t i) const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr T const&value(size_t i) const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr T &value(size_t i) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr Pair const&get(size_t i) const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr Pair &get(size_t i) noexcept;
|
||||||
|
|
||||||
|
constexpr void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename KK>
|
||||||
|
constexpr Pair const&access(PairVector const&pairs, KK const&key, bool &isNew) const;
|
||||||
|
|
||||||
|
template<typename KK>
|
||||||
|
constexpr Pair &access(PairVector &pairs, KK const&key, bool &isNew);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz>::SmallMap(SmallMap<K, T, SmallSz> const&other) {
|
||||||
|
m_pairs = other.m_pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz>::SmallMap(SmallMap<K, T, SmallSz> &&other) noexcept {
|
||||||
|
m_pairs = std::move(other.m_pairs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz>::~SmallMap() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr bool SmallMap<K, T, SmallSz>::operator==(SmallMap const&other) const {
|
||||||
|
return m_pairs == other.m_pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K, T, SmallSz> const&other) {
|
||||||
|
if (this != &other) {
|
||||||
|
clear();
|
||||||
|
m_pairs = other.m_pairs;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K, T, SmallSz> &&other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
clear();
|
||||||
|
m_pairs = std::move(other.m_pairs);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
|
||||||
|
bool isNew{};
|
||||||
|
auto p = &access(m_pairs, k, isNew);
|
||||||
|
if (isNew) {
|
||||||
|
p->key = k;
|
||||||
|
}
|
||||||
|
return p->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept {
|
||||||
|
auto p = access(m_pairs, k);
|
||||||
|
if (!p) {
|
||||||
|
return {nullptr, OxError(1, "value not found for given key")};
|
||||||
|
}
|
||||||
|
return &p->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept {
|
||||||
|
auto p = access(m_pairs, k);
|
||||||
|
if (!p) {
|
||||||
|
return {nullptr, OxError(1, "value not found for given key")};
|
||||||
|
}
|
||||||
|
return &p->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr void SmallMap<K, T, SmallSz>::erase(MaybeView_t<K> const&k) {
|
||||||
|
size_t i{};
|
||||||
|
for (auto const&p : m_pairs) {
|
||||||
|
if (k == p.key) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
std::ignore = m_pairs.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept {
|
||||||
|
return access(m_pairs, k) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr std::size_t SmallMap<K, T, SmallSz>::size() const noexcept {
|
||||||
|
return m_pairs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
|
||||||
|
ox::Vector<K> keys;
|
||||||
|
keys.reserve(m_pairs.size());
|
||||||
|
for (auto const&p : m_pairs) {
|
||||||
|
keys.emplace_back(p.key);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
|
||||||
|
return m_pairs[i].key;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr T const&SmallMap<K, T, SmallSz>::value(size_t i) const noexcept {
|
||||||
|
return m_pairs[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr T &SmallMap<K, T, SmallSz>::value(size_t i) noexcept {
|
||||||
|
return m_pairs[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::get(size_t i) const noexcept {
|
||||||
|
return m_pairs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::get(size_t i) noexcept {
|
||||||
|
return m_pairs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
constexpr void SmallMap<K, T, SmallSz>::clear() {
|
||||||
|
m_pairs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
template<typename KK>
|
||||||
|
constexpr typename SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::access(
|
||||||
|
PairVector const&pairs, KK const&k, bool &isNew) const {
|
||||||
|
for (auto const&p : pairs) {
|
||||||
|
if (p.key == k) {
|
||||||
|
isNew = false;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isNew = true;
|
||||||
|
return pairs.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T, size_t SmallSz>
|
||||||
|
template<typename KK>
|
||||||
|
constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::access(
|
||||||
|
PairVector &pairs, KK const&k, bool &isNew) {
|
||||||
|
for (auto &p : pairs) {
|
||||||
|
if (p.key == k) {
|
||||||
|
isNew = false;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isNew = true;
|
||||||
|
return pairs.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
deps/ox/src/ox/std/span.hpp
vendored
14
deps/ox/src/ox/std/span.hpp
vendored
@ -19,8 +19,8 @@ template<typename T>
|
|||||||
class SpanView {
|
class SpanView {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const T *m_items{};
|
T const*m_items{};
|
||||||
const std::size_t m_size{};
|
std::size_t m_size{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
@ -106,6 +106,16 @@ class SpanView {
|
|||||||
return m_items[i];
|
return m_items[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr SpanView operator+(size_t i) const noexcept {
|
||||||
|
return {m_items + i, m_size - i};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr SpanView operator+=(size_t i) noexcept {
|
||||||
|
m_items += i;
|
||||||
|
m_size -= i;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr T const*data() const noexcept {
|
constexpr T const*data() const noexcept {
|
||||||
return m_items;
|
return m_items;
|
||||||
|
1
deps/ox/src/ox/std/std.hpp
vendored
1
deps/ox/src/ox/std/std.hpp
vendored
@ -39,6 +39,7 @@
|
|||||||
#include "realstd.hpp"
|
#include "realstd.hpp"
|
||||||
#include "serialize.hpp"
|
#include "serialize.hpp"
|
||||||
#include "size.hpp"
|
#include "size.hpp"
|
||||||
|
#include "smallmap.hpp"
|
||||||
#include "stacktrace.hpp"
|
#include "stacktrace.hpp"
|
||||||
#include "stddef.hpp"
|
#include "stddef.hpp"
|
||||||
#include "string.hpp"
|
#include "string.hpp"
|
||||||
|
46
deps/ox/src/ox/std/strconv.hpp
vendored
Normal file
46
deps/ox/src/ox/std/strconv.hpp
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bit.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
#include "math.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "writer.hpp"
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
template<Integer_c Integer>
|
||||||
|
constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept {
|
||||||
|
if (v) {
|
||||||
|
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
|
||||||
|
ox::ResizedInt_t<Integer, 64> val = v;
|
||||||
|
constexpr auto base = 10;
|
||||||
|
auto it = 0;
|
||||||
|
if (val < 0) {
|
||||||
|
oxReturnError(writer.put('-'));
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
while (mod) {
|
||||||
|
auto digit = val / mod;
|
||||||
|
val %= mod;
|
||||||
|
mod /= base;
|
||||||
|
if (it || digit) {
|
||||||
|
ox::ResizedInt_t<Integer, 64> start = '0';
|
||||||
|
if (digit >= 10) {
|
||||||
|
start = 'a';
|
||||||
|
digit -= 10;
|
||||||
|
}
|
||||||
|
oxReturnError(writer.put(static_cast<char>(start + digit)));
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 0 is a special case
|
||||||
|
oxReturnError(writer.put('0'));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "istring.hpp"
|
53
deps/ox/src/ox/std/string.hpp
vendored
53
deps/ox/src/ox/std/string.hpp
vendored
@ -16,6 +16,7 @@
|
|||||||
#include "ignore.hpp"
|
#include "ignore.hpp"
|
||||||
#include "memops.hpp"
|
#include "memops.hpp"
|
||||||
#include "serialize.hpp"
|
#include "serialize.hpp"
|
||||||
|
#include "strconv.hpp"
|
||||||
#include "stringliteral.hpp"
|
#include "stringliteral.hpp"
|
||||||
#include "stringview.hpp"
|
#include "stringview.hpp"
|
||||||
#include "strops.hpp"
|
#include "strops.hpp"
|
||||||
@ -23,6 +24,9 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
|
template<typename Integer>
|
||||||
|
constexpr ox::IString<21> itoa(Integer v) noexcept;
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
class BasicString {
|
class BasicString {
|
||||||
private:
|
private:
|
||||||
@ -178,12 +182,20 @@ class BasicString {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr Error append(ox::StringView sv) noexcept {
|
||||||
|
return append(sv.data(), sv.len());
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr BasicString substr(std::size_t pos) const noexcept;
|
constexpr BasicString substr(std::size_t pos) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr BasicString substr(std::size_t begin, std::size_t end) const noexcept;
|
constexpr BasicString substr(std::size_t begin, std::size_t end) const noexcept;
|
||||||
|
|
||||||
|
constexpr void resize(size_t sz) noexcept {
|
||||||
|
m_buff.resize(sz);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr const char *data() const noexcept {
|
constexpr const char *data() const noexcept {
|
||||||
return m_buff.data();
|
return m_buff.data();
|
||||||
@ -323,17 +335,13 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
|
|||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
|
||||||
ox::Array<char, 65> str{};
|
set(ox::itoa(i));
|
||||||
ox::itoa(i, str.data());
|
|
||||||
set(str.data());
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
|
||||||
ox::Array<char, 65> str{};
|
set(ox::itoa(i));
|
||||||
ox::itoa(i, str.data());
|
|
||||||
set(str.data());
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,9 +387,8 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
|
|||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
|
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
|
||||||
char str[65] = {};
|
auto const str = ox::itoa(i);
|
||||||
ox::itoa(i, str);
|
return this->operator+=(str.c_str());
|
||||||
return this->operator+=(str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
@ -423,8 +430,7 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
|
|||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
|
||||||
char str[65] = {};
|
auto const str = ox::itoa(i);
|
||||||
ox::itoa(i, str);
|
|
||||||
return *this + str;
|
return *this + str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,7 +515,7 @@ constexpr char &BasicString<SmallStringSize_v>::operator[](std::size_t i) noexce
|
|||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t pos) const noexcept {
|
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t pos) const noexcept {
|
||||||
return BasicString(m_buff.data() + pos, m_buff.size() - pos);
|
return BasicString(m_buff.data() + pos, m_buff.size() - pos - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
@ -525,26 +531,12 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(
|
|||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
|
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
|
||||||
std::size_t i;
|
return m_buff.size();
|
||||||
for (i = 0; i < m_buff.size() && m_buff[i]; ++i);
|
|
||||||
return i + 1; // add one for null terminator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
|
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
|
||||||
std::size_t length = 0;
|
return m_buff.size() - 1;
|
||||||
for (const auto c : m_buff) {
|
|
||||||
const auto b = static_cast<uint8_t>(c);
|
|
||||||
if (b) {
|
|
||||||
// normal ASCII character or start of UTF-8 character
|
|
||||||
if ((b & 128) == 0 || (b & (256 << 6)) == (256 << 6)) {
|
|
||||||
++length;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
@ -589,4 +581,9 @@ constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
|
|||||||
return alignOf<PlatSpec>(&v);
|
return alignOf<PlatSpec>(&v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t sz>
|
||||||
|
struct MaybeView<ox::BasicString<sz>> {
|
||||||
|
using type = ox::StringView;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
5
deps/ox/src/ox/std/stringliteral.hpp
vendored
5
deps/ox/src/ox/std/stringliteral.hpp
vendored
@ -32,10 +32,9 @@ class StringLiteral: public detail::BaseStringView {
|
|||||||
|
|
||||||
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
|
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
|
||||||
|
|
||||||
constexpr explicit StringLiteral(char const *str) noexcept: StringLiteral(str, ox::strlen(str)) {
|
constexpr explicit StringLiteral(char const *str) noexcept: StringLiteral(str, ox::strlen(str)) {}
|
||||||
}
|
|
||||||
|
|
||||||
constexpr auto &operator=(StringLiteral const&other) noexcept {
|
constexpr StringLiteral &operator=(StringLiteral const&other) noexcept {
|
||||||
if (&other != this) {
|
if (&other != this) {
|
||||||
set(other.data(), other.len());
|
set(other.data(), other.len());
|
||||||
}
|
}
|
||||||
|
5
deps/ox/src/ox/std/stringview.hpp
vendored
5
deps/ox/src/ox/std/stringview.hpp
vendored
@ -98,11 +98,6 @@ constexpr auto toStdStringView(CRStringView sv) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct MaybeView<T, true> {
|
|
||||||
using type = ox::StringView;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr ox::Result<int> atoi(ox::CRStringView str) noexcept {
|
constexpr ox::Result<int> atoi(ox::CRStringView str) noexcept {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int multiplier = 1;
|
int multiplier = 1;
|
||||||
|
7
deps/ox/src/ox/std/strongint.hpp
vendored
7
deps/ox/src/ox/std/strongint.hpp
vendored
@ -34,7 +34,7 @@ class Integer: public Base {
|
|||||||
|
|
||||||
constexpr Integer(const Integer<T, Base> &i) noexcept;
|
constexpr Integer(const Integer<T, Base> &i) noexcept;
|
||||||
|
|
||||||
constexpr Integer<T, Base> operator=(Integer<T, Base> i) noexcept;
|
constexpr Integer<T, Base> &operator=(Integer<T, Base> i) noexcept;
|
||||||
|
|
||||||
constexpr Integer<T, Base> operator==(Integer<T, Base> i) const noexcept;
|
constexpr Integer<T, Base> operator==(Integer<T, Base> i) const noexcept;
|
||||||
|
|
||||||
@ -118,10 +118,9 @@ constexpr Integer<T, Base>::Integer(const Integer<T, Base> &i) noexcept: Base(i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, class Base>
|
template<typename T, class Base>
|
||||||
constexpr Integer<T, Base> Integer<T, Base>::operator=(Integer<T, Base> i) noexcept {
|
constexpr Integer<T, Base> &Integer<T, Base>::operator=(Integer<T, Base> i) noexcept {
|
||||||
// needed in case T has nodiscard
|
// needed in case T has nodiscard
|
||||||
constexpr auto ignore = [](Base) {};
|
Base::operator=(i);
|
||||||
ignore(Base::operator=(i));
|
|
||||||
m_i = i.m_i;
|
m_i = i.m_i;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
45
deps/ox/src/ox/std/strops.hpp
vendored
45
deps/ox/src/ox/std/strops.hpp
vendored
@ -14,56 +14,21 @@
|
|||||||
#include "stringview.hpp"
|
#include "stringview.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include "vector.hpp"
|
#include "vector.hpp"
|
||||||
#include "writer.hpp"
|
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
template<OxString_c Str>
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr Str substr(Str const&str, std::size_t pos) noexcept {
|
constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept {
|
||||||
if (str.len() >= pos) {
|
if (str.len() >= pos) {
|
||||||
return Str(str.data() + pos, str.len() - pos);
|
return {str.data() + pos, str.len() - pos};
|
||||||
}
|
}
|
||||||
return Str();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<OxString_c Str>
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr ox::StringView substr(Str const&str, std::size_t start, std::size_t end) noexcept {
|
constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept {
|
||||||
if (str.len() >= start && end >= start) {
|
if (str.len() >= start && end >= start) {
|
||||||
return Str(str.data() + start, end - start);
|
return {str.data() + start, end - start};
|
||||||
}
|
|
||||||
return Str();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Integer>
|
|
||||||
constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept {
|
|
||||||
if (v) {
|
|
||||||
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
|
|
||||||
ox::ResizedInt_t<Integer, 64> val = v;
|
|
||||||
constexpr auto base = 10;
|
|
||||||
auto it = 0;
|
|
||||||
if (val < 0) {
|
|
||||||
oxReturnError(writer.put('-'));
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
while (mod) {
|
|
||||||
auto digit = val / mod;
|
|
||||||
val %= mod;
|
|
||||||
mod /= base;
|
|
||||||
if (it || digit) {
|
|
||||||
ox::ResizedInt_t<Integer, 64> start = '0';
|
|
||||||
if (digit >= 10) {
|
|
||||||
start = 'a';
|
|
||||||
digit -= 10;
|
|
||||||
}
|
|
||||||
oxReturnError(writer.put(static_cast<char>(start + digit)));
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 0 is a special case
|
|
||||||
oxReturnError(writer.put('0'));
|
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
4
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
4
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
@ -12,8 +12,10 @@ add_test("[ox/std] ox_memcmp HIJKLMN != ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTOR
|
|||||||
add_test("[ox/std] ox_memcmp ABCDEFG == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFG == ABCDEFG")
|
add_test("[ox/std] ox_memcmp ABCDEFG == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFG == ABCDEFG")
|
||||||
add_test("[ox/std] ox_memcmp ABCDEFGHI == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFGHI == ABCDEFG")
|
add_test("[ox/std] ox_memcmp ABCDEFGHI == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFGHI == ABCDEFG")
|
||||||
add_test("[ox/std] itoa" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "itoa")
|
add_test("[ox/std] itoa" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "itoa")
|
||||||
add_test("[ox/std] BString" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "BString")
|
add_test("[ox/std] IString" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "IString")
|
||||||
add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
|
add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
|
||||||
|
add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
|
||||||
|
add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
|
||||||
add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
|
add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
|
||||||
add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
|
add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
|
||||||
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
|
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
|
||||||
|
177
deps/ox/src/ox/std/test/tests.cpp
vendored
177
deps/ox/src/ox/std/test/tests.cpp
vendored
@ -6,12 +6,112 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if __has_include(<chrono>)
|
||||||
|
#include<chrono>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ox/std/def.hpp>
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <ox/std/uuid.hpp>
|
#include <ox/std/uuid.hpp>
|
||||||
#include <ox/std/std.hpp>
|
#include <ox/std/std.hpp>
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static uint64_t nowMs() {
|
||||||
|
#if __has_include(<chrono>)
|
||||||
|
using namespace std::chrono;
|
||||||
|
return static_cast<uint64_t>(
|
||||||
|
duration_cast<milliseconds>(
|
||||||
|
system_clock::now().time_since_epoch()).count());
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Map = ox::SmallMap<ox::String, ox::UUID>>
|
||||||
|
uint64_t timeMapStrToUuid(int elemCnt, int lookups, uint64_t seed = 4321) noexcept {
|
||||||
|
ox::UUID::seedGenerator({1234, seed});
|
||||||
|
Map map;
|
||||||
|
// setup test map
|
||||||
|
for (int i = 0; i < elemCnt; ++i) {
|
||||||
|
auto const uuid = ox::UUID::generate().unwrap();
|
||||||
|
map[uuid.toString()] = uuid;
|
||||||
|
}
|
||||||
|
auto const keys = map.keys();
|
||||||
|
ox::Random rand;
|
||||||
|
// start
|
||||||
|
auto const startTime = nowMs();
|
||||||
|
for (int i = 0; i < lookups; ++i) {
|
||||||
|
auto const&k = keys[rand.gen() % keys.size()];
|
||||||
|
map[k];
|
||||||
|
oxExpect(map[k], ox::UUID::fromString(k).unwrap());
|
||||||
|
}
|
||||||
|
return nowMs() - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Map = ox::SmallMap<ox::UUID, ox::String>>
|
||||||
|
uint64_t timeMapUuidToStr(int elemCnt, int lookups, uint64_t seed = 4321) noexcept {
|
||||||
|
ox::UUID::seedGenerator({1234, seed});
|
||||||
|
Map map;
|
||||||
|
// setup test map
|
||||||
|
for (int i = 0; i < elemCnt; ++i) {
|
||||||
|
auto const uuid = ox::UUID::generate().unwrap();
|
||||||
|
map[uuid] = uuid.toString();
|
||||||
|
}
|
||||||
|
auto const keys = map.keys();
|
||||||
|
ox::Random rand;
|
||||||
|
// start
|
||||||
|
auto const startTime = nowMs();
|
||||||
|
for (int i = 0; i < lookups; ++i) {
|
||||||
|
auto const&k = keys[rand.gen() % keys.size()];
|
||||||
|
oxExpect(map[k], k.toString());
|
||||||
|
}
|
||||||
|
return nowMs() - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ox::Error compareMaps(int lookupCnt = 1'000'000) {
|
||||||
|
auto const seed = nowMs();
|
||||||
|
uint64_t hashTime{};
|
||||||
|
uint64_t smallTime{};
|
||||||
|
int elemCnt = 1;
|
||||||
|
oxOut("UUIDStr to UUID:\n\n");
|
||||||
|
while (hashTime >= smallTime) {
|
||||||
|
smallTime = timeMapStrToUuid<ox::SmallMap<ox::UUIDStr, ox::UUID>>(elemCnt, lookupCnt, seed);
|
||||||
|
hashTime = timeMapStrToUuid<ox::HashMap<ox::UUIDStr, ox::UUID>>(elemCnt, lookupCnt, seed);
|
||||||
|
oxOutf(
|
||||||
|
"UUIDStr to UUID: elemCnt: {}, lookupCnt: {} - hash map time: {}ms, small map time: {}ms\n",
|
||||||
|
elemCnt, lookupCnt, hashTime, smallTime);
|
||||||
|
++elemCnt;
|
||||||
|
}
|
||||||
|
oxOut("\n\nString to UUID:\n\n");
|
||||||
|
hashTime = 0;
|
||||||
|
smallTime = 0;
|
||||||
|
elemCnt = 1;
|
||||||
|
while (hashTime >= smallTime) {
|
||||||
|
smallTime = timeMapStrToUuid<ox::SmallMap<ox::String, ox::UUID>>(elemCnt, lookupCnt, seed);
|
||||||
|
hashTime = timeMapStrToUuid<ox::HashMap<ox::String, ox::UUID>>(elemCnt, lookupCnt, seed);
|
||||||
|
oxOutf(
|
||||||
|
"String to UUID: elemCnt: {}, lookupCnt: {} - hash map time: {}ms, small map time: {}ms\n",
|
||||||
|
elemCnt, lookupCnt, hashTime, smallTime);
|
||||||
|
++elemCnt;
|
||||||
|
}
|
||||||
|
oxOut("\n\nUUID to UUIDStr:\n\n");
|
||||||
|
hashTime = 0;
|
||||||
|
smallTime = 0;
|
||||||
|
elemCnt = 1;
|
||||||
|
while (hashTime >= smallTime) {
|
||||||
|
smallTime = timeMapUuidToStr<ox::SmallMap<ox::UUID, ox::UUIDStr>>(elemCnt, lookupCnt, seed);
|
||||||
|
hashTime = timeMapUuidToStr<ox::HashMap<ox::UUID, ox::UUIDStr>>(elemCnt, lookupCnt, seed);
|
||||||
|
oxOutf(
|
||||||
|
"UUID to UUIDStr: elemCnt: {}, lookupCnt: {} - hash map time: {}ms, small map time: {}ms\n",
|
||||||
|
elemCnt, lookupCnt, hashTime, smallTime);
|
||||||
|
++elemCnt;
|
||||||
|
}
|
||||||
|
oxOut("\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
static std::map<ox::StringView, ox::Error(*)()> tests = {
|
static std::map<ox::StringView, ox::Error(*)()> tests = {
|
||||||
{
|
{
|
||||||
"malloc",
|
"malloc",
|
||||||
@ -22,6 +122,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
auto a2 = static_cast<char*>(ox::heapmgr::malloc(5));
|
auto a2 = static_cast<char*>(ox::heapmgr::malloc(5));
|
||||||
oxAssert(a1 >= buff.front().unwrap() && a1 < buff.back().unwrap(), "malloc is broken");
|
oxAssert(a1 >= buff.front().unwrap() && a1 < buff.back().unwrap(), "malloc is broken");
|
||||||
oxAssert(a2 >= buff.front().unwrap() && a2 < buff.back().unwrap() && a2 > a1 + 5, "malloc is broken");
|
oxAssert(a2 >= buff.front().unwrap() && a2 < buff.back().unwrap() && a2 > a1 + 5, "malloc is broken");
|
||||||
|
ox::heapmgr::free(a1);
|
||||||
|
ox::heapmgr::free(a2);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -66,14 +168,14 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"BString",
|
"IString",
|
||||||
[]() {
|
[]() {
|
||||||
ox::IString<5> s;
|
ox::IString<5> s;
|
||||||
s += "A";
|
oxReturnError(s.append("A"));
|
||||||
s += "B";
|
oxReturnError(s.append("B"));
|
||||||
s += 9;
|
oxReturnError(s.append("9"));
|
||||||
s += "C";
|
oxReturnError(s.append("C"));
|
||||||
oxAssert(s == "AB9C", "BString append broken");
|
oxAssert(s == "AB9C", "IString append broken");
|
||||||
s = "asdf";
|
s = "asdf";
|
||||||
oxAssert(s == "asdf", "String assign broken");
|
oxAssert(s == "asdf", "String assign broken");
|
||||||
oxAssert(s != "aoeu", "String assign broken");
|
oxAssert(s != "aoeu", "String assign broken");
|
||||||
@ -108,7 +210,10 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
oxAssert(ox::StringView("Write") != ox::String(""), "String / StringView comparison broken");
|
oxAssert(ox::StringView("Write") != ox::String(""), "String / StringView comparison broken");
|
||||||
oxAssert(ox::String("Write") != ox::StringView(""), "String / StringView comparison broken");
|
oxAssert(ox::String("Write") != ox::StringView(""), "String / StringView comparison broken");
|
||||||
oxAssert(ox::String("Write") == ox::StringView("Write"), "String / StringView comparison broken");
|
oxAssert(ox::String("Write") == ox::StringView("Write"), "String / StringView comparison broken");
|
||||||
oxAssert(ox::String(ox::StringView("Write")) == ox::StringView("Write"), "String / StringView comparison broken");
|
oxExpect(ox::String("asdf").substr(1, 3), "sd");
|
||||||
|
oxAssert(
|
||||||
|
ox::String(ox::StringView("Write")) == ox::StringView("Write"),
|
||||||
|
"String / StringView comparison broken");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -118,7 +223,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
ox::Vector<int> v;
|
ox::Vector<int> v;
|
||||||
oxAssert(v.size() == 0, "Initial Vector size not 0");
|
oxAssert(v.size() == 0, "Initial Vector size not 0");
|
||||||
oxAssert(v.empty(), "Vector::empty() is broken");
|
oxAssert(v.empty(), "Vector::empty() is broken");
|
||||||
auto insertTest = [&v](int val, [[maybe_unused]] std::size_t size) {
|
auto insertTest = [&v](int val, std::size_t size) {
|
||||||
v.push_back(val);
|
v.push_back(val);
|
||||||
oxReturnError(OxError(v.size() != size, "Vector size incorrect"));
|
oxReturnError(OxError(v.size() != size, "Vector size incorrect"));
|
||||||
oxReturnError(OxError(v[v.size() - 1] != val, "Vector value wrong"));
|
oxReturnError(OxError(v[v.size() - 1] != val, "Vector value wrong"));
|
||||||
@ -130,10 +235,38 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"SmallMap",
|
||||||
|
[] {
|
||||||
|
ox::SmallMap<ox::String, ox::String> map;
|
||||||
|
map["asdf"] = "aoeu";
|
||||||
|
oxExpect(map["asdf"], "aoeu");
|
||||||
|
oxExpect(map.size(), 1u);
|
||||||
|
oxExpect(map["aoeu"], "");
|
||||||
|
oxExpect(map.size(), 2u);
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SmallMap2",
|
||||||
|
[] {
|
||||||
|
ox::SmallMap<ox::String, int> si;
|
||||||
|
si["asdf"] = 42;
|
||||||
|
si["aoeu"] = 100;
|
||||||
|
oxAssert(si["asdf"] == 42, "asdf != 42");
|
||||||
|
oxAssert(si["aoeu"] == 100, "aoeu != 100");
|
||||||
|
ox::SmallMap<int, int> ii;
|
||||||
|
ii[4] = 42;
|
||||||
|
ii[5] = 100;
|
||||||
|
oxAssert(ii[4] == 42, "4 != 42");
|
||||||
|
oxAssert(ii[5] == 100, "5 != 100");
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"HashMap",
|
"HashMap",
|
||||||
[] {
|
[] {
|
||||||
ox::HashMap<const char*, int> si;
|
ox::HashMap<ox::String, int> si;
|
||||||
si["asdf"] = 42;
|
si["asdf"] = 42;
|
||||||
si["aoeu"] = 100;
|
si["aoeu"] = 100;
|
||||||
oxAssert(si["asdf"] == 42, "asdf != 42");
|
oxAssert(si["asdf"] == 42, "asdf != 42");
|
||||||
@ -146,12 +279,36 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"TimeSmallMapMillion",
|
||||||
|
[] {
|
||||||
|
timeMapStrToUuid<ox::SmallMap<ox::String, ox::UUID>>(1'000, 1'000'000);
|
||||||
|
return ox::Error{};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TimeHashMapMillion",
|
||||||
|
[] {
|
||||||
|
timeMapStrToUuid<ox::HashMap<ox::String, ox::UUID>>(1'000, 1'000'000);
|
||||||
|
return ox::Error{};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"CompareMaps",
|
||||||
|
[] {
|
||||||
|
return compareMaps();
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Serialize-Int",
|
"Serialize-Int",
|
||||||
[] {
|
[] {
|
||||||
using BA = ox::Array<char, 4>;
|
using BA = ox::Array<char, 4>;
|
||||||
const auto actual = ox::serialize<uint32_t>(256).unwrap();
|
const auto actual = ox::serialize<uint32_t>(256).unwrap();
|
||||||
oxOutf("[{}, {}, {}, {}]", static_cast<int>(actual[0]), static_cast<int>(actual[1]), static_cast<int>(actual[2]), static_cast<int>(actual[3]));
|
oxOutf("[{}, {}, {}, {}]",
|
||||||
|
static_cast<int>(actual[0]),
|
||||||
|
static_cast<int>(actual[1]),
|
||||||
|
static_cast<int>(actual[2]),
|
||||||
|
static_cast<int>(actual[3]));
|
||||||
oxExpect(ox::serialize<int32_t>(4).unwrap(), BA({4, 0, 0, 0}));
|
oxExpect(ox::serialize<int32_t>(4).unwrap(), BA({4, 0, 0, 0}));
|
||||||
oxExpect(ox::serialize<int32_t>(256).unwrap(), BA({0, 1, 0, 0}));
|
oxExpect(ox::serialize<int32_t>(256).unwrap(), BA({0, 1, 0, 0}));
|
||||||
oxExpect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));
|
oxExpect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));
|
||||||
|
31
deps/ox/src/ox/std/utility.hpp
vendored
31
deps/ox/src/ox/std/utility.hpp
vendored
@ -8,7 +8,27 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if __has_include(<utility>)
|
||||||
|
#include <utility>
|
||||||
#include "typetraits.hpp"
|
#include "typetraits.hpp"
|
||||||
|
#else
|
||||||
|
#include "typetraits.hpp"
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr ox::remove_reference_t<T> &&move(T &&t) noexcept {
|
||||||
|
return static_cast<ox::remove_reference_t<T>&&>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr void swap(T &a, T &b) noexcept {
|
||||||
|
auto temp = std::move(a);
|
||||||
|
a = std::move(b);
|
||||||
|
b = std::move(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
@ -30,14 +50,3 @@ constexpr T &&forward(remove_reference_t<T> &&t) noexcept {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if __has_include(<utility>)
|
|
||||||
#include <utility>
|
|
||||||
#else
|
|
||||||
namespace std {
|
|
||||||
template<typename T>
|
|
||||||
constexpr typename ox::remove_reference<T>::type &&move(T &&t) noexcept {
|
|
||||||
return static_cast<typename ox::remove_reference<T>::type&&>(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
45
deps/ox/src/ox/std/uuid.hpp
vendored
45
deps/ox/src/ox/std/uuid.hpp
vendored
@ -8,12 +8,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "array.hpp"
|
#include "bit.hpp"
|
||||||
|
#include "ignore.hpp"
|
||||||
#include "istring.hpp"
|
#include "istring.hpp"
|
||||||
#include "buffer.hpp"
|
#include "buffer.hpp"
|
||||||
|
#include "hash.hpp"
|
||||||
#include "random.hpp"
|
#include "random.hpp"
|
||||||
#include "ranges.hpp"
|
#include "ranges.hpp"
|
||||||
#include "stringview.hpp"
|
#include "stringview.hpp"
|
||||||
|
#include "strops.hpp"
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
@ -80,7 +83,8 @@ constexpr ox::IString<2> toHex(uint8_t v) noexcept {
|
|||||||
'e',
|
'e',
|
||||||
'f',
|
'f',
|
||||||
};
|
};
|
||||||
ox::Array<char, 3> out;
|
ox::IString<2> out;
|
||||||
|
std::ignore = out.resize(2);
|
||||||
out[0] = valMap[static_cast<unsigned>((v & 0xf0) / 16)];
|
out[0] = valMap[static_cast<unsigned>((v & 0xf0) / 16)];
|
||||||
out[1] = valMap[static_cast<unsigned>(v & 0x0f)];
|
out[1] = valMap[static_cast<unsigned>(v & 0x0f)];
|
||||||
out[2] = 0;
|
out[2] = 0;
|
||||||
@ -103,7 +107,7 @@ class UUID {
|
|||||||
static ox::Result<UUID> generate() noexcept;
|
static ox::Result<UUID> generate() noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr auto value() const noexcept {
|
constexpr auto const&value() const noexcept {
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,8 +120,8 @@ class UUID {
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
constexpr uint64_t zero = 0;
|
constexpr uint64_t zero = 0;
|
||||||
return ox::memcmp(&zero, m_value.data() + 0, 8) == 0
|
return memcmp(&zero, m_value.data() + 0, 8) == 0
|
||||||
&& ox::memcmp(&zero, m_value.data() + 8, 8) == 0;
|
&& memcmp(&zero, m_value.data() + 8, 8) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,6 +148,14 @@ class UUID {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(UUID const&o) const noexcept {
|
||||||
|
return m_value == o.m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(UUID const&o) const noexcept {
|
||||||
|
return !operator==(o);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr ox::Error toString(Writer_c auto &writer) const noexcept {
|
constexpr ox::Error toString(Writer_c auto &writer) const noexcept {
|
||||||
auto valueI = 0u;
|
auto valueI = 0u;
|
||||||
@ -174,13 +186,32 @@ class UUID {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr UUIDStr toString() const noexcept {
|
constexpr UUIDStr toString() const noexcept {
|
||||||
UUIDStr out;
|
UUIDStr out;
|
||||||
ox::CharBuffWriter bw(out.data(), out.cap());
|
std::ignore = out.resize(UUIDStr::cap());
|
||||||
|
ox::CharBuffWriter bw(out.data(), UUIDStr::cap());
|
||||||
std::ignore = toString(bw);
|
std::ignore = toString(bw);
|
||||||
out[out.cap()] = 0;
|
out[UUIDStr::cap()] = 0;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<ox::UUID> {
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr size_t operator()(ox::UUID v) const noexcept {
|
||||||
|
size_t out{};
|
||||||
|
if (std::is_constant_evaluated()) {
|
||||||
|
for (auto i = 0u; i < sizeof(out); ++i) {
|
||||||
|
out |= static_cast<size_t>(v.value()[i]) << (i * 8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(&out, &v, sizeof(out));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept {
|
constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept {
|
||||||
oxReturnError(io->template setTypeInfo<UUID>());
|
oxReturnError(io->template setTypeInfo<UUID>());
|
||||||
|
58
deps/ox/src/ox/std/vector.hpp
vendored
58
deps/ox/src/ox/std/vector.hpp
vendored
@ -30,7 +30,6 @@ struct VectorAllocator {
|
|||||||
static_assert(alignof(AllocAlias<T>) == alignof(T));
|
static_assert(alignof(AllocAlias<T>) == alignof(T));
|
||||||
private:
|
private:
|
||||||
ox::Array<AllocAlias<T>, Size> m_data = {};
|
ox::Array<AllocAlias<T>, Size> m_data = {};
|
||||||
Allocator m_allocator;
|
|
||||||
protected:
|
protected:
|
||||||
constexpr VectorAllocator() noexcept = default;
|
constexpr VectorAllocator() noexcept = default;
|
||||||
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
|
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
|
||||||
@ -39,7 +38,7 @@ struct VectorAllocator {
|
|||||||
constexpr void allocate(T **items, std::size_t cap) noexcept {
|
constexpr void allocate(T **items, std::size_t cap) noexcept {
|
||||||
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
|
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
|
||||||
if (std::is_constant_evaluated() || cap > Size) {
|
if (std::is_constant_evaluated() || cap > Size) {
|
||||||
*items = m_allocator.allocate(cap);
|
*items = Allocator{}.allocate(cap);
|
||||||
} else {
|
} else {
|
||||||
*items = reinterpret_cast<T*>(m_data.data());
|
*items = reinterpret_cast<T*>(m_data.data());
|
||||||
}
|
}
|
||||||
@ -86,8 +85,10 @@ struct VectorAllocator {
|
|||||||
constexpr void deallocate(T *items, std::size_t cap) noexcept {
|
constexpr void deallocate(T *items, std::size_t cap) noexcept {
|
||||||
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
|
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
|
||||||
if (std::is_constant_evaluated()) {
|
if (std::is_constant_evaluated()) {
|
||||||
|
Allocator{}.deallocate(items, cap);
|
||||||
|
} else {
|
||||||
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
|
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
|
||||||
m_allocator.deallocate(items, cap);
|
Allocator{}.deallocate(items, cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,15 +97,13 @@ struct VectorAllocator {
|
|||||||
|
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct VectorAllocator<T, Allocator, 0> {
|
struct VectorAllocator<T, Allocator, 0> {
|
||||||
private:
|
|
||||||
Allocator m_allocator;
|
|
||||||
protected:
|
protected:
|
||||||
constexpr VectorAllocator() noexcept = default;
|
constexpr VectorAllocator() noexcept = default;
|
||||||
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
|
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
|
||||||
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
|
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
|
||||||
|
|
||||||
constexpr void allocate(T **items, std::size_t cap) noexcept {
|
constexpr void allocate(T **items, std::size_t cap) noexcept {
|
||||||
*items = m_allocator.allocate(cap);
|
*items = Allocator{}.allocate(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
@ -121,7 +120,7 @@ struct VectorAllocator<T, Allocator, 0> {
|
|||||||
|
|
||||||
constexpr void deallocate(T *items, std::size_t cap) noexcept {
|
constexpr void deallocate(T *items, std::size_t cap) noexcept {
|
||||||
if (items) {
|
if (items) {
|
||||||
m_allocator.deallocate(items, cap);
|
Allocator{}.deallocate(items, cap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,12 +268,12 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr bool contains(MaybeView_t<T> const&) const noexcept(useNoexcept);
|
constexpr bool contains(MaybeView_t<T> const&) const noexcept;
|
||||||
|
|
||||||
constexpr iterator<T&, T*, false> insert(
|
constexpr iterator<T&, T*, false> insert(
|
||||||
std::size_t pos, std::size_t cnt, MaybeView_t<T> const&val) noexcept(useNoexcept);
|
std::size_t pos, std::size_t cnt, T val) noexcept(useNoexcept);
|
||||||
|
|
||||||
constexpr iterator<T&, T*, false> insert(std::size_t pos, MaybeView_t<T> const&val) noexcept(useNoexcept);
|
constexpr iterator<T&, T*, false> insert(std::size_t pos, T val) noexcept(useNoexcept);
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept);
|
constexpr iterator<T&, T*, false> emplace(std::size_t pos, Args&&... args) noexcept(useNoexcept);
|
||||||
@ -282,9 +281,7 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
|
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
|
||||||
|
|
||||||
constexpr void push_back(T &&item) noexcept(useNoexcept);
|
constexpr void push_back(T item) noexcept(useNoexcept);
|
||||||
|
|
||||||
constexpr void push_back(MaybeView_t<T> const&item) noexcept(useNoexcept);
|
|
||||||
|
|
||||||
constexpr void pop_back() noexcept(useNoexcept);
|
constexpr void pop_back() noexcept(useNoexcept);
|
||||||
|
|
||||||
@ -522,8 +519,8 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
||||||
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept(useNoexcept) {
|
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
|
||||||
for (std::size_t i = 0; i < m_size; i++) {
|
for (std::size_t i = 0; i < m_size; ++i) {
|
||||||
if (m_items[i] == v) {
|
if (m_items[i] == v) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -534,14 +531,14 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> co
|
|||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
||||||
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
|
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
|
||||||
Vector<T, SmallVectorSize, Allocator>::insert(
|
Vector<T, SmallVectorSize, Allocator>::insert(
|
||||||
std::size_t pos, std::size_t cnt, MaybeView_t<T> const&val) noexcept(useNoexcept) {
|
std::size_t pos, std::size_t cnt, T val) noexcept(useNoexcept) {
|
||||||
if (m_size + cnt > m_cap) {
|
if (m_size + cnt > m_cap) {
|
||||||
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
|
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
|
||||||
if (pos < m_size) {
|
if (pos < m_size) {
|
||||||
m_items[pos] = val;
|
m_items[pos] = std::move(val);
|
||||||
} else {
|
} else {
|
||||||
for (auto i = 0u; i < cnt; ++i) {
|
for (auto i = 0u; i < cnt; ++i) {
|
||||||
std::construct_at(&m_items[pos + i], val);
|
std::construct_at(&m_items[pos + i], m_items[pos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -549,10 +546,10 @@ Vector<T, SmallVectorSize, Allocator>::insert(
|
|||||||
for (auto i = m_size + cnt - 1; i > pos; --i) {
|
for (auto i = m_size + cnt - 1; i > pos; --i) {
|
||||||
std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
|
std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
|
||||||
}
|
}
|
||||||
m_items[pos] = val;
|
m_items[pos] = std::move(val);
|
||||||
} else {
|
} else {
|
||||||
for (auto i = 0u; i < cnt; ++i) {
|
for (auto i = 0u; i < cnt; ++i) {
|
||||||
std::construct_at(&m_items[pos + i], val);
|
std::construct_at(&m_items[pos + i], m_items[pos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,22 +559,22 @@ Vector<T, SmallVectorSize, Allocator>::insert(
|
|||||||
|
|
||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
||||||
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
|
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
|
||||||
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, MaybeView_t<T> const&val) noexcept(useNoexcept) {
|
Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, T val) noexcept(useNoexcept) {
|
||||||
if (m_size == m_cap) {
|
if (m_size == m_cap) {
|
||||||
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
|
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
|
||||||
if (pos < m_size) {
|
if (pos < m_size) {
|
||||||
m_items[pos] = val;
|
m_items[pos] = std::move(val);
|
||||||
} else {
|
} else {
|
||||||
std::construct_at(&m_items[pos], val);
|
std::construct_at(&m_items[pos], m_items[pos]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pos < m_size) {
|
if (pos < m_size) {
|
||||||
for (auto i = m_size; i > pos; --i) {
|
for (auto i = m_size; i > pos; --i) {
|
||||||
std::construct_at(&m_items[i], std::move(m_items[i - 1]));
|
std::construct_at(&m_items[i], std::move(m_items[i - 1]));
|
||||||
}
|
}
|
||||||
m_items[pos] = val;
|
m_items[pos] = std::move(val);
|
||||||
} else {
|
} else {
|
||||||
std::construct_at(&m_items[pos], val);
|
std::construct_at(&m_items[pos], m_items[pos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++m_size;
|
++m_size;
|
||||||
@ -619,7 +616,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
||||||
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
|
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
|
||||||
if (m_size == m_cap) {
|
if (m_size == m_cap) {
|
||||||
reserve(m_cap ? m_cap * 2 : initialCap);
|
reserve(m_cap ? m_cap * 2 : initialCap);
|
||||||
}
|
}
|
||||||
@ -627,15 +624,6 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexce
|
|||||||
++m_size;
|
++m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
|
||||||
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(MaybeView_t<T> const&item) noexcept(useNoexcept) {
|
|
||||||
if (m_size == m_cap) {
|
|
||||||
reserve(m_cap ? m_cap * 2 : initialCap);
|
|
||||||
}
|
|
||||||
std::construct_at(&m_items[m_size], item);
|
|
||||||
++m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
template<typename T, std::size_t SmallVectorSize, typename Allocator>
|
||||||
constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) {
|
constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) {
|
||||||
--m_size;
|
--m_size;
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
O1;net.drinkingtea.ox.TypeDescriptor;1;{
|
||||||
|
"fieldList" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"fieldName" : "pages",
|
||||||
|
"subscriptLevels" : 2,
|
||||||
|
"subscriptStack" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"subscriptType" : 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"subscriptType" : 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeId" : "B.uint16;0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preloadable" : true,
|
||||||
|
"primitiveType" : 5,
|
||||||
|
"typeName" : "net.drinkingtea.nostalgia.core.Palette",
|
||||||
|
"typeVersion" : 2
|
||||||
|
}
|
@ -27,7 +27,7 @@ struct TileSheetV1 {
|
|||||||
int rows = 1;
|
int rows = 1;
|
||||||
int columns = 1;
|
int columns = 1;
|
||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
Palette pal;
|
PaletteV1 pal;
|
||||||
ox::Vector<uint8_t> pixels = {};
|
ox::Vector<uint8_t> pixels = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ static ox::Error loadTileSheetSet(
|
|||||||
.targetBpp = static_cast<unsigned>(set.bpp),
|
.targetBpp = static_cast<unsigned>(set.bpp),
|
||||||
.setEntry = &entry,
|
.setEntry = &entry,
|
||||||
};
|
};
|
||||||
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
oxReturnError(ox::readMC({ts, static_cast<std::size_t>(tsStat.size)}, target));
|
||||||
tileWriteIdx += target.tileWriteIdx;
|
tileWriteIdx += target.tileWriteIdx;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
@ -215,7 +215,7 @@ ox::Error loadBgTileSheet(
|
|||||||
.defaultPalette = {},
|
.defaultPalette = {},
|
||||||
.tileMap = MEM_BG_TILES[cbb].data(),
|
.tileMap = MEM_BG_TILES[cbb].data(),
|
||||||
};
|
};
|
||||||
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
oxReturnError(ox::readMC({ts, static_cast<std::size_t>(tsStat.size)}, target));
|
||||||
// update bpp of all bgs with the updated cbb
|
// update bpp of all bgs with the updated cbb
|
||||||
const auto bpp = ctx.cbbData[cbb].bpp;
|
const auto bpp = ctx.cbbData[cbb].bpp;
|
||||||
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||||
@ -267,7 +267,7 @@ ox::Error loadSpriteTileSheet(
|
|||||||
.defaultPalette = {},
|
.defaultPalette = {},
|
||||||
.tileMap = MEM_SPRITE_TILES,
|
.tileMap = MEM_SPRITE_TILES,
|
||||||
};
|
};
|
||||||
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
oxReturnError(ox::readMC({ts, static_cast<std::size_t>(tsStat.size)}, target));
|
||||||
if (loadDefaultPalette && target.defaultPalette) {
|
if (loadDefaultPalette && target.defaultPalette) {
|
||||||
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
|
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,7 @@ void panic(const char *file, int line, const char *panicMsg, ox::Error const&err
|
|||||||
std::ignore = initConsole(*ctx);
|
std::ignore = initConsole(*ctx);
|
||||||
setBgStatus(*ctx, 0, true);
|
setBgStatus(*ctx, 0, true);
|
||||||
clearBg(*ctx, 0);
|
clearBg(*ctx, 0);
|
||||||
ox::IString<23> serr = "Error code: ";
|
auto const serr = ox::sfmt<ox::IString<23>>("Error code: {}", static_cast<int64_t>(err));
|
||||||
serr += static_cast<int64_t>(err);
|
|
||||||
puts(*ctx, 32 + 1, 1, "SADNESS...");
|
puts(*ctx, 32 + 1, 1, "SADNESS...");
|
||||||
puts(*ctx, 32 + 1, 4, "UNEXPECTED STATE:");
|
puts(*ctx, 32 + 1, 4, "UNEXPECTED STATE:");
|
||||||
puts(*ctx, 32 + 2, 6, panicMsg);
|
puts(*ctx, 32 + 2, 6, panicMsg);
|
||||||
|
@ -58,29 +58,25 @@ static class: public keel::Module {
|
|||||||
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
|
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
|
||||||
return {
|
return {
|
||||||
// convert tilesheets to CompactTileSheets
|
// convert tilesheets to CompactTileSheets
|
||||||
[](keel::Context &ctx, ox::Buffer &buff) -> ox::Error {
|
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
|
||||||
oxRequire(hdr, keel::readAssetHeader(buff));
|
|
||||||
auto const typeId = ox::buildTypeId(
|
|
||||||
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
|
|
||||||
if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
|
if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
|
||||||
typeId == ox::ModelTypeId_v<TileSheetV2> ||
|
typeId == ox::ModelTypeId_v<TileSheetV2> ||
|
||||||
typeId == ox::ModelTypeId_v<TileSheetV3> ||
|
typeId == ox::ModelTypeId_v<TileSheetV3> ||
|
||||||
typeId == ox::ModelTypeId_v<TileSheetV4>) {
|
typeId == ox::ModelTypeId_v<TileSheetV4>) {
|
||||||
oxReturnError(keel::convertBuffToBuff<CompactTileSheet>(
|
oxReturnError(keel::convertBuffToBuff<CompactTileSheet>(
|
||||||
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
|
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return {};
|
return false;
|
||||||
},
|
},
|
||||||
[](keel::Context &ctx, ox::Buffer &buff) -> ox::Error {
|
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
|
||||||
oxRequire(hdr, keel::readAssetHeader(buff));
|
|
||||||
auto const typeId = ox::buildTypeId(
|
|
||||||
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
|
|
||||||
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
|
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
|
||||||
typeId == ox::ModelTypeId_v<PaletteV1>) {
|
typeId == ox::ModelTypeId_v<PaletteV1>) {
|
||||||
oxReturnError(keel::convertBuffToBuff<Palette>(
|
oxReturnError(keel::convertBuffToBuff<Palette>(
|
||||||
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
|
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return {};
|
return false;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,6 @@ void PaletteEditorImGui::drawColumn(ox::CStringView txt) noexcept {
|
|||||||
ImGui::Text("%s", txt.c_str());
|
ImGui::Text("%s", txt.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaletteEditorImGui::drawColumn(uint64_t i) noexcept {
|
|
||||||
ox::Array<char, 10> numStr;
|
|
||||||
ox::itoa(i, numStr.data());
|
|
||||||
drawColumn(numStr.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void PaletteEditorImGui::drawColorsEditor() noexcept {
|
void PaletteEditorImGui::drawColorsEditor() noexcept {
|
||||||
constexpr auto tableFlags = ImGuiTableFlags_RowBg;
|
constexpr auto tableFlags = ImGuiTableFlags_RowBg;
|
||||||
auto const colorsSz = ImGui::GetContentRegionAvail();
|
auto const colorsSz = ImGui::GetContentRegionAvail();
|
||||||
|
@ -33,7 +33,9 @@ class PaletteEditorImGui: public studio::Editor {
|
|||||||
private:
|
private:
|
||||||
static void drawColumn(ox::CStringView txt) noexcept;
|
static void drawColumn(ox::CStringView txt) noexcept;
|
||||||
|
|
||||||
static void drawColumn(uint64_t i) noexcept;
|
static void drawColumn(ox::Integer_c auto i) noexcept {
|
||||||
|
drawColumn(ox::itoa(i));
|
||||||
|
}
|
||||||
|
|
||||||
void drawColorsEditor() noexcept;
|
void drawColorsEditor() noexcept;
|
||||||
|
|
||||||
|
@ -64,7 +64,6 @@ static ox::Error toPngFile(
|
|||||||
for (auto &c : pixels) {
|
for (auto &c : pixels) {
|
||||||
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
|
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
|
||||||
}
|
}
|
||||||
std::hash<std::string>();
|
|
||||||
constexpr auto fmt = LCT_RGBA;
|
constexpr auto fmt = LCT_RGBA;
|
||||||
return OxError(static_cast<ox::ErrorCode>(
|
return OxError(static_cast<ox::ErrorCode>(
|
||||||
lodepng_encode_file(
|
lodepng_encode_file(
|
||||||
@ -411,14 +410,13 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
|
|||||||
auto const pages = m_model.pal().pages.size();
|
auto const pages = m_model.pal().pages.size();
|
||||||
if (pages > 1) {
|
if (pages > 1) {
|
||||||
ImGui::Indent(20);
|
ImGui::Indent(20);
|
||||||
ox::Array<char, 10> numStr;
|
auto numStr = ox::itoa(m_model.palettePage() + 1);
|
||||||
ox::itoa(m_model.palettePage() + 1, numStr.data());
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - comboWidthSub);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - comboWidthSub);
|
||||||
if (ImGui::BeginCombo("Page", numStr.data(), 0)) {
|
if (ImGui::BeginCombo("Page", numStr.c_str(), 0)) {
|
||||||
for (auto n = 0u; n < pages; ++n) {
|
for (auto n = 0u; n < pages; ++n) {
|
||||||
auto const selected = (m_model.palettePage() == n);
|
auto const selected = (m_model.palettePage() == n);
|
||||||
ox::itoa(n + 1, numStr.data());
|
numStr = ox::itoa(n + 1);
|
||||||
if (ImGui::Selectable(numStr.data(), selected) && m_model.palettePage() != n) {
|
if (ImGui::Selectable(numStr.c_str(), selected) && m_model.palettePage() != n) {
|
||||||
m_model.setPalettePage(n);
|
m_model.setPalettePage(n);
|
||||||
}
|
}
|
||||||
if (selected) {
|
if (selected) {
|
||||||
@ -441,7 +439,7 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
|
|||||||
ImGui::PushID(static_cast<int>(i));
|
ImGui::PushID(static_cast<int>(i));
|
||||||
// Column: color idx
|
// Column: color idx
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
auto const label = ox::IString<8>() + (i + 1);
|
auto const label = ox::itoa(i + 1);
|
||||||
auto const rowSelected = i == m_view.palIdx();
|
auto const rowSelected = i == m_view.palIdx();
|
||||||
if (ImGui::Selectable(label.c_str(), rowSelected, ImGuiSelectableFlags_SpanAllColumns)) {
|
if (ImGui::Selectable(label.c_str(), rowSelected, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||||
m_view.setPalIdx(i);
|
m_view.setPalIdx(i);
|
||||||
|
@ -11,7 +11,7 @@ target_link_libraries(
|
|||||||
|
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
NostalgiaStudio PUBLIC
|
NostalgiaStudio PUBLIC
|
||||||
OLYMPIC_APP_VERSION="dev build"
|
OLYMPIC_APP_VERSION="d2024.05.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
@ -11,9 +11,7 @@ namespace keel {
|
|||||||
|
|
||||||
constexpr auto K1HdrSz = 40;
|
constexpr auto K1HdrSz = 40;
|
||||||
|
|
||||||
ox::Result<ox::UUID> readUuidHeader(ox::Buffer const&buff) noexcept;
|
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
ox::Result<ox::UUID> readUuidHeader(const char *buff, std::size_t buffLen) noexcept;
|
|
||||||
|
|
||||||
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexcept {
|
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexcept {
|
||||||
oxReturnError(write(writer, "K1;"));
|
oxReturnError(write(writer, "K1;"));
|
||||||
@ -22,24 +20,24 @@ ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexce
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> readAsset(ox::Buffer const&buff) noexcept {
|
ox::Result<T> readAsset(ox::BufferView buff) noexcept {
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
const auto err = readUuidHeader(buff).error;
|
const auto err = readUuidHeader(buff).error;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
offset = K1HdrSz; // the size of K1 headers
|
offset = K1HdrSz; // the size of K1 headers
|
||||||
}
|
}
|
||||||
return ox::readClaw<T>(buff.data() + offset, buff.size() - offset);
|
return ox::readClaw<T>(buff + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::Buffer const&buff) noexcept;
|
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
struct AssetHdr {
|
struct AssetHdr {
|
||||||
ox::UUID uuid;
|
ox::UUID uuid;
|
||||||
ox::ClawHeader clawHdr;
|
ox::ClawHeader clawHdr;
|
||||||
};
|
};
|
||||||
|
|
||||||
ox::Result<AssetHdr> readAssetHeader(char const*buff, std::size_t buffLen) noexcept;
|
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
ox::Result<AssetHdr> readAssetHeader(ox::Buffer const&buff) noexcept;
|
ox::Result<AssetHdr> readAssetHeader(ox::BufferView buff) noexcept;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
namespace keel {
|
namespace keel {
|
||||||
|
|
||||||
class Context;
|
class Context;
|
||||||
using PackTransform = ox::Error(*)(Context&, ox::Buffer &clawData);
|
using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringView);
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
@ -36,4 +36,22 @@ class Context {
|
|||||||
constexpr virtual ~Context() noexcept = default;
|
constexpr virtual ~Context() noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr ox::SpanView<PackTransform> packTransforms(
|
||||||
|
[[maybe_unused]] Context const&ctx) noexcept {
|
||||||
|
#ifndef OX_BARE_METAL
|
||||||
|
return ctx.packTransforms;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ox::SpanView<class BaseConverter const*> converters(
|
||||||
|
[[maybe_unused]] Context const&ctx) noexcept {
|
||||||
|
#ifndef OX_BARE_METAL
|
||||||
|
return ctx.converters;
|
||||||
|
#else
|
||||||
|
return {};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ ox::Error preloadObj(
|
|||||||
oxOutf("preloading {} as a {}\n", path, obj.type()->typeName);
|
oxOutf("preloading {} as a {}\n", path, obj.type()->typeName);
|
||||||
// preload
|
// preload
|
||||||
oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj), ox::alignOf<GbaPlatSpec>(obj)));
|
oxRequire(a, pl.startAlloc(ox::sizeOf<GbaPlatSpec>(&obj), ox::alignOf<GbaPlatSpec>(obj)));
|
||||||
auto const err = ox::preload<GbaPlatSpec, decltype(obj)>(&pl, &obj);
|
auto const err = ox::preload<GbaPlatSpec, ox::ModelObject>(&pl, &obj);
|
||||||
oxReturnError(pl.endAlloc());
|
oxReturnError(pl.endAlloc());
|
||||||
oxReturnError(err);
|
oxReturnError(err);
|
||||||
keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)};
|
keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)};
|
||||||
|
@ -40,7 +40,7 @@ class WrapInline: public Wrap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
constexpr auto makeWrap(Args &&...args) noexcept {
|
constexpr ox::UPtr<Wrap> makeWrap(Args &&...args) noexcept {
|
||||||
return ox::make_unique<WrapInline<T>>(ox::forward<Args>(args)...);
|
return ox::make_unique<WrapInline<T>>(ox::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,9 +65,10 @@ class BaseConverter {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
|
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
|
||||||
|
|
||||||
virtual ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
|
virtual ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
|
||||||
|
|
||||||
virtual ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept = 0;
|
virtual ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
|
||||||
|
keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool matches(
|
inline bool matches(
|
||||||
@ -84,12 +85,12 @@ class Converter: public BaseConverter {
|
|||||||
public:
|
public:
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::StringView srcTypeName() const noexcept final {
|
ox::StringView srcTypeName() const noexcept final {
|
||||||
return ox::requireModelTypeName<SrcType>();
|
return ox::ModelTypeName_v<SrcType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int srcTypeVersion() const noexcept final {
|
int srcTypeVersion() const noexcept final {
|
||||||
return ox::requireModelTypeVersion<SrcType>();
|
return ox::ModelTypeVersion_v<SrcType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -108,17 +109,19 @@ class Converter: public BaseConverter {
|
|||||||
&& dstTypeVersion == DstTypeVersion;
|
&& dstTypeVersion == DstTypeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept final {
|
ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(
|
||||||
|
keel::Context &ctx, Wrap &src) const noexcept final {
|
||||||
auto dst = makeWrap<DstType>();
|
auto dst = makeWrap<DstType>();
|
||||||
oxReturnError(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst)));
|
oxReturnError(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst)));
|
||||||
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
return {std::move(dst)};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept final {
|
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
|
||||||
|
keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept final {
|
||||||
oxRequireM(src, readAsset<SrcType>(srcBuff));
|
oxRequireM(src, readAsset<SrcType>(srcBuff));
|
||||||
auto dst = makeWrap<DstType>();
|
auto dst = makeWrap<DstType>();
|
||||||
oxReturnError(convert(ctx, src, wrapCast<DstType>(*dst)));
|
oxReturnError(convert(ctx, src, wrapCast<DstType>(*dst)));
|
||||||
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
return {std::move(dst)};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -126,9 +129,11 @@ class Converter: public BaseConverter {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convert(
|
ox::Result<ox::UPtr<Wrap>> convert(
|
||||||
keel::Context &ctx, ox::Buffer const&srcBuffer,
|
keel::Context &ctx,
|
||||||
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept;
|
ox::Buffer const&srcBuffer,
|
||||||
|
ox::CRStringView dstTypeName,
|
||||||
|
int dstTypeVersion) noexcept;
|
||||||
|
|
||||||
template<typename DstType>
|
template<typename DstType>
|
||||||
ox::Result<DstType> convert(keel::Context &ctx, ox::Buffer const&srcBuffer) noexcept {
|
ox::Result<DstType> convert(keel::Context &ctx, ox::Buffer const&srcBuffer) noexcept {
|
||||||
@ -148,7 +153,8 @@ ox::Error convert(keel::Context &ctx, ox::Buffer const&buff, DstType *outObj) no
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename DstType>
|
template<typename DstType>
|
||||||
ox::Result<ox::Buffer> convertBuffToBuff(keel::Context &ctx, ox::Buffer const&srcBuffer, ox::ClawFormat fmt) noexcept {
|
ox::Result<ox::Buffer> convertBuffToBuff(
|
||||||
|
keel::Context &ctx, ox::Buffer const&srcBuffer, ox::ClawFormat fmt) noexcept {
|
||||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
||||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
||||||
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
|
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
|
||||||
@ -156,14 +162,12 @@ ox::Result<ox::Buffer> convertBuffToBuff(keel::Context &ctx, ox::Buffer const&sr
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
|
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
|
||||||
auto transformRule(keel::Context &ctx, ox::Buffer &buff) noexcept -> ox::Error {
|
ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) noexcept {
|
||||||
oxRequire(hdr, readAssetHeader(buff));
|
|
||||||
const auto typeId = ox::buildTypeId(
|
|
||||||
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
|
|
||||||
if (typeId == ox::ModelTypeId_v<From>) {
|
if (typeId == ox::ModelTypeId_v<From>) {
|
||||||
oxReturnError(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
|
oxReturnError(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return {};
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class TypeStore: public ox::TypeStore {
|
|||||||
explicit TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept;
|
explicit TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ox::Result<ox::UPtr<ox::DescriptorType>> loadDescriptor(ox::CRStringView typeId) noexcept override;
|
ox::Result<ox::UPtr<ox::DescriptorType>> loadDescriptor(ox::StringView typeId) noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,41 +6,45 @@
|
|||||||
|
|
||||||
namespace keel {
|
namespace keel {
|
||||||
|
|
||||||
ox::Result<ox::UUID> readUuidHeader(ox::Buffer const&buff) noexcept {
|
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept {
|
||||||
return readUuidHeader(buff.data(), buff.size());
|
if (buff.size() < K1HdrSz) [[unlikely]] {
|
||||||
}
|
|
||||||
|
|
||||||
ox::Result<ox::UUID> readUuidHeader(char const*buff, std::size_t buffLen) noexcept {
|
|
||||||
if (buffLen < K1HdrSz) {
|
|
||||||
return OxError(1, "Insufficient data to contain complete Keel header");
|
return OxError(1, "Insufficient data to contain complete Keel header");
|
||||||
}
|
}
|
||||||
constexpr ox::StringView k1Hdr = "K1;";
|
constexpr ox::StringView k1Hdr = "K1;";
|
||||||
if (k1Hdr != ox::StringView(buff, k1Hdr.bytes())) {
|
if (k1Hdr != ox::StringView(buff.data(), k1Hdr.bytes())) [[unlikely]] {
|
||||||
return OxError(2, "No Keel asset header data");
|
return OxError(2, "No Keel asset header data");
|
||||||
}
|
}
|
||||||
return ox::UUID::fromString(ox::StringView(buff + k1Hdr.bytes(), 36));
|
return ox::UUID::fromString(ox::StringView(buff.data() + k1Hdr.bytes(), 36));
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::Buffer const&buff) noexcept {
|
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept {
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
if (!readUuidHeader(buff).error) {
|
if (!readUuidHeader(buff).error) {
|
||||||
offset = K1HdrSz;
|
offset = K1HdrSz;
|
||||||
}
|
}
|
||||||
return ox::readClaw(ts, buff.data() + offset, buff.size() - offset);
|
buff += offset;
|
||||||
|
return ox::readClaw(ts, buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<AssetHdr> readAssetHeader(char const*buff, std::size_t buffLen) noexcept {
|
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView buff) noexcept {
|
||||||
AssetHdr out;
|
const auto err = readUuidHeader(buff).error;
|
||||||
const auto err = readUuidHeader(buff, buffLen).moveTo(out.uuid);
|
|
||||||
const auto offset = err ? 0u : K1HdrSz;
|
const auto offset = err ? 0u : K1HdrSz;
|
||||||
buff = buff + offset;
|
if (offset >= buff.size()) [[unlikely]] {
|
||||||
buffLen = buffLen - offset;
|
return OxError(1, "Buffer too small for expected data");
|
||||||
oxReturnError(ox::readClawHeader(buff, buffLen).moveTo(out.clawHdr));
|
}
|
||||||
|
return ox::readClawTypeId(buff + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Result<AssetHdr> readAssetHeader(ox::BufferView buff) noexcept {
|
||||||
|
ox::Result<AssetHdr> out;
|
||||||
|
const auto err = readUuidHeader(buff).moveTo(out.value.uuid);
|
||||||
|
const auto offset = err ? 0u : K1HdrSz;
|
||||||
|
if (offset >= buff.size()) [[unlikely]] {
|
||||||
|
return OxError(1, "Buffer too small for expected data");
|
||||||
|
}
|
||||||
|
buff += offset;
|
||||||
|
oxReturnError(ox::readClawHeader(buff).moveTo(out.value.clawHdr));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<AssetHdr> readAssetHeader(ox::Buffer const&buff) noexcept {
|
|
||||||
return readAssetHeader(buff.data(), buff.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -102,14 +102,15 @@ ox::Result<ox::String> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept {
|
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
oxRequireM(typeId, readAssetTypeId(clawData));
|
||||||
for (auto tr : ctx.packTransforms) {
|
for (auto const tr : packTransforms(ctx)) {
|
||||||
oxReturnError(tr(ctx, clawData));
|
bool changed{};
|
||||||
|
oxReturnError(tr(ctx, clawData, typeId).moveTo(changed));
|
||||||
|
if (changed) {
|
||||||
|
oxReturnError(readAssetTypeId(clawData).moveTo(typeId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
#else
|
|
||||||
return OxError(1, "Transformations not supported on this platform");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -153,7 +154,7 @@ ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::CRStringView path
|
|||||||
oxRequire(stat, ctx.rom->stat(path));
|
oxRequire(stat, ctx.rom->stat(path));
|
||||||
oxRequire(buff, static_cast<ox::MemFS*>(ctx.rom.get())->directAccess(path));
|
oxRequire(buff, static_cast<ox::MemFS*>(ctx.rom.get())->directAccess(path));
|
||||||
PreloadPtr p;
|
PreloadPtr p;
|
||||||
oxReturnError(ox::readMC(buff, static_cast<std::size_t>(stat.size), &p));
|
oxReturnError(ox::readMC({buff, static_cast<std::size_t>(stat.size)}, p));
|
||||||
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const
|
|||||||
oxRequire(stat, ctx.rom->stat(file));
|
oxRequire(stat, ctx.rom->stat(file));
|
||||||
oxRequire(buff, static_cast<ox::MemFS*>(ctx.rom.get())->directAccess(file));
|
oxRequire(buff, static_cast<ox::MemFS*>(ctx.rom.get())->directAccess(file));
|
||||||
PreloadPtr p;
|
PreloadPtr p;
|
||||||
oxReturnError(ox::readMC(buff, static_cast<std::size_t>(stat.size), &p));
|
oxReturnError(ox::readMC({buff, static_cast<std::size_t>(stat.size)}, p));
|
||||||
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ static ox::Error pathToInode(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (beginsWith(path, "uuid://")) {
|
if (beginsWith(path, "uuid://")) {
|
||||||
auto const uuid = substr<ox::StringView>(path, 7);
|
auto const uuid = ox::substr(path, 7);
|
||||||
oxReturnError(keel::uuidToPath(ctx, uuid).moveTo(path));
|
oxReturnError(keel::uuidToPath(ctx, uuid).moveTo(path));
|
||||||
}
|
}
|
||||||
oxRequire(s, dest.stat(path));
|
oxRequire(s, dest.stat(path));
|
||||||
|
@ -10,13 +10,13 @@
|
|||||||
namespace keel {
|
namespace keel {
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static ox::Result<const BaseConverter*> findConverter(
|
static ox::Result<BaseConverter const*> findConverter(
|
||||||
ox::Vector<const BaseConverter*> const&converters,
|
ox::SpanView<BaseConverter const*> const&converters,
|
||||||
ox::CRStringView srcTypeName,
|
ox::CRStringView srcTypeName,
|
||||||
int srcTypeVersion,
|
int srcTypeVersion,
|
||||||
ox::CRStringView dstTypeName,
|
ox::CRStringView dstTypeName,
|
||||||
int dstTypeVersion) noexcept {
|
int dstTypeVersion) noexcept {
|
||||||
for (auto &c : converters) {
|
for (auto const&c : converters) {
|
||||||
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -24,21 +24,22 @@ static ox::Result<const BaseConverter*> findConverter(
|
|||||||
return OxError(1, "Could not find converter");
|
return OxError(1, "Could not find converter");
|
||||||
};
|
};
|
||||||
|
|
||||||
static ox::Result<ox::UniquePtr<Wrap>> convert(
|
static ox::Result<ox::UPtr<Wrap>> convert(
|
||||||
[[maybe_unused]] keel::Context &ctx,
|
keel::Context &ctx,
|
||||||
ox::Vector<const BaseConverter*> const&converters,
|
ox::SpanView<BaseConverter const*> const&converters,
|
||||||
[[maybe_unused]] ox::Buffer const&srcBuffer,
|
ox::Buffer const&srcBuffer,
|
||||||
[[maybe_unused]] ox::CRStringView srcTypeName,
|
ox::CRStringView srcTypeName,
|
||||||
[[maybe_unused]] int srcTypeVersion,
|
int srcTypeVersion,
|
||||||
[[maybe_unused]] ox::CRStringView dstTypeName,
|
ox::CRStringView dstTypeName,
|
||||||
[[maybe_unused]] int dstTypeVersion) noexcept {
|
int dstTypeVersion) noexcept {
|
||||||
// look for direct converter
|
// look for direct converter
|
||||||
auto [c, err] = findConverter(converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
auto [c, err] = findConverter(
|
||||||
|
converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
return c->convertBuffToPtr(ctx, srcBuffer);
|
return c->convertBuffToPtr(ctx, srcBuffer);
|
||||||
}
|
}
|
||||||
// try to chain multiple converters
|
// try to chain multiple converters
|
||||||
for (const auto &subConverter : converters) {
|
for (auto const&subConverter : converters) {
|
||||||
if (!subConverter->dstMatches(dstTypeName, dstTypeVersion)) {
|
if (!subConverter->dstMatches(dstTypeName, dstTypeVersion)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -52,24 +53,20 @@ static ox::Result<ox::UniquePtr<Wrap>> convert(
|
|||||||
return OxError(1, "Could not convert between types");
|
return OxError(1, "Could not convert between types");
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convert(
|
ox::Result<ox::UPtr<Wrap>> convert(
|
||||||
[[maybe_unused]] keel::Context &ctx,
|
keel::Context &ctx,
|
||||||
[[maybe_unused]] ox::Buffer const&srcBuffer,
|
ox::Buffer const&srcBuffer,
|
||||||
[[maybe_unused]] ox::CRStringView dstTypeName,
|
ox::CRStringView dstTypeName,
|
||||||
[[maybe_unused]] int dstTypeVersion) noexcept {
|
int dstTypeVersion) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
oxRequire(hdr, readAssetHeader(srcBuffer));
|
oxRequire(hdr, readAssetHeader(srcBuffer));
|
||||||
return convert(
|
return convert(
|
||||||
ctx,
|
ctx,
|
||||||
ctx.converters,
|
converters(ctx),
|
||||||
srcBuffer,
|
srcBuffer,
|
||||||
hdr.clawHdr.typeName,
|
hdr.clawHdr.typeName,
|
||||||
hdr.clawHdr.typeVersion,
|
hdr.clawHdr.typeVersion,
|
||||||
dstTypeName,
|
dstTypeName,
|
||||||
dstTypeVersion);
|
dstTypeVersion);
|
||||||
#else
|
|
||||||
return OxError(1, "Operation not supported on this platform");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,11 @@ TypeStore::TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept:
|
|||||||
m_descPath(descPath) {
|
m_descPath(descPath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UPtr<ox::DescriptorType>> TypeStore::loadDescriptor(ox::CRStringView typeId) noexcept {
|
ox::Result<ox::UPtr<ox::DescriptorType>> TypeStore::loadDescriptor(ox::StringView const typeId) noexcept {
|
||||||
auto path = ox::sfmt("{}/{}", m_descPath, typeId);
|
auto const path = ox::sfmt("{}/{}", m_descPath, typeId);
|
||||||
oxRequire(buff, m_fs.read(path));
|
oxRequire(buff, m_fs.read(path));
|
||||||
auto dt = ox::make_unique<ox::DescriptorType>();
|
auto dt = ox::make_unique<ox::DescriptorType>();
|
||||||
oxReturnError(ox::readClaw<ox::DescriptorType>(buff, dt.get()));
|
oxReturnError(ox::readClaw<ox::DescriptorType>(buff, *dt));
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ static ox::Error run(
|
|||||||
static_cast<uint64_t>(time << 1)
|
static_cast<uint64_t>(time << 1)
|
||||||
});
|
});
|
||||||
// run app
|
// run app
|
||||||
auto const err = runApp(appName, projectDataDir, ox::UniquePtr<ox::FileSystem>(nullptr));
|
auto const err = runApp(appName, projectDataDir, ox::UPtr<ox::FileSystem>(nullptr));
|
||||||
oxAssert(err, "Something went wrong...");
|
oxAssert(err, "Something went wrong...");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,9 @@ ox::Result<T> getDragDropPayload(ox::CStringView name) noexcept {
|
|||||||
if (!payload) {
|
if (!payload) {
|
||||||
return OxError(1, "No drag/drop payload");
|
return OxError(1, "No drag/drop payload");
|
||||||
}
|
}
|
||||||
return ox::readClaw<T>(
|
return ox::readClaw<T>({
|
||||||
reinterpret_cast<char const*>(payload->Data),
|
reinterpret_cast<char const*>(payload->Data),
|
||||||
static_cast<size_t>(payload->DataSize));
|
static_cast<size_t>(payload->DataSize)});
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error setDragDropPayload(ox::CStringView name, auto const &obj) noexcept {
|
ox::Error setDragDropPayload(ox::CStringView name, auto const &obj) noexcept {
|
||||||
|
@ -13,5 +13,6 @@
|
|||||||
#include <studio/popup.hpp>
|
#include <studio/popup.hpp>
|
||||||
#include <studio/project.hpp>
|
#include <studio/project.hpp>
|
||||||
#include <studio/task.hpp>
|
#include <studio/task.hpp>
|
||||||
|
#include <studio/undocommand.hpp>
|
||||||
#include <studio/undostack.hpp>
|
#include <studio/undostack.hpp>
|
||||||
#include <studio/widget.hpp>
|
#include <studio/widget.hpp>
|
||||||
|
19
src/olympic/studio/modlib/include/studio/undocommand.hpp
Normal file
19
src/olympic/studio/modlib/include/studio/undocommand.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
class UndoCommand {
|
||||||
|
public:
|
||||||
|
virtual ~UndoCommand() noexcept = default;
|
||||||
|
virtual void redo() noexcept = 0;
|
||||||
|
virtual void undo() noexcept = 0;
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual int commandId() const noexcept = 0;
|
||||||
|
virtual bool mergeWith(UndoCommand const*cmd) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -9,17 +9,9 @@
|
|||||||
#include <ox/std/memory.hpp>
|
#include <ox/std/memory.hpp>
|
||||||
#include <ox/std/vector.hpp>
|
#include <ox/std/vector.hpp>
|
||||||
|
|
||||||
namespace studio {
|
#include "undocommand.hpp"
|
||||||
|
|
||||||
class UndoCommand {
|
namespace studio {
|
||||||
public:
|
|
||||||
virtual ~UndoCommand() noexcept = default;
|
|
||||||
virtual void redo() noexcept = 0;
|
|
||||||
virtual void undo() noexcept = 0;
|
|
||||||
[[nodiscard]]
|
|
||||||
virtual int commandId() const noexcept = 0;
|
|
||||||
virtual bool mergeWith(UndoCommand const*cmd) noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UndoStack {
|
class UndoStack {
|
||||||
private:
|
private:
|
||||||
|
@ -7,6 +7,7 @@ add_library(
|
|||||||
popup.cpp
|
popup.cpp
|
||||||
project.cpp
|
project.cpp
|
||||||
task.cpp
|
task.cpp
|
||||||
|
undocommand.cpp
|
||||||
undostack.cpp
|
undostack.cpp
|
||||||
filedialog_nfd.cpp
|
filedialog_nfd.cpp
|
||||||
)
|
)
|
||||||
|
10
src/olympic/studio/modlib/src/undocommand.cpp
Normal file
10
src/olympic/studio/modlib/src/undocommand.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
#include <studio/undocommand.hpp>
|
||||||
|
|
||||||
|
namespace studio {
|
||||||
|
|
||||||
|
bool UndoCommand::mergeWith(UndoCommand const*) noexcept {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,10 +6,6 @@
|
|||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
bool UndoCommand::mergeWith(UndoCommand const*) noexcept {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UndoStack::push(ox::UPtr<UndoCommand> &&cmd) noexcept {
|
void UndoStack::push(ox::UPtr<UndoCommand> &&cmd) noexcept {
|
||||||
for (auto const i = m_stackIdx; i < m_stack.size();) {
|
for (auto const i = m_stackIdx; i < m_stack.size();) {
|
||||||
std::ignore = m_stack.erase(i);
|
std::ignore = m_stack.erase(i);
|
||||||
|
Reference in New Issue
Block a user