Compare commits

...

54 Commits

Author SHA1 Message Date
889fe04255 [nostalgia/studio] Set version to 2024.05.0
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-23 22:11:52 -05:00
eed115b287 [keel] Fix a GCC break
All checks were successful
Build / build (push) Successful in 2m39s
2024-05-17 21:13:15 -05:00
7233da75ea [ox/std] Remove dedicated keys array from SmallMap
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-11 01:59:40 -05:00
30797c710b [ox/std] Add small sz option to SmallMap 2024-05-11 00:53:31 -05:00
e8041121d0 [ox/std] Add missing oxExpect to timeMapStrToUuid
All checks were successful
Build / build (push) Successful in 2m32s
2024-05-11 00:26:57 -05:00
d054528e49 [ox/std] Remove empty if from SmallMap
Some checks failed
Build / build (push) Has been cancelled
2024-05-11 00:24:37 -05:00
09d840cfd0 [ox/std] Add some functions for comparing HashMap and SmallMap
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-10 23:58:35 -05:00
aeb1ef3b12 [ox/std] Cleanup SmallMap, make it easier to make potential changes 2024-05-10 23:58:22 -05:00
b66f61c217 [ox/std] Add hash function for UUID 2024-05-10 23:55:41 -05:00
b089bf460b [ox/std] Optimize Array compare 2024-05-10 23:54:22 -05:00
cd60c4abaf [ox/std] Fix bugs in HashMap and SmallMap
All checks were successful
Build / build (push) Successful in 2m30s
2024-05-10 22:10:34 -05:00
d1845448c3 [ox/std] Add == and != operators to UUID 2024-05-10 22:10:14 -05:00
c4f6ee0026 [nostalgia,olympic] Make performPackTransforms update type id when needed 2024-05-10 19:51:03 -05:00
17f28d43d1 [ox/clargs] Replace C string with StringView
All checks were successful
Build / build (push) Successful in 2m27s
2024-05-10 01:30:54 -05:00
043df533b7 [ox] Cleanup string len handling
Some checks failed
Build / build (push) Has been cancelled
Remove UTF-8 parsing. It is a rare enough need that it should have a specialized call when needed.
Better to have a more optimal length fetch for typical case.
2024-05-10 01:29:13 -05:00
bec75d2eba [ox/std] Fix memory leak in Vector 2024-05-09 23:12:36 -05:00
f624c720f9 [studio] Fix broken readClaw call
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-08 23:54:06 -05:00
204e5bbff4 [ox/std] Add SmallMap
All checks were successful
Build / build (push) Successful in 2m28s
2024-05-08 23:46:12 -05:00
1ecf197a9e [nostalgia] Remove .idea directory 2024-05-08 23:44:05 -05:00
74a8a7d751 [ox/std] Remove incomplete writeF32toa
All checks were successful
Build / build (push) Successful in 2m28s
2024-05-08 23:43:12 -05:00
331f721292 [olympic,nostalgia] Cleanup
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-08 23:35:34 -05:00
63486c23d4 [ox] Cleanup 2024-05-08 23:35:05 -05:00
47a6a410c4 [ox/std] Update Vector memory map for preloader
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-03 23:41:16 -05:00
d82c082256 [buildcore] Add error message to pybb debug for missing debugger
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-03 22:58:36 -05:00
227f3cd9f5 [nostalgia/core/studio] Update itoa usages
All checks were successful
Build / build (push) Successful in 2m34s
2024-05-03 20:32:18 -05:00
20ff0f89fe [ox/std] Rework itoa 2024-05-03 20:31:40 -05:00
4061b8314e [ox/model] Remove broken global var
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-03 00:12:34 -05:00
18bb50626d [ox/std] Add String::append(StringView), cleanup
All checks were successful
Build / build (push) Successful in 2m30s
2024-05-03 00:07:03 -05:00
6a4b48221f [nostalgia,studio] Fixes for Ox changes 2024-05-03 00:00:05 -05:00
d2a3cfa72e [ox/std] Remove append operators from IString
This is because the append operators cannot report the failure that is possible with IString
2024-05-02 23:59:19 -05:00
7c4e2a6564 [ox/std] Cleanup IString 2024-05-02 23:33:39 -05:00
e30ebce4c0 [nostalgia] Add pyenv to .gitignore
All checks were successful
Build / build (push) Successful in 2m34s
2024-05-02 23:15:01 -05:00
7163947efd [ox/std] Cleanup 2024-05-02 23:14:03 -05:00
0a0a6e306d [studio] Move UndoCommand implementation to its own file 2024-05-02 22:50:25 -05:00
97bc9332d3 [nostalgia/core] Fix TileSheetV1 to use PaletteV1 2024-05-02 22:48:35 -05:00
9caf7099b6 [keel] Fix for Ox change 2024-05-02 22:21:04 -05:00
fda1280d29 [ox/std] Make substr always take and return a StringView 2024-05-02 22:20:25 -05:00
59aa4ad21a [cityhash] Cleanup 2024-05-02 22:20:01 -05:00
1a8afa1a98 [nostalgia/sample_project] Add missing type descriptor 2024-05-02 22:11:52 -05:00
cdbc2d6cc8 [olympic/studio] Move UndoCommand to its own file 2024-05-02 22:09:35 -05:00
acd93337d4 [ox/std] Fix Integer assignment operator return
All checks were successful
Build / build (push) Successful in 2m27s
2024-04-29 22:54:34 -05:00
cebd3b0a0f [ox/std] Fix Integer assignment operator return 2024-04-29 22:52:34 -05:00
43e2e2155b [ox/std] Cleanup 2024-04-29 22:48:22 -05:00
be1f90955b [ox/std] Make safeDelete constexpr
All checks were successful
Build / build (push) Successful in 2m32s
2024-04-29 22:43:27 -05:00
0f2c18d554 [ox/std] Add std::string(_view) variant of MaybeView
All checks were successful
Build / build (push) Successful in 2m29s
2024-04-25 23:03:38 -05:00
0c0ccd1a69 [nostalgia/core/studio] Cleanup scratchpad code
All checks were successful
Build / build (push) Successful in 2m32s
2024-04-24 23:09:50 -05:00
1b629da8fc [ox/std] Make Vector::contains always noexcept
All checks were successful
Build / build (push) Successful in 2m29s
2024-04-24 21:39:02 -05:00
32e4702dc7 [ox] Improve hasing and MaybeView
All checks were successful
Build / build (push) Successful in 2m29s
* Add CityHash dep
* Use CityHash for HashMap
* Make MaybeView more versatile
* Cleanup some inappropriate MaybeView uses
2024-04-24 20:59:37 -05:00
6b47133c22 [nostalgia] Cleanup StudioModules
All checks were successful
Build / build (push) Successful in 2m22s
2024-04-24 00:58:10 -05:00
0764720f9a [nostalgia,olympic] Update for Ox changes 2024-04-24 00:54:43 -05:00
78955376d6 [glutils] Update for Ox changes 2024-04-24 00:54:25 -05:00
a00a0bd2ff [ox] Rename BString to IString 2024-04-24 00:54:02 -05:00
ed4f0e1f2b [nostalgia,olympic] Replace oxIgnoreError with std::ignore 2024-04-22 23:43:22 -05:00
ea1feb726e [ox] Remove oxIgnoreError 2024-04-22 23:40:42 -05:00
120 changed files with 2314 additions and 1100 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
.stfolder
.stignore
scripts/__pycache__
pyenv
CMakeLists.txt.user
ROM.oxfs
Session.vim

8
.idea/.gitignore generated vendored
View File

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

View File

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

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="DrinkingTea" />
</state>
</component>

View File

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

View File

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

View File

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

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

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

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

View File

@ -98,6 +98,9 @@ def debug(paths: List[str]) -> int:
args = ['gdb', '--args']
elif shutil.which('lldb') is not None:
args = ['lldb', '--']
else:
sys.stderr.write('debug: could not find a supported debugger\n')
return 1
args.extend(paths)
return subprocess.run(args).returncode

View File

@ -3,7 +3,7 @@
*/
#include <ox/std/assert.hpp>
#include <ox/std/bstring.hpp>
#include <ox/std/istring.hpp>
#include <ox/std/trace.hpp>
#include "glutils/glutils.hpp"

View File

@ -82,4 +82,5 @@ if(OX_USE_STDLIB)
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
add_subdirectory(deps/jsoncpp)
endif()
add_subdirectory(deps/cityhash)
add_subdirectory(src)

30
deps/ox/deps/cityhash/CMakeLists.txt vendored Normal file
View 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)

View 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_

View File

@ -42,9 +42,9 @@ bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
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);
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 {

View File

@ -26,7 +26,7 @@ class ClArgs {
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
[[nodiscard]]
String getString(ox::CRStringView argName, const char *defaultValue) const noexcept;
String getString(ox::CRStringView argName, ox::StringView defaultValue) const noexcept;
[[nodiscard]]
int getInt(ox::CRStringView arg, int defaultValue) const noexcept;

View File

@ -12,34 +12,66 @@
namespace ox {
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept {
const auto s1End = ox::strchr(buff, ';', buffLen);
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
auto buffRaw = buff.data();
auto buffLen = buff.size();
size_t outSz{};
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
if (!s1End) {
return OxError(1, "Could not read Claw header");
}
const auto s1Size = static_cast<std::size_t>(s1End - buff);
const String fmt(buff, s1Size);
buff += s1Size + 1;
buffLen -= s1Size + 1;
const auto s2End = ox::strchr(buff, ';', buffLen);
auto const fmtSz = static_cast<std::size_t>(s1End - buffRaw) + 1;
buffRaw += fmtSz;
buffLen -= fmtSz;
outSz += fmtSz;
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
if (!s2End) {
return OxError(2, "Could not read Claw header");
}
const auto s2Size = static_cast<std::size_t>(s2End - buff);
const String typeName(buff, s2Size);
buff += s2Size + 1;
buffLen -= s2Size + 1;
const auto s3End = ox::strchr(buff, ';', buffLen);
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw) + 1;
buffRaw += s2Size;
buffLen -= s2Size;
outSz += s2Size;
auto const s3End = ox::strchr(buffRaw, ';', buffLen) + 1;
if (!s3End) {
return OxError(3, "Could not read Claw header");
}
const auto s3Size = static_cast<std::size_t>(s3End - buff);
const String versionStr(buff, s3Size);
buff += s3Size + 1;
buffLen -= s3Size + 1;
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
buffRaw += s3Size;
buffLen -= s3Size;
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;
if (fmt == "M2") {
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");
}
hdr.typeName = typeName;
if (auto r = ox::atoi(versionStr.c_str()); r.error == 0) {
hdr.typeVersion = r.value;
}
hdr.data = buff;
std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
hdr.data = buffRaw;
hdr.dataSize = buffLen;
return hdr;
}
Result<ClawHeader> readClawHeader(const ox::Buffer &buff) noexcept {
return readClawHeader(buff.data(), buff.size());
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff));
return {{header.data, header.dataSize}};
}
Result<Buffer> stripClawHeader(const char *buff, std::size_t buffLen) noexcept {
oxRequire(header, readClawHeader(buff, buffLen));
Buffer out(header.dataSize);
ox::listcpy(out.data(), header.data, out.size());
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);
Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff));
auto const [t, tdErr] = ts.getLoad(
header.typeName, header.typeVersion, header.typeParams);
if (tdErr) {
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) {
case ClawFormat::Metal:
{
ox::BufferReader br(header.data, header.dataSize);
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
@ -92,7 +113,7 @@ Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize);
OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
return obj;
@ -106,8 +127,4 @@ Result<ModelObject> readClaw(TypeStore &ts, const char *buff, std::size_t buffSz
return OxError(1);
}
Result<ModelObject> readClaw(TypeStore &ts, const Buffer &buff) noexcept {
return readClaw(ts, buff.data(), buff.size());
}
}

View File

@ -8,6 +8,7 @@
#pragma once
#include <ox/std/span.hpp>
#include <ox/mc/read.hpp>
#ifdef OX_USE_STDLIB
#include <ox/oc/read.hpp>
@ -31,17 +32,15 @@ struct ClawHeader {
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<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept;
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept;
template<typename T>
Error readClaw(const char *buff, std::size_t buffLen, T *val) {
oxRequire(header, readClawHeader(buff, buffLen));
Error readClaw(ox::BufferView buff, T &val) {
oxRequire(header, readClawHeader(buff));
if (header.typeName != getModelTypeName<T>()) {
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) {
case ClawFormat::Metal:
{
ox::BufferReader br(header.data, header.dataSize);
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader);
return model(&handler, val);
return model(&handler, &val);
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize);
return model(&reader, val);
return model(&reader, &val);
#else
break;
#endif
@ -72,24 +71,12 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
}
template<typename T>
Result<T> readClaw(const char *buff, std::size_t buffLen) {
T val;
oxReturnError(readClaw(buff, buffLen, &val));
Result<T> readClaw(ox::BufferView buff) {
Result<T> val;
oxReturnError(readClaw(buff, val.value));
return val;
}
template<typename T>
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;
Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept;
}

View File

@ -10,5 +10,6 @@ target_link_libraries(
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] ClawHeaderReadTypeId" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReadTypeId)
add_test("[ox/claw] ClawWriter" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawWriter)
add_test("[ox/claw] ClawReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawReader)

View File

@ -29,7 +29,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> String = "";
ox::IString<32> String = "";
};
struct TestStruct {
@ -47,7 +47,7 @@ struct TestStruct {
int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union;
ox::BString<32> String = "";
ox::IString<32> String = "";
uint32_t List[4] = {0, 0, 0, 0};
TestStructNest EmptyStruct;
TestStructNest Struct;
@ -109,7 +109,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader",
[] {
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(ch.fmt == ox::ClawFormat::Organic, "Format 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",
[] {
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(ch.fmt == ox::ClawFormat::Metal, "Format 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);
}
},
{
"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",
[] {
@ -156,7 +166,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
testIn.Struct.String = "Test String 2";
const auto [buff, err] = ox::writeMC(testIn);
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";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");

View File

@ -61,14 +61,14 @@ struct type_version<T, decltype((void) T::TypeVersion, -1)> {
template<typename T>
constexpr const char *getTypeName(const T *t) noexcept {
TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t));
std::ignore = model(&tnc, t);
return tnc.name;
}
template<typename T>
constexpr int getTypeVersion(const T *t) noexcept {
TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t));
std::ignore = model(&tnc, t);
return tnc.version;
}

View File

@ -391,7 +391,7 @@ Error Signal<Error(Args...)>::disconnectObject(const void *receiver) const noexc
template<class... Args>
void Signal<Error(Args...)>::emit(Args... args) const noexcept {
for (auto &f : m_slots) {
oxIgnoreError(f->call(ox::forward<Args>(args)...));
std::ignore = f->call(ox::forward<Args>(args)...);
}
}

View File

@ -159,7 +159,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
// determine if already exists
auto name = nameBuff;
oxReturnError(path.get(name));
oxReturnError(path.get(*name));
auto childInode = find(PathIterator(*name));
if (!childInode.ok()) {
// 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;
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 {}",
*name, path.fullPath());
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
// get the name
oxReturnError(path.next(name));
oxReturnError(path.next(*name));
// find existing version of directory
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;
}
auto &name = *nameBuff;
oxReturnError(path.get(&name));
oxReturnError(path.get(name));
oxTrace("ox.fs.Directory.remove", name);
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
auto name = nameBuff;
oxReturnError(path.get(name));
oxReturnError(path.get(*name));
oxRequire(v, findEntry(*name));
// recurse if not at end of path

View File

@ -61,8 +61,9 @@ Error PathIterator::fileName(char *out, std::size_t outSize) {
}
// 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::ignore = fileName.resize(MaxFileNameLength);
if (m_iterator >= m_maxSize) {
oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
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);
size = end - start;
// cannot fit the output in the output parameter
if (size >= pathOutSize || size == 0) {
if (size >= MaxFileNameLength || size == 0) {
return OxError(1);
}
ox::memcpy(pathOut, &m_path[start], size);
ox::memcpy(fileName.data(), &m_path[start], size);
// truncate trailing /
if (size && pathOut[size - 1] == '/') {
if (size && fileName[size - 1] == '/') {
size--;
}
pathOut[size] = 0; // end with null terminator
return OxError(0);
oxReturnError(fileName.resize(size));
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;
auto retval = OxError(1);
std::ignore = fileName.resize(MaxFileNameLength);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = OxError(0);
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);
size = end - start;
// cannot fit the output in the output parameter
if (size >= pathOutSize) {
if (size >= MaxFileNameLength) {
return OxError(1);
}
ox::memcpy(pathOut, &m_path[start], size);
ox::memcpy(fileName.data(), &m_path[start], size);
}
// truncate trailing /
if (size && pathOut[size - 1] == '/') {
if (size && fileName[size - 1] == '/') {
size--;
}
pathOut[size] = 0; // end with null terminator
fileName[size] = 0; // end with null terminator
oxReturnError(fileName.resize(size));
m_iterator += size;
return retval;
}
/**
* @return 0 if no error
*/
Error PathIterator::get(BString<MaxFileNameLength> *fileName) {
return get(fileName->data(), fileName->cap());
}
/**
* @return 0 if no error
*/
Error PathIterator::next(BString<MaxFileNameLength> *fileName) {
return next(fileName->data(), fileName->cap());
}
Result<std::size_t> PathIterator::nextSize() const {
std::size_t size = 0;
auto retval = OxError(1);

View File

@ -13,7 +13,7 @@
namespace ox {
constexpr std::size_t MaxFileNameLength = 255;
using FileName = BString<MaxFileNameLength>;
using FileName = IString<MaxFileNameLength>;
class PathIterator {
private:
@ -41,22 +41,12 @@ class PathIterator {
/**
* @return 0 if no error
*/
Error next(char *pathOut, std::size_t pathOutSize);
Error next(FileName &fileName);
/**
* @return 0 if no error
*/
Error get(char *pathOut, std::size_t pathOutSize);
/**
* @return 0 if no error
*/
Error next(FileName *fileName);
/**
* @return 0 if no error
*/
Error get(FileName *fileName);
Error get(FileName &fileName);
/**
* @return 0 if no error

View File

@ -34,7 +34,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
using BuffPtr_t = uint32_t;
ox::Vector<char> buff(5 * ox::units::MB);
auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
using String = ox::BString<6>;
using String = ox::IString<6>;
auto a1 = buffer->malloc(sizeof(String)).value;
auto a2 = buffer->malloc(sizeof(String)).value;
oxAssert(a1.valid(), "Allocation 1 failed.");
@ -60,10 +60,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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, path.len()) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next");
return OxError(0);
}
},
@ -72,9 +72,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
auto const path = ox::String("/usr/share/");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
@ -83,8 +83,8 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
@ -93,10 +93,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
auto const path = ox::String("usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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, path.len()) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
@ -105,9 +105,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
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) {
if (argc < 3) {
oxError("Must specify test to run and test argument");
if (argc < 2) {
oxError("Must specify test to run");
return -1;
}
ox::StringView const testName = args[1];
ox::StringView const testArg = args[2] ? args[2] : nullptr;

View File

@ -98,7 +98,7 @@ void LoggerConn::msgSend() noexcept {
break;
}
//std::printf("LoggerConn: sending %lu bytes\n", read);
oxIgnoreError(send(tmp.data(), read));
std::ignore = send(tmp.data(), read);
}
}
}

View File

@ -185,7 +185,7 @@ constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noe
template<typename I>
Result<I> decodeInteger(McInt m) noexcept {
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);
}

View File

@ -77,7 +77,7 @@ class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<R
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept;
constexpr Error field(const char*, IString<L> *val) noexcept;
constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept;
@ -322,9 +322,6 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
*val = BasicString<SmallStringSize>(cap);
auto data = val->data();
// read the string
if (static_cast<StringLength>(cap) < size) {
return OxError(McOutputBuffEnded);
}
oxReturnError(m_reader.read(data, size));
} else {
*val = "";
@ -336,8 +333,23 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<
template<Reader_c Reader>
template<std::size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept {
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>
@ -524,25 +536,20 @@ constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
template<typename T>
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept {
BufferReader br(buff, buffLen);
Error readMC(ox::BufferView buff, T &val) noexcept {
BufferReader br(buff);
MetalClawReader reader(br);
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
return model(&handler, val);
return model(&handler, &val);
}
template<typename T>
Result<T> readMC(const char *buff, std::size_t buffLen) noexcept {
T val;
oxReturnError(readMC(buff, buffLen, &val));
Result<T> readMC(ox::BufferView buff) noexcept {
Result<T> val;
oxReturnError(readMC(buff, val.value));
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>>;
}

View File

@ -27,7 +27,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> BString = "";
ox::IString<32> IString = "";
};
struct TestStruct {
@ -46,7 +46,7 @@ struct TestStruct {
int unionIdx = 1;
TestUnion Union;
ox::String String;
ox::BString<32> BString = "";
ox::IString<32> IString = "";
uint32_t List[4] = {0, 0, 0, 0};
ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5};
ox::Vector<uint32_t> Vector2 = {1, 2, 3, 4, 5};
@ -72,7 +72,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcep
oxModelBegin(TestStructNest)
oxModelField(Bool)
oxModelField(Int)
oxModelField(BString)
oxModelField(IString)
oxModelEnd()
template<typename T>
@ -95,7 +95,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexce
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
}
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("BString", &obj->BString));
oxReturnError(io->field("IString", &obj->IString));
oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("Vector", &obj->Vector));
oxReturnError(io->field("Vector2", &obj->Vector2));
@ -127,7 +127,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
TestStruct testIn, testOut;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "Test String 1";
testIn.IString = "Test String 1";
testIn.String = "Test String 2";
testIn.Vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };
testIn.Vector2 = {};
@ -137,13 +137,13 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
testIn.List[3] = 4;
testIn.Struct.Bool = true;
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 3";
testIn.Struct.IString = "Test String 3";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
// run tests
const auto [buff, err] = ox::writeMC(testIn);
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";
oxAssert(testIn.Bool == testOut.Bool, "Bool 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.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch");
oxAssert(testIn.BString == testOut.BString, "BString 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[1] == testOut.List[1], "List[1] value mismatch");
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
@ -171,9 +172,9 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
oxAssert(testIn.EmptyStruct.BString == testOut.EmptyStruct.BString, "EmptyStruct.BString value mismatch");
oxAssert(testIn.EmptyStruct.IString == testOut.EmptyStruct.IString, "EmptyStruct.IString value mismatch");
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
oxAssert(testIn.Struct.BString == testOut.Struct.BString, "Struct.BString value mismatch");
oxAssert(testIn.Struct.IString == testOut.Struct.IString, "Struct.IString value mismatch");
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
return OxError(0);
}
@ -303,14 +304,14 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
TestStruct testIn;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "Test String 1";
testIn.IString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = true;
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2";
testIn.Struct.IString = "Test String 2";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), testIn), "Data generation failed");
@ -319,10 +320,10 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(typeErr, "Descriptor write failed");
ox::ModelObject testOut;
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("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut.at("BString").unwrap()->get<ox::String>() == testIn.BString.c_str(), "testOut.String failed");
oxAssert(testOut.at("IString").unwrap()->get<ox::String>() == testIn.IString.c_str(), "testOut.String failed");
oxAssert(testOut.at("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut.at("Struct").unwrap()->get<ox::ModelObject>();
auto &testOutUnion = testOut.at("Union").unwrap()->get<ox::ModelUnion>();
@ -333,14 +334,14 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct.at("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct.at("BString").unwrap()->get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString failed");
oxAssert(testOutStruct.at("IString").unwrap()->get<ox::String>() == testIn.Struct.IString.c_str(), "testOut.Struct.IString failed");
oxAssert(testOut.at("unionIdx").unwrap()->get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion.at("Int").unwrap()->get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy.at("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy.at("BString").unwrap()->get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString (copy) failed");
oxAssert(testOutStructCopy.at("IString").unwrap()->get<ox::String>() == testIn.Struct.IString.c_str(), "testOut.Struct.IString (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0);
@ -357,19 +358,19 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
TestStruct testIn, testOut;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "Test String 1";
testIn.IString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2";
testIn.Struct.IString = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, testIn), "Data generation failed");
ox::TypeStore typeStore;
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(typeErr, "Descriptor write failed");
ox::BufferReader br(dataBuff, dataBuffLen);
ox::BufferReader br({dataBuff, dataBuffLen});
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 {
//std::cout << f.fieldName.c_str() << '\n';

View File

@ -66,7 +66,7 @@ class MetalClawWriter {
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, const BString<L> *val) noexcept;
constexpr Error field(const char*, const IString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept;
@ -206,8 +206,8 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, const BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->len());
}
template<Writer_c Writer>

View File

@ -37,12 +37,12 @@ constexpr auto buildTypeId() noexcept {
static constexpr auto buildTypeId(CRStringView name, int version,
const TypeParamPack &typeParams = {}) noexcept {
String tp;
if (typeParams.size()) {
if (!typeParams.empty()) {
tp = "#";
for (const auto &p : typeParams) {
tp += p + ",";
}
tp = tp.substr(0, tp.len() - 1);
tp.resize(tp.len() - 1);
tp += "#";
}
return ox::sfmt("{}{};{}", name, tp, version);

View File

@ -9,7 +9,7 @@
#pragma once
#include <ox/std/byteswap.hpp>
#include <ox/std/bstring.hpp>
#include <ox/std/istring.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
@ -152,7 +152,7 @@ class TypeDescWriter {
template<std::size_t sz>
[[nodiscard]]
constexpr const DescriptorType *type(const BString<sz> *val) const noexcept;
constexpr const DescriptorType *type(const IString<sz> *val) const noexcept;
template<typename T>
[[nodiscard]]
@ -334,7 +334,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
}
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const BString<sz>*) const noexcept {
constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::BString, 0, PT, 0);
}

View File

@ -9,7 +9,7 @@
#pragma once
#include <ox/std/byteswap.hpp>
#include <ox/std/bstring.hpp>
#include <ox/std/istring.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>

View File

@ -276,8 +276,8 @@ constexpr void moveModel(T *dst, T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Mover<size> mover(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&mover, src));
std::ignore = model(&dstFields, dst);
std::ignore = model(&mover, src);
}
template<typename T>
@ -285,8 +285,8 @@ constexpr void copyModel(T *dst, const T *src) noexcept {
constexpr auto size = ModelFieldCount_v<T>;
detail::MemberList<size> dstFields;
detail::Copier<size> copier(&dstFields);
oxIgnoreError(model(&dstFields, dst));
oxIgnoreError(model(&copier, src));
std::ignore = model(&dstFields, dst);
std::ignore = model(&copier, src);
}
template<typename T>
@ -295,8 +295,8 @@ constexpr bool equalsModel(T *a, T *b) noexcept {
constexpr auto size = T::Fields;
detail::MemberList<size> aFields;
detail::Equals<size> equals(&aFields);
oxIgnoreError(model(&aFields, a));
oxIgnoreError(model(&equals, b));
std::ignore = model(&aFields, a);
std::ignore = model(&equals, b);
return equals.value;
}

View File

@ -1057,13 +1057,13 @@ constexpr ModelValue::ModelValue(ModelValue &&other) noexcept {
template<typename T>
constexpr ModelValue::ModelValue(const T &val) noexcept
requires(!ox::is_same_v<ox::remove_reference_t<T>, ModelValue>) {
oxIgnoreError(set(val));
std::ignore = set(val);
}
template<typename T>
constexpr ModelValue::ModelValue(T &&val) noexcept
requires(!ox::is_same_v<ox::remove_reference_t<T>, ModelValue>) {
oxIgnoreError(set(ox::forward<T>(val)));
std::ignore = set(ox::forward<T>(val));
}
constexpr ModelValue::~ModelValue() noexcept {

View File

@ -97,13 +97,15 @@ struct TypeInfoCatcher {
};
template<typename T>
[[nodiscard]]
constexpr int getModelTypeVersion(T *val) noexcept {
TypeInfoCatcher nc;
oxIgnoreError(model(&nc, val));
std::ignore = model(&nc, val);
return nc.version;
}
template<typename T>
[[nodiscard]]
constexpr int getModelTypeVersion() noexcept {
std::allocator<T> a;
const auto t = a.allocate(1);
@ -113,6 +115,7 @@ constexpr int getModelTypeVersion() noexcept {
}
template<typename T>
[[nodiscard]]
consteval int requireModelTypeVersion() noexcept {
constexpr auto version = getModelTypeVersion<T>();
static_assert(version != 0, "TypeVersion is required");
@ -120,13 +123,15 @@ consteval int requireModelTypeVersion() noexcept {
}
template<typename T, typename Str = const char*>
[[nodiscard]]
constexpr Str getModelTypeName(T *val) noexcept {
TypeNameCatcher nc;
oxIgnoreError(model(&nc, val));
std::ignore = model(&nc, val);
return nc.name;
}
template<typename T, typename Str = const char*>
[[nodiscard]]
constexpr Str getModelTypeName() noexcept {
std::allocator<T> a;
auto t = a.allocate(1);
@ -136,8 +141,10 @@ constexpr Str getModelTypeName() noexcept {
}
template<typename T>
[[nodiscard]]
consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T>();
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
return name;
}
@ -147,19 +154,12 @@ constexpr auto ModelTypeName_v = getModelTypeName<T, Str>();
template<typename T, typename Str = const char*>
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::BString<versionStr.len()>{versionStr};
};
template<typename T>
constexpr auto ModelTypeId_v = [] {
constexpr auto name = ModelTypeName_v<T, ox::StringView>;
constexpr auto version = ModelTypeVersion_v<T>;
constexpr auto versionStr = ox::sfmt<ox::BString<19>>("{}", version);
return ox::sfmt<ox::BString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr);
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr);
}();
}

View File

@ -21,7 +21,7 @@
#endif
#include <ox/std/array.hpp>
#include <ox/std/bstring.hpp>
#include <ox/std/istring.hpp>
#include <ox/std/string.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>

View File

@ -101,7 +101,7 @@ class TypeStore {
}
protected:
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::CRStringView) noexcept {
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::StringView) noexcept {
return OxError(1);
}

View File

@ -64,7 +64,7 @@ constexpr Error DataWalker<Reader, T>::read(const DescriptorField &f, Reader *rd
template<typename Reader, typename T>
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>

View File

@ -70,7 +70,7 @@ class OrganicClawReader {
Error field(const char *key, BasicString<L> *val) noexcept;
template<std::size_t L>
Error field(const char *key, BString<L> *val) noexcept;
Error field(const char *key, IString<L> *val) noexcept;
Error fieldCString(const char *key, char *val, std::size_t buffLen) noexcept;
@ -206,8 +206,20 @@ Error OrganicClawReader::field(const char *key, BasicString<L> *val) noexcept {
}
template<std::size_t L>
Error OrganicClawReader::field(const char *key, BString<L> *val) noexcept {
return fieldCString(key, val->data(), val->cap());
Error OrganicClawReader::field(const char *key, IString<L> *val) noexcept {
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
@ -246,18 +258,18 @@ Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) noexcep
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.
try {
Json::Value doc;
Json::CharReaderBuilder parserBuilder;
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");
}
OrganicClawReader reader(buff, buffSize);
OrganicClawReader reader(buff.data(), buff.size());
ModelHandlerInterface handler(&reader);
return model(&handler, val);
return model(&handler, &val);
} catch (const Error &err) {
return err;
} catch (...) {
@ -266,20 +278,15 @@ Error readOC(const char *buff, std::size_t buffSize, auto *val) noexcept {
}
template<typename T>
Result<T> readOC(const char *json, std::size_t jsonLen) noexcept {
T val;
oxReturnError(readOC(json, jsonLen, &val));
Result<T> readOC(BufferView buff) noexcept {
Result<T> val;
oxReturnError(readOC(buff, val.value));
return val;
}
template<typename T>
Result<T> readOC(const char *json) noexcept {
return readOC<T>(json, ox::strlen(json));
}
template<typename T>
Result<T> readOC(const Buffer &buff) noexcept {
return readOC<T>(buff.data(), buff.size());
Result<T> readOC(ox::StringView json) noexcept {
return readOC<T>(ox::BufferView{json.data(), json.len()});
}
}

View File

@ -35,7 +35,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> String = "";
ox::IString<32> String = "";
};
struct TestStruct {
@ -211,7 +211,7 @@ const std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(type.error, "Descriptor write failed");
ox::ModelObject testOut;
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("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut.get("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");

View File

@ -132,7 +132,7 @@ class OrganicClawWriter {
}
template<std::size_t L>
Error field(char const*key, BString<L> const*val) noexcept {
Error field(char const*key, IString<L> const*val) noexcept {
if (targetValid() && val->len()) {
value(key) = val->c_str();
}

View File

@ -45,7 +45,7 @@ add_library(
if(NOT MSVC)
target_compile_options(OxStd PRIVATE -Wsign-conversion)
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_link_options(OxStd PUBLIC -W1,-E)
elseif(${OX_OS_FREEBSD})
@ -81,6 +81,7 @@ target_link_libraries(
OxStd PUBLIC
$<$<CXX_COMPILER_ID:GNU>:gcc>
OxTraceHook
CityHash
)
install(
@ -90,7 +91,7 @@ install(
assert.hpp
bit.hpp
bounds.hpp
bstring.hpp
istring.hpp
buffer.hpp
buildinfo.hpp
byteswap.hpp
@ -116,6 +117,7 @@ install(
ranges.hpp
serialize.hpp
size.hpp
smallmap.hpp
stacktrace.hpp
std.hpp
stddef.hpp
@ -123,6 +125,7 @@ install(
stringliteral.hpp
stringview.hpp
strongint.hpp
strconv.hpp
strops.hpp
trace.hpp
typeinfo.hpp

View File

@ -137,12 +137,16 @@ constexpr Array<T, ArraySize>::Array(Array &&other) noexcept {
template<typename T, std::size_t ArraySize>
constexpr bool Array<T, ArraySize>::operator==(const Array &other) const {
for (std::size_t i = 0; i < ArraySize; i++) {
if (!(m_items[i] == other.m_items[i])) {
return false;
if (std::is_constant_evaluated()) {
for (std::size_t i = 0; i < ArraySize; i++) {
if (!(m_items[i] == other.m_items[i])) {
return false;
}
}
return true;
} else {
return memcmp(this, &other, sizeof(*this)) == 0;
}
return true;
}
template<typename T, std::size_t ArraySize>

View File

@ -1,281 +0,0 @@
/*
* 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 "memops.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "typetraits.hpp"
namespace ox {
// Bounded String
template<std::size_t buffLen>
class BString {
private:
char m_buff[buffLen + 1];
public:
constexpr BString() noexcept;
constexpr BString(StringView str) noexcept;
constexpr BString(const char *str) noexcept;
constexpr BString &operator=(CRStringView str) noexcept;
constexpr BString &operator=(const char *str) noexcept;
constexpr BString &operator=(char *str) noexcept;
constexpr BString &operator=(Integer_c auto i) noexcept;
constexpr BString &operator+=(const char *str) noexcept;
constexpr BString &operator+=(char *str) noexcept;
constexpr BString &operator+=(Integer_c auto i) noexcept;
constexpr BString &operator+=(StringView s) noexcept;
constexpr BString operator+(const char *str) const noexcept;
constexpr BString operator+(char *str) const noexcept;
constexpr BString operator+(Integer_c auto i) const noexcept;
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const OxString_c auto &other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const OxString_c auto &other) noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept;
[[nodiscard]]
constexpr const char *data() const noexcept;
[[nodiscard]]
constexpr char *data() noexcept;
[[nodiscard]]
constexpr const char *c_str() const noexcept;
/**
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
*/
[[nodiscard]]
constexpr std::size_t bytes() const noexcept;
/**
* Returns the capacity of bytes for this string.
*/
[[nodiscard]]
constexpr std::size_t cap() const noexcept;
};
template<std::size_t size>
constexpr BString<size>::BString() noexcept: m_buff{{0}} {
}
template<std::size_t size>
constexpr BString<size>::BString(StringView str) noexcept: m_buff{{0}} {
operator=(str);
}
template<std::size_t size>
constexpr BString<size>::BString(const char *str) noexcept: m_buff{{0}} {
operator=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(Integer_c auto i) noexcept {
char str[65] = {};
ox::itoa(i, str);
return this->operator=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(ox::CRStringView str) noexcept {
std::size_t strLen = str.bytes() + 1;
if (cap() < strLen) {
strLen = cap();
}
ox::memcpy(m_buff, str.data(), strLen);
// make sure last element is a null terminator
m_buff[strLen] = 0;
return *this;
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(const char *str) noexcept {
std::size_t strLen = ox::strlen(str) + 1;
if (cap() < strLen) {
strLen = cap();
}
ox::memcpy(m_buff, str, strLen);
// make sure last element is a null terminator
m_buff[cap()] = 0;
return *this;
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator=(char *str) noexcept {
return *this = static_cast<const char*>(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(const char *str) noexcept {
std::size_t strLen = ox::strlen(str) + 1;
oxIgnoreError(append(str, strLen));
return *this;
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(Integer_c auto i) noexcept {
char str[65] = {};
ox::itoa(i, str);
return this->operator+=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
return *this;
}
template<std::size_t size>
constexpr BString<size> BString<size>::operator+(const char *str) const noexcept {
auto out = *this;
std::size_t strLen = ox::strlen(str) + 1;
oxIgnoreError(out.append(str, strLen));
return out;
}
template<std::size_t size>
constexpr BString<size> BString<size>::operator+(char *str) const noexcept {
return *this + static_cast<const char*>(str);
}
template<std::size_t size>
constexpr BString<size> BString<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 BString<buffLen>::operator==(const char *other) const noexcept {
return ox::StringView(*this) == other;
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator==(const OxString_c auto &other) const noexcept {
return ox::StringView(*this) == ox::StringView(other);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t buffLen>
constexpr bool BString<buffLen>::operator!=(const OxString_c auto &other) noexcept {
return !operator==(other);
}
template<std::size_t buffLen>
constexpr char BString<buffLen>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
constexpr Error BString<buffLen>::append(const char *str, std::size_t strLen) noexcept {
Error err;
auto currentLen = len();
if (cap() < currentLen + strLen + 1) {
strLen = cap() - currentLen;
err = OxError(1, "Insufficient space for full string");
}
ox::strncpy(m_buff + currentLen, str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
return err;
}
template<std::size_t buffLen>
constexpr const char *BString<buffLen>::data() const noexcept {
return static_cast<const char*>(m_buff);
}
template<std::size_t buffLen>
constexpr char *BString<buffLen>::data() noexcept {
return static_cast<char*>(m_buff);
}
template<std::size_t buffLen>
constexpr const char *BString<buffLen>::c_str() const noexcept {
return static_cast<const char*>(m_buff);
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::len() const noexcept {
std::size_t length = 0;
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>
constexpr std::size_t BString<buffLen>::bytes() const noexcept {
std::size_t i = 0;
for (i = 0; i < buffLen && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
template<std::size_t buffLen>
constexpr std::size_t BString<buffLen>::cap() const noexcept {
return buffLen;
}
}

View File

@ -10,6 +10,7 @@
#include "error.hpp"
#include "reader.hpp"
#include "span.hpp"
#include "vector.hpp"
#include "writer.hpp"
@ -18,6 +19,7 @@ namespace ox {
extern template class Vector<char>;
using Buffer = Vector<char>;
using BufferView = SpanView<char>;
class BufferWriter {
private:
@ -174,10 +176,7 @@ class BufferReader {
char const* m_buff = nullptr;
public:
constexpr explicit BufferReader(char const*buff, std::size_t sz) noexcept:
m_size(sz), m_buff(buff) {}
constexpr explicit BufferReader(ox::Buffer const&buffer) noexcept:
constexpr explicit BufferReader(ox::BufferView buffer) noexcept:
m_size(buffer.size()), m_buff(buffer.data()) {}
constexpr ox::Result<char> peek() const noexcept {

View File

@ -9,7 +9,7 @@
#pragma once
#include "basestringview.hpp"
#include "bstring.hpp"
#include "istring.hpp"
#include "string.hpp"
#include "stringliteral.hpp"
@ -27,7 +27,7 @@ class CStringView: public detail::BaseStringView {
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(std::nullptr_t) noexcept {}

View File

@ -112,38 +112,4 @@ constexpr int lastIndexOf(const auto &str, int character, std::size_t maxLen = 0
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;
}
}

View File

@ -234,6 +234,22 @@ struct [[nodiscard]] Result {
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>
constexpr ox::Result<U> to(auto const&f) & noexcept {
if (error) [[unlikely]] {
@ -314,7 +330,3 @@ constexpr Error toError(const Result<T> &r) noexcept {
}
}
constexpr void oxIgnoreError(const ox::Error&) noexcept {}
template<typename T>
constexpr void oxIgnoreError(const ox::Result<T>&) noexcept {}

View File

@ -18,7 +18,8 @@
#include "realstd.hpp"
#include "error.hpp"
#include "bstring.hpp"
#include "ignore.hpp"
#include "istring.hpp"
#include "string.hpp"
#include "strops.hpp"
#include "types.hpp"
@ -38,13 +39,18 @@ constexpr StringView toStringView(const char *s) noexcept {
}
template<bool force = false, std::size_t size>
constexpr StringView toStringView(const BString<size> &s) noexcept {
return s.c_str();
constexpr StringView toStringView(const IString<size> &s) noexcept {
return s;
}
template<bool force = false>
constexpr StringView toStringView(ox::StringLiteral s) noexcept {
return s;
}
template<bool force = false, std::size_t size>
constexpr StringView toStringView(const BasicString<size> &s) noexcept {
return s.c_str();
return s;
}
#if __has_include(<string>)
@ -74,14 +80,17 @@ constexpr StringView toStringView(const auto&) noexcept requires(force) {
class FmtArg {
private:
char dataStr[10] = {};
static constexpr auto DataSz = 23;
char dataStr[DataSz] = {};
template<typename T>
constexpr StringView sv(const T &v, char *dataStr) noexcept {
if constexpr(is_bool_v<T>) {
return v ? "true" : "false";
} 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 {
return toStringView(v);
}
@ -191,18 +200,18 @@ constexpr StringType sfmt(StringView fmt, Args&&... args) noexcept {
StringType out;
const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt);
const auto &firstSegment = fmtSegments.segments[0];
oxIgnoreError(out.append(firstSegment.str, firstSegment.length));
std::ignore = out.append(firstSegment.str, firstSegment.length);
const detail::FmtArg elements[sizeof...(args)] = {args...};
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];
oxIgnoreError(out.append(s.str, s.length));
std::ignore = out.append(s.str, s.length);
}
return out;
}
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()) {
return T("");
}

170
deps/ox/src/ox/std/hash.hpp vendored Normal file
View 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);
}
};
}

View File

@ -9,6 +9,8 @@
#pragma once
#include "algorithm.hpp"
#include "hash.hpp"
#include "ignore.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "vector.hpp"
@ -31,7 +33,7 @@ class HashMap {
Vector<Pair*> m_pairs;
public:
explicit constexpr HashMap(std::size_t size = 100);
explicit constexpr HashMap(std::size_t size = 127);
constexpr HashMap(HashMap const&other);
@ -67,10 +69,6 @@ class HashMap {
private:
constexpr void expand();
constexpr static uint64_t hash(Integral_c auto) noexcept;
constexpr static uint64_t hash(StringView const&) noexcept;
template<typename KK>
constexpr Pair *const&access(Vector<Pair*> const&pairs, KK const&key) const;
@ -135,17 +133,18 @@ constexpr HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &&other) noexcep
template<typename K, typename T>
constexpr T &HashMap<K, T>::operator[](MaybeView_t<K> const&k) {
auto &p = access(m_pairs, k);
if (p == nullptr) {
auto p = &access(m_pairs, k);
if (*p == nullptr) {
if (static_cast<double>(m_pairs.size()) * 0.7 <
static_cast<double>(m_keys.size())) {
expand();
p = &access(m_pairs, k);
}
p = new Pair;
p->key = k;
*p = new Pair;
(*p)->key = k;
m_keys.emplace_back(k);
}
return p->value;
return (*p)->value;
}
template<typename K, typename T>
@ -171,17 +170,17 @@ constexpr void HashMap<K, T>::erase(MaybeView_t<K> const&k) {
if (!contains(k)) {
return;
}
auto h = hash(k) % m_pairs.size();
auto h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
while (true) {
const auto &p = m_pairs[h];
if (p == nullptr || p->key == k) {
oxIgnoreError(m_pairs.erase(h));
std::ignore = m_pairs.erase(h);
break;
} else {
h = hash(h) % m_pairs.size();
h = ox::hash<MaybeView_t<K>>{}(k) % m_pairs.size();
}
}
oxIgnoreError(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));
}
template<typename K, typename T>
@ -205,12 +204,12 @@ constexpr void HashMap<K, T>::clear() {
delete m_pairs[i];
}
m_pairs.clear();
m_pairs.resize(100);
m_pairs.resize(127);
}
template<typename K, typename T>
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) {
auto const&k = m_keys[i];
access(r, k) = std::move(access(m_pairs, k));
@ -218,32 +217,12 @@ constexpr void HashMap<K, T>::expand() {
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 KK>
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) {
const auto &p = pairs[h];
auto const&p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == k) {
return p;
} else {
@ -255,9 +234,9 @@ constexpr typename HashMap<K, T>::Pair *const&HashMap<K, T>::access(Vector<Pair*
template<typename K, typename T>
template<typename KK>
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) {
auto &p = pairs[h];
auto &p = *pairs.at(h).unwrap();
if (p == nullptr || p->key == k) {
return p;
} else {

254
deps/ox/src/ox/std/istring.hpp vendored Normal file
View File

@ -0,0 +1,254 @@
/*
* 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 "array.hpp"
#include "concepts.hpp"
#include "cstrops.hpp"
#include "memops.hpp"
#include "error.hpp"
#include "buffer.hpp"
#include "ignore.hpp"
#include "stringview.hpp"
#include "typetraits.hpp"
#include "strconv.hpp"
namespace ox {
// Inline String
template<std::size_t StrCap>
class IString {
private:
size_t m_size{};
ox::Array<char, StrCap + 1> m_buff;
public:
constexpr IString() noexcept;
constexpr IString(StringView str) noexcept;
constexpr IString(const char *str) noexcept;
constexpr IString &operator=(CRStringView str) noexcept;
constexpr IString &operator=(const char *str) noexcept;
constexpr IString &operator=(Integer_c auto i) noexcept;
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const OxString_c auto &other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const OxString_c auto &other) noexcept;
constexpr char operator[](std::size_t i) const noexcept;
constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept;
constexpr Error append(ox::StringView str) noexcept;
[[nodiscard]]
constexpr const char *data() const noexcept;
[[nodiscard]]
constexpr char *data() noexcept;
[[nodiscard]]
constexpr const char *c_str() const noexcept;
/**
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t len() const noexcept;
/**
* Returns the number of bytes used for this string.
*/
[[nodiscard]]
constexpr std::size_t bytes() const noexcept;
constexpr ox::Error resize(size_t sz) noexcept;
/**
* Returns the capacity of bytes for this string.
*/
[[nodiscard]]
constexpr static std::size_t cap() noexcept {
return StrCap;
}
};
template<std::size_t size>
constexpr IString<size>::IString() noexcept: m_buff{{0}} {
}
template<std::size_t size>
constexpr IString<size>::IString(StringView str) noexcept: m_buff{{0}} {
operator=(str);
}
template<std::size_t size>
constexpr IString<size>::IString(const char *str) noexcept: m_buff{{0}} {
operator=(str);
}
template<std::size_t size>
constexpr IString<size> &IString<size>::operator=(Integer_c auto i) noexcept {
ox::Array<char, 22> s;
ox::CharBuffWriter w(s);
std::ignore = ox::writeItoa(i, w);
this->operator=({s.data(), w.tellp()});
return *this;
}
template<std::size_t size>
constexpr IString<size> &IString<size>::operator=(ox::CRStringView str) noexcept {
std::size_t strLen = str.len();
if (cap() < strLen) {
strLen = cap();
}
m_size = strLen;
ox::listcpy(m_buff.data(), str.data(), strLen);
// make sure last element is a null terminator
m_buff[strLen] = 0;
return *this;
}
template<std::size_t size>
constexpr IString<size> &IString<size>::operator=(const char *str) noexcept {
operator=(ox::StringView{str});
return *this;
}
template<std::size_t StrCap>
constexpr bool IString<StrCap>::operator==(const char *other) const noexcept {
return ox::StringView(*this) == other;
}
template<std::size_t StrCap>
constexpr bool IString<StrCap>::operator==(const OxString_c auto &other) const noexcept {
return ox::StringView(*this) == ox::StringView(other);
}
template<std::size_t StrCap>
constexpr bool IString<StrCap>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t StrCap>
constexpr bool IString<StrCap>::operator!=(const OxString_c auto &other) noexcept {
return !operator==(other);
}
template<std::size_t StrCap>
constexpr char IString<StrCap>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t StrCap>
constexpr char &IString<StrCap>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noexcept {
Error err{};
auto const currentLen = len();
if (cap() < currentLen + strLen) {
strLen = cap() - currentLen;
err = OxError(1, "Insufficient space for full string");
}
ox::strncpy(m_buff.data() + currentLen, str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
m_size += strLen;
return err;
}
template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(ox::StringView str) noexcept {
return append(str.data(), str.len());
}
template<std::size_t StrCap>
constexpr const char *IString<StrCap>::data() const noexcept {
return static_cast<const char*>(m_buff.data());
}
template<std::size_t StrCap>
constexpr char *IString<StrCap>::data() noexcept {
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 StrCap>
constexpr std::size_t IString<StrCap>::len() const noexcept {
return m_size;
}
template<std::size_t StrCap>
constexpr std::size_t IString<StrCap>::bytes() const noexcept {
return m_size + 1;
}
template<std::size_t StrCap>
constexpr ox::Error IString<StrCap>::resize(size_t sz) noexcept {
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;
}
}

View File

@ -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);
}
template<typename I>
template<typename I, typename E>
[[nodiscard]]
constexpr I pow(I v, int e) noexcept {
constexpr I pow(I v, E e) noexcept {
I out = 1;
for (I i = 0; i < e; i++) {
for (E i = 0; i < e; ++i) {
out *= v;
}
return out;

View File

@ -8,14 +8,17 @@
#pragma once
#include "typetraits.hpp"
#if __has_include(<string>)
#include <string>
#include <string_view>
#endif
namespace ox {
// Maybe StringView. If T is a string type, MaybeType::type/MaybeView_t is a
// StringView. This avoids creating unnecessary Strings when taking a
// StringView or C string as a function argument.
template<typename T, bool isStr = isOxString_v<T>>
template<typename T>
struct MaybeView {
using type = T;
};
@ -23,4 +26,11 @@ struct MaybeView {
template<typename T>
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
}

View File

@ -33,7 +33,7 @@ template<typename T1, typename T2>
constexpr T1 *listcpy(T1 *dest, T2 *src, std::size_t maxLen) noexcept {
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
std::size_t i = 0;
while (i < maxLen && src[i]) {
while (i < maxLen) {
dest[i] = static_cast<T1Type>(src[i]);
++i;
}

View File

@ -51,12 +51,12 @@ namespace ox {
*/
template<typename T>
void safeDelete(T *val) requires(sizeof(T) >= 1) {
constexpr void safeDelete(T *val) requires(sizeof(T) >= 1) {
delete val;
}
template<typename T>
void safeDeleteArray(T *val) requires(sizeof(T) >= 1) {
constexpr void safeDeleteArray(T *val) requires(sizeof(T) >= 1) {
delete[] val;
}

View File

@ -19,7 +19,6 @@ namespace ox {
template<typename PlatSpec>
struct VectorMemMap {
const std::size_t smallVecSize = 0; // not a map value
uint8_t allocator = 0;
typename PlatSpec::size_t size = 0;
typename PlatSpec::size_t cap = 0;
typename PlatSpec::PtrType items = 0;
@ -34,10 +33,8 @@ constexpr auto sizeOf(const VectorMemMap<PlatSpec> *t) noexcept {
std::size_t size = 0;
if (t->smallVecSize) {
size += t->smallVecSize;
size += padding(size, PlatSpec::alignOf(t->allocator));
size += padding(size, PlatSpec::alignOf(t->size));
}
size += sizeof(t->allocator);
size += padding(size, PlatSpec::alignOf(t->size));
size += sizeof(t->size);
size += padding(size, PlatSpec::alignOf(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>
constexpr ox::Error serialize(Writer_c auto &w, const VectorMemMap<PlatSpec> &vm) noexcept {
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.cap)));
oxReturnError(serialize(w, PlatSpec::correctEndianness(vm.items)));

249
deps/ox/src/ox/std/smallmap.hpp vendored Normal file
View 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();
}
}

View File

@ -19,8 +19,8 @@ template<typename T>
class SpanView {
private:
const T *m_items{};
const std::size_t m_size{};
T const*m_items{};
std::size_t m_size{};
public:
using value_type = T;
@ -106,6 +106,16 @@ class SpanView {
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]]
constexpr T const*data() const noexcept {
return m_items;

View File

@ -13,7 +13,7 @@
#include "assert.hpp"
#include "bit.hpp"
#include "bounds.hpp"
#include "bstring.hpp"
#include "istring.hpp"
#include "byteswap.hpp"
#include "concepts.hpp"
#include "cstringview.hpp"
@ -39,6 +39,7 @@
#include "realstd.hpp"
#include "serialize.hpp"
#include "size.hpp"
#include "smallmap.hpp"
#include "stacktrace.hpp"
#include "stddef.hpp"
#include "string.hpp"

46
deps/ox/src/ox/std/strconv.hpp vendored Normal file
View 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"

View File

@ -13,8 +13,10 @@
#endif
#include "algorithm.hpp"
#include "ignore.hpp"
#include "memops.hpp"
#include "serialize.hpp"
#include "strconv.hpp"
#include "stringliteral.hpp"
#include "stringview.hpp"
#include "strops.hpp"
@ -22,6 +24,9 @@
namespace ox {
template<typename Integer>
constexpr ox::IString<21> itoa(Integer v) noexcept;
template<std::size_t SmallStringSize_v>
class BasicString {
private:
@ -33,9 +38,6 @@ class BasicString {
constexpr explicit BasicString(std::size_t cap) noexcept;
template<size_t Sz>
constexpr BasicString(char const (&str)[Sz]) noexcept;
constexpr explicit BasicString(const char *str) noexcept;
constexpr explicit BasicString(const char8_t *str) noexcept;
@ -180,12 +182,20 @@ class BasicString {
return OxError(0);
}
constexpr Error append(ox::StringView sv) noexcept {
return append(sv.data(), sv.len());
}
[[nodiscard]]
constexpr BasicString substr(std::size_t pos) const noexcept;
[[nodiscard]]
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]]
constexpr const char *data() const noexcept {
return m_buff.data();
@ -325,17 +335,13 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
ox::Array<char, 65> str{};
ox::itoa(i, str.data());
set(str.data());
set(ox::itoa(i));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
ox::Array<char, 65> str{};
ox::itoa(i, str.data());
set(str.data());
set(ox::itoa(i));
return *this;
}
@ -364,7 +370,7 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(const char *str) noexcept {
std::size_t strLen = ox::strlen(str);
oxIgnoreError(append(str, strLen));
std::ignore = append(str, strLen);
return *this;
}
@ -381,21 +387,20 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
char str[65] = {};
ox::itoa(i, str);
return this->operator+=(str);
auto const str = ox::itoa(i);
return this->operator+=(str.c_str());
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
std::ignore = append(s.data(), strLen);
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
oxIgnoreError(append(src.c_str(), src.len()));
std::ignore = append(src.c_str(), src.len());
return *this;
}
@ -425,8 +430,7 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
char str[65] = {};
ox::itoa(i, str);
auto const str = ox::itoa(i);
return *this + str;
}
@ -511,7 +515,7 @@ constexpr char &BasicString<SmallStringSize_v>::operator[](std::size_t i) noexce
template<std::size_t SmallStringSize_v>
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>
@ -527,26 +531,12 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
std::size_t i;
for (i = 0; i < m_buff.size() && m_buff[i]; ++i);
return i + 1; // add one for null terminator
return m_buff.size();
}
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
std::size_t length = 0;
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;
return m_buff.size() - 1;
}
template<std::size_t SmallStringSize_v>
@ -591,4 +581,9 @@ constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
return alignOf<PlatSpec>(&v);
}
template<size_t sz>
struct MaybeView<ox::BasicString<sz>> {
using type = ox::StringView;
};
}

View File

@ -32,11 +32,9 @@ class StringLiteral: public detail::BaseStringView {
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView(str, len) {}
template<size_t Sz>
constexpr explicit StringLiteral(char const (&str)[Sz]) noexcept: StringLiteral(str, Sz) {
}
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) {
set(other.data(), other.len());
}

View File

@ -20,7 +20,7 @@
namespace ox {
template<std::size_t buffLen>
class BString;
class IString;
template<std::size_t buffLen>
class BasicString;
@ -41,7 +41,7 @@ class StringView: public detail::BaseStringView {
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const BString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr StringView(std::nullptr_t) noexcept {}
@ -98,11 +98,6 @@ constexpr auto toStdStringView(CRStringView sv) noexcept {
#endif
template<typename T>
struct MaybeView<T, true> {
using type = ox::StringView;
};
constexpr ox::Result<int> atoi(ox::CRStringView str) noexcept {
int total = 0;
int multiplier = 1;

View File

@ -34,7 +34,7 @@ class Integer: public Base {
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;
@ -118,10 +118,9 @@ constexpr Integer<T, Base>::Integer(const Integer<T, Base> &i) noexcept: Base(i)
}
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
constexpr auto ignore = [](Base) {};
ignore(Base::operator=(i));
Base::operator=(i);
m_i = i.m_i;
return *this;
}

View File

@ -14,56 +14,21 @@
#include "stringview.hpp"
#include "types.hpp"
#include "vector.hpp"
#include "writer.hpp"
namespace ox {
template<OxString_c Str>
[[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) {
return Str(str.data() + pos, str.len() - pos);
return {str.data() + pos, str.len() - pos};
}
return Str();
return {};
}
template<OxString_c Str>
[[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) {
return Str(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 {str.data() + start, end - start};
}
return {};
}

View File

@ -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 ABCDEFGHI == ABCDEFG" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ABCDEFGHI == ABCDEFG")
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] 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] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)

View File

@ -6,12 +6,112 @@
* 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
#include <map>
#include <ox/std/uuid.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 = {
{
"malloc",
@ -22,6 +122,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
auto a2 = static_cast<char*>(ox::heapmgr::malloc(5));
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");
ox::heapmgr::free(a1);
ox::heapmgr::free(a2);
return OxError(0);
}
},
@ -66,14 +168,14 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
}
},
{
"BString",
"IString",
[]() {
ox::BString<5> s;
s += "A";
s += "B";
s += 9;
s += "C";
oxAssert(s == "AB9C", "BString append broken");
ox::IString<5> s;
oxReturnError(s.append("A"));
oxReturnError(s.append("B"));
oxReturnError(s.append("9"));
oxReturnError(s.append("C"));
oxAssert(s == "AB9C", "IString append broken");
s = "asdf";
oxAssert(s == "asdf", "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::String("Write") != ox::StringView(""), "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);
}
},
@ -118,7 +223,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
ox::Vector<int> v;
oxAssert(v.size() == 0, "Initial Vector size not 0");
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);
oxReturnError(OxError(v.size() != size, "Vector size incorrect"));
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);
}
},
{
"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",
[] {
ox::HashMap<const char*, int> si;
ox::HashMap<ox::String, int> si;
si["asdf"] = 42;
si["aoeu"] = 100;
oxAssert(si["asdf"] == 42, "asdf != 42");
@ -146,12 +279,36 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
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",
[] {
using BA = ox::Array<char, 4>;
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>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));

View File

@ -37,7 +37,7 @@ void setLogger(Logger *logger) noexcept {
}
void send(const TraceMsg &msg) noexcept {
oxIgnoreError(logger->send(msg));
std::ignore = logger->send(msg);
}
}

View File

@ -12,7 +12,7 @@
#include <array>
#endif
#include "bstring.hpp"
#include "istring.hpp"
#include "def.hpp"
#include "fmt.hpp"
#include "hashmap.hpp"
@ -148,12 +148,12 @@ class OutStream {
m_msg.line = line;
m_msg.ch = ch;
const auto &firstSegment = fmtSegments.segments[0];
oxIgnoreError(m_msg.msg.append(firstSegment.str, firstSegment.length));
std::ignore = m_msg.msg.append(firstSegment.str, firstSegment.length);
//const detail::FmtArg elements[sizeof...(args)] = {args...};
for (size_t i = 0; auto const&e : std::initializer_list<detail::FmtArg>{elements...}) {
m_msg.msg += e.out;
const auto &s = fmtSegments.segments[i + 1];
oxIgnoreError(m_msg.msg.append(s.str, s.length));
std::ignore = m_msg.msg.append(s.str, s.length);
++i;
}
}
@ -182,7 +182,7 @@ class OutStream {
}
template<std::size_t sz>
constexpr OutStream &operator<<(const BString<sz> &v) noexcept {
constexpr OutStream &operator<<(const IString<sz> &v) noexcept {
return operator<<(v.c_str());
}

View File

@ -272,7 +272,7 @@ constexpr bool is_move_constructible_v = detail::is_move_constructible<T>(0);
template<std::size_t SmallStringSize>
class BasicString;
template<std::size_t sz>
class BString;
class IString;
class CStringView;
class StringLiteral;
class StringView;
@ -289,7 +289,7 @@ constexpr auto isOxString(const BasicString<sz>*) noexcept {
}
template<std::size_t sz>
constexpr auto isOxString(const BString<sz>*) noexcept {
constexpr auto isOxString(const IString<sz>*) noexcept {
return true;
}

View File

@ -8,7 +8,27 @@
#pragma once
#if __has_include(<utility>)
#include <utility>
#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 {
@ -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

View File

@ -8,16 +8,19 @@
#pragma once
#include "array.hpp"
#include "bstring.hpp"
#include "bit.hpp"
#include "ignore.hpp"
#include "istring.hpp"
#include "buffer.hpp"
#include "hash.hpp"
#include "random.hpp"
#include "ranges.hpp"
#include "stringview.hpp"
#include "strops.hpp"
namespace ox {
using UUIDStr = ox::BString<36>;
using UUIDStr = ox::IString<36>;
namespace detail {
@ -61,7 +64,7 @@ constexpr ox::Result<uint8_t> fromHex(ox::CRStringView v) noexcept {
return out;
}
constexpr ox::BString<2> toHex(uint8_t v) noexcept {
constexpr ox::IString<2> toHex(uint8_t v) noexcept {
constexpr ox::Array<char, 16> valMap {
'0',
'1',
@ -80,7 +83,8 @@ constexpr ox::BString<2> toHex(uint8_t v) noexcept {
'e',
'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[1] = valMap[static_cast<unsigned>(v & 0x0f)];
out[2] = 0;
@ -103,7 +107,7 @@ class UUID {
static ox::Result<UUID> generate() noexcept;
[[nodiscard]]
constexpr auto value() const noexcept {
constexpr auto const&value() const noexcept {
return m_value;
}
@ -116,8 +120,8 @@ class UUID {
return false;
} else {
constexpr uint64_t zero = 0;
return ox::memcmp(&zero, m_value.data() + 0, 8) == 0
&& ox::memcmp(&zero, m_value.data() + 8, 8) == 0;
return memcmp(&zero, m_value.data() + 0, 8) == 0
&& memcmp(&zero, m_value.data() + 8, 8) == 0;
}
}
@ -144,6 +148,14 @@ class UUID {
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]]
constexpr ox::Error toString(Writer_c auto &writer) const noexcept {
auto valueI = 0u;
@ -155,7 +167,7 @@ class UUID {
for (auto i = 0u; i < cnt; ++i) {
const auto v = value[valueI];
const auto h = detail::toHex(v);
oxIgnoreError(writer.write(h.c_str(), h.len()));
std::ignore = writer.write(h.c_str(), h.len());
++valueI;
}
};
@ -174,13 +186,32 @@ class UUID {
[[nodiscard]]
constexpr UUIDStr toString() const noexcept {
UUIDStr out;
ox::CharBuffWriter bw(out.data(), out.cap());
oxIgnoreError(toString(bw));
out[out.cap()] = 0;
std::ignore = out.resize(UUIDStr::cap());
ox::CharBuffWriter bw(out.data(), UUIDStr::cap());
std::ignore = toString(bw);
out[UUIDStr::cap()] = 0;
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>
constexpr Error model(T *io, ox::CommonPtrWith<UUID> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<UUID>());

View File

@ -30,7 +30,6 @@ struct VectorAllocator {
static_assert(alignof(AllocAlias<T>) == alignof(T));
private:
ox::Array<AllocAlias<T>, Size> m_data = {};
Allocator m_allocator;
protected:
constexpr 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 {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) {
*items = m_allocator.allocate(cap);
*items = Allocator{}.allocate(cap);
} else {
*items = reinterpret_cast<T*>(m_data.data());
}
@ -86,8 +85,10 @@ struct VectorAllocator {
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
if (std::is_constant_evaluated()) {
Allocator{}.deallocate(items, cap);
} else {
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>
struct VectorAllocator<T, Allocator, 0> {
private:
Allocator m_allocator;
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept {
*items = m_allocator.allocate(cap);
*items = Allocator{}.allocate(cap);
}
[[maybe_unused]]
@ -121,7 +120,7 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void deallocate(T *items, std::size_t cap) noexcept {
if (items) {
m_allocator.deallocate(items, cap);
Allocator{}.deallocate(items, cap);
}
}
@ -269,12 +268,12 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
}
[[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(
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>
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>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void push_back(MaybeView_t<T> const&item) noexcept(useNoexcept);
constexpr void push_back(T item) 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>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept(useNoexcept) {
for (std::size_t i = 0; i < m_size; i++) {
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
for (std::size_t i = 0; i < m_size; ++i) {
if (m_items[i] == v) {
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>
constexpr typename Vector<T, SmallVectorSize, Allocator>::template iterator<T&, T*, false>
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) {
reserveInsert(m_cap ? m_size + cnt : initialCap, pos, cnt);
if (pos < m_size) {
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
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 {
@ -549,10 +546,10 @@ Vector<T, SmallVectorSize, Allocator>::insert(
for (auto i = m_size + cnt - 1; i > pos; --i) {
std::construct_at(&m_items[i], std::move(m_items[i - cnt]));
}
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
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>
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) {
reserveInsert(m_cap ? m_cap * 2 : initialCap, pos);
if (pos < m_size) {
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
std::construct_at(&m_items[pos], val);
std::construct_at(&m_items[pos], m_items[pos]);
}
} else {
if (pos < m_size) {
for (auto i = m_size; i > pos; --i) {
std::construct_at(&m_items[i], std::move(m_items[i - 1]));
}
m_items[pos] = val;
m_items[pos] = std::move(val);
} else {
std::construct_at(&m_items[pos], val);
std::construct_at(&m_items[pos], m_items[pos]);
}
}
++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>
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) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
@ -627,15 +624,6 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexce
++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>
constexpr void Vector<T, SmallVectorSize, Allocator>::pop_back() noexcept(useNoexcept) {
--m_size;

View File

@ -222,8 +222,8 @@ int caller2() {
```
Lastly, there are a few macros available to help in passing ```ox::Error```s
back up the call stack, ```oxReturnError```, ```oxThrowError```,
```oxIgnoreError```, and ```oxRequire```.
back up the call stack, ```oxReturnError```, ```oxThrowError```, and
```oxRequire```.
```oxReturnError``` is by far the more helpful of the two.
```oxReturnError``` will return an ```ox::Error``` if it is not 0 and
@ -232,13 +232,10 @@ Because exceptions are disabled for GBA builds and thus cannot be used in the
engine, ```oxThrowError``` is only really useful at the boundary between
engine libraries and Nostalgia Studio.
```oxIgnoreError``` does what it says, it ignores the error.
Since ```ox::Error``` is always nodiscard, you must do something with them.
In extremely rare cases, you may not have anything you can do with them or you
may know the code will never fail in that particular instance.
This should be used very sparingly.
At the time of this writing, it has only been used 4 times in 20,000 lines of
code.
In rare cases, you may not have anything you can do with them or you may know
the code will never fail in that particular instance.
This should be used sparingly.
```cpp
@ -257,7 +254,7 @@ ox::Error engineCode() noexcept {
void anyCode() {
auto [val, err] = foo(1);
oxIgnoreError(err);
std::ignore = err;
doStuff(val);
}
```

View File

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

View File

@ -27,7 +27,7 @@ struct TileSheetV1 {
int rows = 1;
int columns = 1;
ox::FileAddress defaultPalette;
Palette pal;
PaletteV1 pal;
ox::Vector<uint8_t> pixels = {};
};

View File

@ -196,7 +196,7 @@ static ox::Error loadTileSheetSet(
.targetBpp = static_cast<unsigned>(set.bpp),
.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;
}
return {};
@ -215,7 +215,7 @@ ox::Error loadBgTileSheet(
.defaultPalette = {},
.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
const auto bpp = ctx.cbbData[cbb].bpp;
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
@ -267,7 +267,7 @@ ox::Error loadSpriteTileSheet(
.defaultPalette = {},
.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) {
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
}

View File

@ -28,12 +28,11 @@ void panic(const char *file, int line, const char *panicMsg, ox::Error const&err
ox::heapmgr::initHeap(HEAP_BEGIN, HEAP_END);
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();
auto ctx = init(*tctx).unwrap();
oxIgnoreError(initGfx(*ctx, {}));
oxIgnoreError(initConsole(*ctx));
std::ignore = initGfx(*ctx, {});
std::ignore = initConsole(*ctx);
setBgStatus(*ctx, 0, true);
clearBg(*ctx, 0);
ox::BString<23> serr = "Error code: ";
serr += static_cast<int64_t>(err);
auto const serr = ox::sfmt<ox::IString<23>>("Error code: {}", static_cast<int64_t>(err));
puts(*ctx, 32 + 1, 1, "SADNESS...");
puts(*ctx, 32 + 1, 4, "UNEXPECTED STATE:");
puts(*ctx, 32 + 2, 6, panicMsg);

View File

@ -58,29 +58,25 @@ static class: public keel::Module {
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
return {
// convert tilesheets to CompactTileSheets
[](keel::Context &ctx, ox::Buffer &buff) -> ox::Error {
oxRequire(hdr, keel::readAssetHeader(buff));
auto const typeId = ox::buildTypeId(
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
typeId == ox::ModelTypeId_v<TileSheetV2> ||
typeId == ox::ModelTypeId_v<TileSheetV3> ||
typeId == ox::ModelTypeId_v<TileSheetV4>) {
oxReturnError(keel::convertBuffToBuff<CompactTileSheet>(
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
return true;
}
return {};
return false;
},
[](keel::Context &ctx, ox::Buffer &buff) -> ox::Error {
oxRequire(hdr, keel::readAssetHeader(buff));
auto const typeId = ox::buildTypeId(
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
typeId == ox::ModelTypeId_v<PaletteV1>) {
oxReturnError(keel::convertBuffToBuff<Palette>(
ctx, buff, ox::ClawFormat::Metal).moveTo(buff));
return true;
}
return {};
return false;
},
};
}

View File

@ -29,11 +29,11 @@ class TileSheetV1ToTileSheetV2Converter: public keel::Converter<TileSheetV1, Til
};
class TileSheetV2ToTileSheetV3Converter: public keel::Converter<TileSheetV2, TileSheetV3> {
static void convertSubsheet(
TileSheetV2::SubSheet &src,
TileSheetV3::SubSheet &dst,
SubSheetId &idIt) noexcept;
ox::Error convert(keel::Context&, TileSheetV2 &src, TileSheetV3 &dst) const noexcept final;
static void convertSubsheet(
TileSheetV2::SubSheet &src,
TileSheetV3::SubSheet &dst,
SubSheetId &idIt) noexcept;
ox::Error convert(keel::Context&, TileSheetV2 &src, TileSheetV3 &dst) const noexcept final;
};
class TileSheetV3ToTileSheetV4Converter: public keel::Converter<TileSheetV3, TileSheetV4> {
@ -45,7 +45,7 @@ class TileSheetV3ToTileSheetV4Converter: public keel::Converter<TileSheetV3, Til
};
class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> {
ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final;
ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final;
};
}

View File

@ -68,12 +68,6 @@ void PaletteEditorImGui::drawColumn(ox::CStringView txt) noexcept {
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 {
constexpr auto tableFlags = ImGuiTableFlags_RowBg;
auto const colorsSz = ImGui::GetContentRegionAvail();

View File

@ -33,7 +33,9 @@ class PaletteEditorImGui: public studio::Editor {
private:
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;

View File

@ -19,7 +19,7 @@ void AddPageCommand::redo() noexcept {
}
void AddPageCommand::undo() noexcept {
oxIgnoreError(m_pal.pages.erase(static_cast<std::size_t>(m_pal.pages.size() - 1)));
std::ignore = m_pal.pages.erase(static_cast<std::size_t>(m_pal.pages.size() - 1));
}
@ -43,7 +43,7 @@ void DuplicatePageCommand::redo() noexcept {
void DuplicatePageCommand::undo() noexcept {
m_page = std::move(m_pal.pages[m_dstIdx]);
oxIgnoreError(m_pal.pages.erase(static_cast<std::size_t>(m_dstIdx)));
std::ignore = m_pal.pages.erase(static_cast<std::size_t>(m_dstIdx));
}
size_t DuplicatePageCommand::insertIdx() const noexcept {
@ -62,7 +62,7 @@ int RemovePageCommand::commandId() const noexcept {
void RemovePageCommand::redo() noexcept {
m_page = std::move(m_pal.pages[m_idx]);
oxIgnoreError(m_pal.pages.erase(static_cast<std::size_t>(m_idx)));
std::ignore = m_pal.pages.erase(static_cast<std::size_t>(m_idx));
}
void RemovePageCommand::undo() noexcept {
@ -86,7 +86,7 @@ void AddColorCommand::redo() noexcept {
}
void AddColorCommand::undo() noexcept {
oxIgnoreError(m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx)));
std::ignore = m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx));
}
@ -102,7 +102,7 @@ int RemoveColorCommand::commandId() const noexcept {
}
void RemoveColorCommand::redo() noexcept {
oxIgnoreError(m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx)));
std::ignore = m_pal->pages[m_page].erase(static_cast<std::size_t>(m_idx));
}
void RemoveColorCommand::undo() noexcept {
@ -171,8 +171,8 @@ void MoveColorCommand::undo() noexcept {
void MoveColorCommand::moveColor(int idx, int offset) noexcept {
const auto c = m_pal->pages[m_page][static_cast<std::size_t>(idx)];
oxIgnoreError(m_pal->pages[m_page].erase(static_cast<std::size_t>(idx)));
std::ignore = m_pal->pages[m_page].erase(static_cast<std::size_t>(idx));
m_pal->pages[m_page].insert(static_cast<std::size_t>(idx + offset), c);
}
}
}

View File

@ -11,7 +11,7 @@
namespace nostalgia::core {
class StudioModule: public studio::Module {
static class: public studio::Module {
ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept final {
return {
studio::editorMaker<TileSheetEditorImGui>(ctx, FileExt_ng),
@ -25,9 +25,8 @@ class StudioModule: public studio::Module {
out.emplace_back(ox::make<studio::ItemMakerT<core::Palette>>("Palette", "Palettes", FileExt_npal));
return out;
}
};
} mod;
static StudioModule mod;
const studio::Module *studioModule() noexcept {
return &mod;
}

View File

@ -13,7 +13,7 @@ core::PaletteChangeCommand::PaletteChangeCommand(
m_img(img),
m_idx(std::move(idx)),
m_oldPalette(m_img.defaultPalette),
m_newPalette(ox::FileAddress(ox::sfmt<ox::BString<43>>("uuid://{}", newPalette))) {
m_newPalette(ox::FileAddress(ox::sfmt<ox::IString<43>>("uuid://{}", newPalette))) {
}
void PaletteChangeCommand::redo() noexcept {

View File

@ -81,7 +81,7 @@ TileSheetEditorImGui::TileSheetEditorImGui(studio::StudioContext &sctx, ox::CRSt
m_tctx(m_sctx.tctx),
m_view(m_sctx, path, *undoStack()),
m_model(m_view.model()) {
oxIgnoreError(setPaletteSelection());
std::ignore = setPaletteSelection();
// connect signal/slots
undoStack()->changeTriggered.connect(this, &TileSheetEditorImGui::markUnsavedChanges);
m_subsheetEditor.inputSubmitted.connect(this, &TileSheetEditorImGui::updateActiveSubsheet);
@ -410,14 +410,13 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
auto const pages = m_model.pal().pages.size();
if (pages > 1) {
ImGui::Indent(20);
ox::Array<char, 10> numStr;
ox::itoa(m_model.palettePage() + 1, numStr.data());
auto numStr = ox::itoa(m_model.palettePage() + 1);
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) {
auto const selected = (m_model.palettePage() == n);
ox::itoa(n + 1, numStr.data());
if (ImGui::Selectable(numStr.data(), selected) && m_model.palettePage() != n) {
numStr = ox::itoa(n + 1);
if (ImGui::Selectable(numStr.c_str(), selected) && m_model.palettePage() != n) {
m_model.setPalettePage(n);
}
if (selected) {
@ -440,7 +439,7 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
ImGui::PushID(static_cast<int>(i));
// Column: color idx
ImGui::TableNextColumn();
auto const label = ox::BString<8>() + (i + 1);
auto const label = ox::itoa(i + 1);
auto const rowSelected = i == m_view.palIdx();
if (ImGui::Selectable(label.c_str(), rowSelected, ImGuiSelectableFlags_SpanAllColumns)) {
m_view.setPalIdx(i);

View File

@ -28,7 +28,7 @@ class TileSheetEditorImGui: public studio::Editor {
private:
class SubSheetEditor {
private:
ox::BString<100> m_name;
ox::IString<100> m_name;
int m_cols = 0;
int m_rows = 0;
bool m_show = false;

View File

@ -10,7 +10,7 @@
namespace nostalgia::scene {
class SceneModule: public keel::Module {
static class: public keel::Module {
private:
SceneDocToSceneStaticConverter m_sceneDocToSceneStaticConverter;
@ -42,9 +42,8 @@ class SceneModule: public keel::Module {
};
}
};
} mod;
static const SceneModule mod;
const keel::Module *keelModule() noexcept {
return &mod;
}

View File

@ -10,7 +10,7 @@ namespace nostalgia::scene {
constexpr ox::StringLiteral FileExt_nscn("nscn");
class StudioModule: public studio::Module {
static class: public studio::Module {
public:
ox::Vector<studio::EditorMaker> editors(studio::StudioContext &ctx) const noexcept override {
return {
@ -21,9 +21,8 @@ class StudioModule: public studio::Module {
ox::Vector<ox::UPtr<studio::ItemMaker>> out;
return out;
}
};
} mod;
static StudioModule const mod;
const studio::Module *studioModule() noexcept {
return &mod;
}

View File

@ -11,7 +11,7 @@ target_link_libraries(
target_compile_definitions(
NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="dev build"
OLYMPIC_APP_VERSION="d2024.05.0"
)
install(

View File

@ -11,9 +11,7 @@ namespace keel {
constexpr auto K1HdrSz = 40;
ox::Result<ox::UUID> readUuidHeader(ox::Buffer const&buff) noexcept;
ox::Result<ox::UUID> readUuidHeader(const char *buff, std::size_t buffLen) noexcept;
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept;
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexcept {
oxReturnError(write(writer, "K1;"));
@ -22,24 +20,24 @@ ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexce
}
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;
const auto err = readUuidHeader(buff).error;
if (!err) {
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 {
ox::UUID uuid;
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;
}

View File

@ -117,7 +117,7 @@ class AssetRef: public ox::SignalHandler {
}
if (m_ctr) {
m_ctr->decRefs();
oxIgnoreError(m_ctr->updated.disconnectObject(this));
std::ignore = m_ctr->updated.disconnectObject(this);
}
m_ctr = h.m_ctr;
if (m_ctr) {
@ -133,11 +133,11 @@ class AssetRef: public ox::SignalHandler {
}
if (m_ctr) {
m_ctr->decRefs();
oxIgnoreError(m_ctr->updated.disconnectObject(this));
std::ignore = m_ctr->updated.disconnectObject(this);
}
m_ctr = h.m_ctr;
if (m_ctr) {
oxIgnoreError(m_ctr->updated.disconnectObject(&h));
std::ignore = m_ctr->updated.disconnectObject(&h);
m_ctr->updated.connect(this, &AssetRef::emitUpdated);
}
h.m_ctr = nullptr;

View File

@ -12,7 +12,7 @@
namespace keel {
class Context;
using PackTransform = ox::Error(*)(Context&, ox::Buffer &clawData);
using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringView);
class Context {
public:
@ -36,4 +36,22 @@ class Context {
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
}
}

View File

@ -94,7 +94,7 @@ ox::Error preloadObj(
oxOutf("preloading {} as a {}\n", path, obj.type()->typeName);
// preload
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(err);
keel::PreloadPtr const p{.preloadAddr = static_cast<uint32_t>(a)};

View File

@ -40,7 +40,7 @@ class WrapInline: public Wrap {
};
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)...);
}
@ -65,9 +65,10 @@ class BaseConverter {
[[nodiscard]]
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]]
inline bool matches(
@ -84,12 +85,12 @@ class Converter: public BaseConverter {
public:
[[nodiscard]]
ox::StringView srcTypeName() const noexcept final {
return ox::requireModelTypeName<SrcType>();
return ox::ModelTypeName_v<SrcType>;
}
[[nodiscard]]
int srcTypeVersion() const noexcept final {
return ox::requireModelTypeVersion<SrcType>();
return ox::ModelTypeVersion_v<SrcType>;
}
[[nodiscard]]
@ -97,7 +98,7 @@ class Converter: public BaseConverter {
constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
return pSrcTypeName == SrcTypeName
&& pSrcTypeVersion == SrcTypeVersion;
&& pSrcTypeVersion == SrcTypeVersion;
}
[[nodiscard]]
@ -105,20 +106,22 @@ class Converter: public BaseConverter {
constexpr auto DstTypeName = ox::StringView(ox::requireModelTypeName<DstType>());
constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return dstTypeName == DstTypeName
&& 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>();
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));
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, src, wrapCast<DstType>(*dst)));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
return {std::move(dst)};
}
protected:
@ -126,9 +129,11 @@ class Converter: public BaseConverter {
};
ox::Result<ox::UniquePtr<Wrap>> convert(
keel::Context &ctx, ox::Buffer const&srcBuffer,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept;
ox::Result<ox::UPtr<Wrap>> convert(
keel::Context &ctx,
ox::Buffer const&srcBuffer,
ox::CRStringView dstTypeName,
int dstTypeVersion) noexcept;
template<typename DstType>
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>
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 DstTypeVersion = ox::requireModelTypeVersion<DstType>();
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>
auto transformRule(keel::Context &ctx, ox::Buffer &buff) noexcept -> ox::Error {
oxRequire(hdr, readAssetHeader(buff));
const auto typeId = ox::buildTypeId(
hdr.clawHdr.typeName, hdr.clawHdr.typeVersion, hdr.clawHdr.typeParams);
ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) noexcept {
if (typeId == ox::ModelTypeId_v<From>) {
oxReturnError(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
return true;
}
return {};
return false;
};

View File

@ -19,7 +19,7 @@ class TypeStore: public ox::TypeStore {
explicit TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept;
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;
};
}

Some files were not shown because too many files have changed in this diff Show More