mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Compare commits
225 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
161280ce7d | ||
|
|
4e129d4ae2 | ||
|
|
2b6f1c061d | ||
|
|
cb19c7d9e7 | ||
|
|
224b120745 | ||
|
|
534dd42472 | ||
|
|
163976f85f | ||
|
|
d79a8808d7 | ||
|
|
1cba5a0774 | ||
|
|
6c76a7ce4e | ||
|
|
084d5cbc94 | ||
|
|
32b1df0f86 | ||
|
|
50718cb905 | ||
|
|
414c0c9438 | ||
|
|
362d5680e4 | ||
|
|
fed7a74a75 | ||
|
|
d276d3767f | ||
|
|
a07660f957 | ||
|
|
4d02ce4414 | ||
|
|
c1e3cfaacc | ||
|
|
c11385cf49 | ||
|
|
0b5064683f | ||
|
|
f3ede27f60 | ||
|
|
4fbb42833e | ||
|
|
3e76b7ff1c | ||
|
|
e901a3de55 | ||
|
|
4899ee14e2 | ||
|
|
3c04a326f4 | ||
|
|
a1ff3b05ed | ||
|
|
74e228688a | ||
|
|
75d454b6a6 | ||
|
|
6cffb888ea | ||
|
|
cf03215564 | ||
|
|
5b90743120 | ||
|
|
0fb91265b6 | ||
|
|
3cb7c489ee | ||
|
|
c65c378b7f | ||
|
|
cf9784afee | ||
|
|
8bd942c1b8 | ||
|
|
109e15b5a0 | ||
|
|
0fdd6bdc81 | ||
|
|
378b35265b | ||
|
|
b5e25e3857 | ||
|
|
9b2fc04959 | ||
|
|
ce8167a102 | ||
|
|
397d065a74 | ||
|
|
5e23817a3d | ||
|
|
396263f5c3 | ||
|
|
26d0760c0d | ||
|
|
11f090116f | ||
|
|
5e1c343be4 | ||
|
|
0e69432e3d | ||
|
|
94a26d9483 | ||
|
|
efa5bdc6df | ||
|
|
459969ddb2 | ||
|
|
ae5047b73f | ||
|
|
17f3db835c | ||
|
|
1845a515ca | ||
|
|
bf50178eb3 | ||
|
|
32675161c4 | ||
|
|
e257500e03 | ||
|
|
0add42b0a0 | ||
|
|
b14053df41 | ||
|
|
6a78864b6c | ||
|
|
b1fea45cd1 | ||
|
|
cef48482f1 | ||
|
|
a126a25d66 | ||
|
|
61c939059d | ||
|
|
5fa820a462 | ||
|
|
472124dab3 | ||
|
|
1e11b6c442 | ||
|
|
34a86852c6 | ||
|
|
52afbdbde9 | ||
|
|
888657cc97 | ||
|
|
d7bfddf35e | ||
|
|
9c435352b9 | ||
|
|
3fe55b5e51 | ||
|
|
cdabe8fd9e | ||
|
|
5390ca6250 | ||
|
|
61e84e4d34 | ||
|
|
1b82b7d2f2 | ||
|
|
49f59d82c9 | ||
|
|
e84e23f7ec | ||
|
|
0b9b49673e | ||
|
|
4512c6446d | ||
|
|
0fea6c6056 | ||
|
|
dd8449576f | ||
|
|
c3b2694834 | ||
|
|
d3ebd4a130 | ||
|
|
a326e31e57 | ||
|
|
945a3f3fc0 | ||
|
|
2a8fbb8fec | ||
|
|
c0f1b02d0b | ||
|
|
f2c557c3b7 | ||
|
|
d00a93f195 | ||
|
|
aa07969fc2 | ||
|
|
6dcd91c5ef | ||
|
|
c2e603ddd8 | ||
|
|
70c4b24519 | ||
|
|
51364a9d1b | ||
|
|
d9f4eb46d9 | ||
|
|
cd2d1a04d8 | ||
|
|
3f7a547d8a | ||
|
|
f254c27966 | ||
|
|
8a1c02c840 | ||
|
|
7f297a9d27 | ||
|
|
64ef33f09b | ||
|
|
cd4c586c3f | ||
|
|
0a9d4e398d | ||
|
|
d61beef7e0 | ||
|
|
7136b05019 | ||
|
|
87fa253059 | ||
|
|
04eb6fc451 | ||
|
|
15fc435d92 | ||
|
|
9d54e9e3c4 | ||
|
|
c73c7cb2a3 | ||
|
|
827ad18ef4 | ||
|
|
3fc562af6f | ||
|
|
87c42f1cd3 | ||
|
|
e93f22fbda | ||
|
|
8fa59cbb43 | ||
|
|
527766310f | ||
|
|
a02b0a1f4c | ||
|
|
4d93db51ee | ||
|
|
fa2e6e8189 | ||
|
|
0fc1871ddf | ||
|
|
197f82d829 | ||
|
|
4ad11724d1 | ||
|
|
6d53fd6f6e | ||
|
|
db47b0555d | ||
|
|
ebd7b7243a | ||
|
|
e0771beabc | ||
|
|
824d064710 | ||
|
|
336ddb67c8 | ||
|
|
9ad98beda7 | ||
|
|
702f836b40 | ||
|
|
d820a2356a | ||
|
|
fa1951642b | ||
|
|
42dc2d541a | ||
|
|
fdbbe5c1aa | ||
|
|
292bf1cbbc | ||
|
|
82769669ec | ||
|
|
29b211eefc | ||
|
|
e4965ab408 | ||
|
|
067a4f7cb1 | ||
|
|
739e91efa4 | ||
|
|
26d733ef59 | ||
|
|
32d6025e29 | ||
|
|
04706f2dcd | ||
|
|
d8a7c57b56 | ||
|
|
ad8769580a | ||
|
|
d51dd09a1f | ||
|
|
5ed4f9519f | ||
|
|
493a084745 | ||
|
|
9bd04526e8 | ||
|
|
90f0486334 | ||
|
|
e4f1b57bd0 | ||
|
|
c949bd3108 | ||
|
|
56f8008d85 | ||
|
|
c6a96ad7f3 | ||
|
|
328e6f518c | ||
|
|
8ec4a2cada | ||
|
|
9b318ec233 | ||
|
|
d96624c578 | ||
|
|
bf1d401566 | ||
|
|
a2c886a2d9 | ||
|
|
e76278cfd7 | ||
|
|
1028f85daa | ||
|
|
e706c914a8 | ||
|
|
f3b71ed7eb | ||
|
|
18b246c577 | ||
|
|
c205719563 | ||
|
|
02a5270c5a | ||
|
|
2ba244dd9c | ||
|
|
d33d0a232b | ||
|
|
5c4197debd | ||
|
|
41261d40b2 | ||
|
|
48ecceab54 | ||
|
|
0d9547a388 | ||
|
|
d2f59c5b3f | ||
|
|
85166bc706 | ||
|
|
bf26898645 | ||
|
|
1f2bcd5462 | ||
|
|
4e6cd4283c | ||
|
|
9aec5de105 | ||
|
|
dec49b05b8 | ||
|
|
29bcd2c96e | ||
|
|
97a9cab218 | ||
|
|
436af4dbca | ||
|
|
b08a2a2c0f | ||
|
|
b43dac24c4 | ||
|
|
bae0f0f579 | ||
|
|
8055c340f6 | ||
|
|
00c1210625 | ||
|
|
070b13c81c | ||
|
|
415c9639e7 | ||
|
|
996f8a6a4d | ||
|
|
e49e3e32e7 | ||
|
|
86a05ba6c0 | ||
|
|
651735f9a0 | ||
|
|
759389066f | ||
|
|
3577a2d6b8 | ||
|
|
b63886b879 | ||
|
|
466d3bc1b6 | ||
|
|
2a2c0f5d91 | ||
|
|
0c0d0ace4d | ||
|
|
a0ab10c23e | ||
|
|
0685260454 | ||
|
|
15662bd32f | ||
|
|
475816251b | ||
|
|
bf62d11a73 | ||
|
|
37d42d555d | ||
|
|
1fc522ec9c | ||
|
|
3a8a6aa429 | ||
|
|
e15ee23925 | ||
|
|
85657c9200 | ||
|
|
3f20e5af1d | ||
|
|
18e2838772 | ||
|
|
f023db8638 | ||
|
|
cb0b94c064 | ||
|
|
7087665ccc | ||
|
|
1793dd7f0b | ||
|
|
a61fd6d280 | ||
|
|
034a048c8a | ||
|
|
608fc4df9f |
15
.clang-format
Normal file
15
.clang-format
Normal file
@@ -0,0 +1,15 @@
|
||||
IndentWidth: 4
|
||||
UseCRLF: false
|
||||
IndentCaseLabels: true
|
||||
UseTab: ForIndentation
|
||||
TabWidth: 4
|
||||
BreakBeforeBraces: Allman
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
44
.clang-tidy
44
.clang-tidy
@@ -1,21 +1,7 @@
|
||||
---
|
||||
# Configure clang-tidy for this project.
|
||||
|
||||
IndentWidth: 4
|
||||
UseCRLF: false
|
||||
IndentCaseLabels: true
|
||||
UseTab: UT_ForIndentation
|
||||
TabWidth: 4
|
||||
BreakBeforeBraces: Allman
|
||||
AllowShortBlocksOnASingleLine: SBS_Empty
|
||||
AllowShortIfStatementsOnASingleLine: SIS_WithoutElse
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeParens: SBPO_ControlStatementsExceptControlMacros
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
|
||||
# Disabled:
|
||||
# -google-readability-namespace-comments the *_CLIENT_NS is a macro, and
|
||||
@@ -40,17 +26,19 @@ Checks: >
|
||||
|
||||
# Turn all the warnings from the checks above into errors.
|
||||
WarningsAsErrors: "*"
|
||||
|
||||
CheckOptions:
|
||||
- { key: readability-function-cognitive-complexity.Threshold, value: 100 }
|
||||
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE }
|
||||
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
|
||||
- { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: k }
|
||||
- { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.GlobalConstantPrefix, value: k }
|
||||
- { key: readability-identifier-naming.StaticConstantCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.StaticConstantPrefix, value: k }
|
||||
- { key: readability-function-cognitive-complexity.Threshold, value: 100 }
|
||||
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE }
|
||||
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
|
||||
- { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: k }
|
||||
- { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.GlobalConstantPrefix, value: k }
|
||||
- { key: readability-identifier-naming.StaticConstantCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.StaticConstantPrefix, value: k }
|
||||
- { key: readability-identifier-naming.MinimumParameterNameLength, value: 0 }
|
||||
|
||||
MinimumParameterNameLength: 0
|
||||
|
||||
1231
.github/workflows/main.yml
vendored
1231
.github/workflows/main.yml
vendored
File diff suppressed because it is too large
Load Diff
6
.gitignore
vendored
6
.gitignore
vendored
@@ -73,8 +73,12 @@ out/
|
||||
/cmake-build-debug/
|
||||
/cmake-build-release/
|
||||
|
||||
# Emacs files
|
||||
# etags(Emacs), ctags, gtags
|
||||
TAGS
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
tags
|
||||
|
||||
# Clangd LSP files
|
||||
/.cache/
|
||||
|
||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
set(C3_LLVM_MIN_VERSION 17)
|
||||
set(C3_LLVM_MAX_VERSION 22)
|
||||
set(C3_LLVM_DEFAULT_VERSION 19)
|
||||
set(C3_LLVM_DEFAULT_VERSION 21)
|
||||
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
message(FATAL_ERROR "In-tree build detected, please build in a separate directory")
|
||||
@@ -56,12 +56,30 @@ set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Use /MT or /MTd
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
if(MSVC)
|
||||
message(STATUS "MSVC version ${MSVC_VERSION}")
|
||||
add_compile_options(/utf-8)
|
||||
|
||||
if(C3_WITH_LLVM)
|
||||
FetchContent_GetProperties(LLVM_Windows)
|
||||
if(NOT LLVM_Windows_URL MATCHES "msvcrt")
|
||||
set(MSVC_CRT_SUFFIX "")
|
||||
message(STATUS "Detected STATIC LLVM (libcmt)")
|
||||
else()
|
||||
set(MSVC_CRT_SUFFIX "DLL")
|
||||
message(STATUS "Detected DYNAMIC LLVM (msvcrt)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Force the Runtime to Release (/MT or /MD) even in Debug
|
||||
# This is required to match our RelWithDebInfo LLVM builds
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded${MSVC_CRT_SUFFIX}")
|
||||
set_property(GLOBAL PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded${MSVC_CRT_SUFFIX}")
|
||||
|
||||
add_compile_definitions(_ITERATOR_DEBUG_LEVEL=0)
|
||||
|
||||
# Suppresses the LNK4098 mismatch warning in Debug builds
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmtd /NODEFAULTLIB:msvcrtd")
|
||||
else()
|
||||
add_compile_options(-gdwarf-3 -fno-exceptions)
|
||||
|
||||
@@ -77,6 +95,7 @@ set(C3_USE_MIMALLOC OFF CACHE BOOL "Use built-
|
||||
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
|
||||
set(C3_USE_TB OFF CACHE BOOL "Use TB")
|
||||
set(C3_LLD_DIR "" CACHE STRING "Use custom LLD directory")
|
||||
set(C3_LLD_INCLUDE_DIR "" CACHE STRING "Use custom LLD include directory")
|
||||
set(C3_ENABLE_CLANGD_LSP OFF CACHE BOOL "Enable/Disable output of compile commands during generation")
|
||||
set(LLVM_CRT_LIBRARY_DIR "" CACHE STRING "Use custom llvm's compiler-rt directory")
|
||||
set(TCC_LIB_PATH "/usr/lib/tcc/libtcc1.a" CACHE STRING "Use custom libtcc1.a path")
|
||||
@@ -142,11 +161,11 @@ if(C3_WITH_LLVM)
|
||||
endif()
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_19_1_5/llvm-19.1.5-windows-amd64-msvc17-libcmt.7z
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_21_1_8/llvm-21.1.8-windows-amd64-msvc17-libcmt.7z
|
||||
)
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows_debug
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_19_1_5/llvm-19.1.5-windows-amd64-msvc17-libcmt-dbg.7z
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_21_1_8/llvm-21.1.8-windows-amd64-msvc17-libcmt-dbg.7z
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message("Loading Windows LLVM debug libraries, this may take a while...")
|
||||
@@ -273,7 +292,12 @@ if(C3_WITH_LLVM)
|
||||
else()
|
||||
message(STATUS "Looking for shared lld libraries in ${LLVM_LIBRARY_DIRS}")
|
||||
|
||||
find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH REQUIRED)
|
||||
#find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH REQUIRED)
|
||||
if(UNIX AND NOT WIN32)
|
||||
find_library(LLVM NAMES libLLVM.so PATHS ${LLVM_LIBRARY_DIRS} REQUIRED)
|
||||
else()
|
||||
find_library(LLVM NAMES libLLVM.a LLVM.lib PATHS ${LLVM_LIBRARY_DIRS} REQUIRED)
|
||||
endif()
|
||||
set(llvm_libs ${LLVM})
|
||||
|
||||
# These don't seem to be reliable on windows.
|
||||
@@ -435,10 +459,18 @@ if(C3_WITH_LLVM)
|
||||
target_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=1)
|
||||
add_library(c3c_wrappers STATIC wrapper/src/wrapper.cpp)
|
||||
if (MSVC)
|
||||
# Use the same detected CRT for the wrapper
|
||||
set_target_properties(c3c_wrappers PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded${MSVC_CRT_SUFFIX}")
|
||||
set_target_properties(miniz PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded${MSVC_CRT_SUFFIX}")
|
||||
|
||||
target_compile_options(c3c PRIVATE
|
||||
"$<$<CONFIG:Debug>:/EHa>"
|
||||
"$<$<CONFIG:Release>:/EHsc>")
|
||||
endif()
|
||||
|
||||
if(C3_LLD_INCLUDE_DIR)
|
||||
target_include_directories(c3c_wrappers PRIVATE ${C3_LLD_INCLUDE_DIR})
|
||||
endif()
|
||||
else()
|
||||
target_sources(c3c PRIVATE src/utils/hostinfo.c)
|
||||
target_compile_definitions(c3c PUBLIC LLVM_AVAILABLE=0)
|
||||
@@ -552,13 +584,21 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
if(C3_WITH_LLVM)
|
||||
set(clang_lib_dir ${llvm_dir}/lib/clang/${C3_LLVM_VERSION}/lib/windows)
|
||||
set(sanitizer_runtime_libraries
|
||||
${clang_lib_dir}/clang_rt.asan-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.lib
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic-x86_64.dll
|
||||
${clang_lib_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
|
||||
# The the sanitizer libs are in the folder "lib/clang/21/lib/windows/" but use the find anyway
|
||||
file(GLOB_RECURSE FOUND_ASAN_LIB "${llvm_dir}/*clang_rt.asan_dynamic-x86_64.lib")
|
||||
if(FOUND_ASAN_LIB)
|
||||
list(GET FOUND_ASAN_LIB 0 _asan_path)
|
||||
get_filename_component(_asan_dir "${_asan_path}" DIRECTORY)
|
||||
set(sanitizer_runtime_libraries
|
||||
${_asan_dir}/clang_rt.asan_dynamic-x86_64.lib
|
||||
${_asan_dir}/clang_rt.asan_dynamic-x86_64.dll
|
||||
${_asan_dir}/clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)
|
||||
message(STATUS "Found Sanitizer binaries at: ${_asan_dir}")
|
||||
else()
|
||||
message(WARNING "Could not find sanitizer runtime libraries in ${llvm_dir}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else()
|
||||
if (C3_WITH_LLVM AND NOT LLVM_ENABLE_RTTI)
|
||||
target_compile_options(c3c_wrappers PRIVATE -fno-rtti)
|
||||
@@ -572,6 +612,7 @@ else()
|
||||
-Wno-unused-function
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-parameter
|
||||
-Wno-char-subscripts
|
||||
)
|
||||
target_link_options(c3c PRIVATE -pthread)
|
||||
endif()
|
||||
|
||||
16
README.md
16
README.md
@@ -36,10 +36,10 @@ whole new language.
|
||||
|
||||
### Example code
|
||||
|
||||
The following code shows [generic modules](https://c3-lang.org/generic-programming/generics/) (more examples can be found at https://c3-lang.org/language-overview/examples/).
|
||||
The following code shows [generics](https://c3-lang.org/generic-programming/generics/) (more examples can be found at https://c3-lang.org/language-overview/examples/).
|
||||
|
||||
```cpp
|
||||
module stack {Type};
|
||||
```c3
|
||||
module stack <Type>;
|
||||
// Above: the parameterized type is applied to the entire module.
|
||||
|
||||
struct Stack
|
||||
@@ -78,7 +78,7 @@ fn bool Stack.empty(Stack* this)
|
||||
|
||||
Testing it out:
|
||||
|
||||
```cpp
|
||||
```c3
|
||||
import stack;
|
||||
|
||||
// Define our new types, the first will implicitly create
|
||||
@@ -142,7 +142,7 @@ fn void main()
|
||||
|
||||
### Current status
|
||||
|
||||
The current stable version of the compiler is **version 0.7.8**.
|
||||
The current stable version of the compiler is **version 0.7.9**.
|
||||
|
||||
The upcoming 0.7.x releases will focus on expanding the standard library,
|
||||
fixing bugs and improving compile time analysis.
|
||||
@@ -384,7 +384,7 @@ scoop install c3
|
||||
#### Getting started with a "hello world"
|
||||
|
||||
Create a `main.c3` file with:
|
||||
```c++
|
||||
```c3
|
||||
module hello_world;
|
||||
import std::io;
|
||||
|
||||
@@ -513,7 +513,7 @@ provide the link path to the LLVM CMake directories, e.g. `cmake -B build -S . -
|
||||
|
||||
*A note on compiling for Linux/Unix/MacOS: to be able to fetch vendor libraries
|
||||
libcurl is needed. The CMake script should detect it if it is available. Note that
|
||||
this functionality is non-essential and it is perfectly fine to user the compiler without it.*
|
||||
this functionality is non-essential and it is perfectly fine to use the compiler without it.*
|
||||
|
||||
#### Licensing
|
||||
|
||||
@@ -523,7 +523,7 @@ which is licensed under LGPL 3.0.
|
||||
|
||||
This means you are free to use all parts of standard library,
|
||||
tests, benchmarks, grammar, examples and so on under the MIT license, including
|
||||
using those libraries and tests if your build your own C3 compiler.
|
||||
using those libraries and tests if you build your own C3 compiler.
|
||||
|
||||
#### Editor plugins
|
||||
|
||||
|
||||
39
benchmarks/stdlib/crypto/chacha20.c3
Normal file
39
benchmarks/stdlib/crypto/chacha20.c3
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module chacha20_benchmarks;
|
||||
|
||||
import std::crypto::chacha20;
|
||||
|
||||
|
||||
fn void initialize_bench() @init
|
||||
{
|
||||
set_benchmark_warmup_iterations(3);
|
||||
set_benchmark_max_iterations(1024);
|
||||
}
|
||||
|
||||
const char[] KEY = x'98bef1469be7269837a45bfbc92a5a6ac762507cf96443bf33b96b1bd4c6f8f6';
|
||||
const char[] NONCE = x'44e792d63335abb1582e9253';
|
||||
const uint COUNTER = 42;
|
||||
|
||||
char[] one_mb @align(ulong.sizeof) = { [0..1024*1024] = 0xA5 };
|
||||
|
||||
// This doesn't test both encryption + decryption, because it's a symmetric operation that shares
|
||||
// a single common data transformation. Testing one limb is enough.
|
||||
fn void gogo_chacha20() @benchmark
|
||||
{
|
||||
chacha20::encrypt_mut(one_mb[..], KEY, NONCE, COUNTER);
|
||||
}
|
||||
|
||||
// Check what the speed of an unligned buffer looks like.
|
||||
fn void gogo_chacha20_unaligned() @benchmark => @pool()
|
||||
{
|
||||
char[] copy = mem::talloc_array(char, one_mb.len + 3);
|
||||
char[] im_off_slightly = copy[3..];
|
||||
copy[3..] = one_mb[..];
|
||||
assert((usz)im_off_slightly.ptr % usz.sizeof > 0);
|
||||
|
||||
runtime::@start_benchmark();
|
||||
chacha20::encrypt_mut(im_off_slightly, KEY, NONCE, COUNTER);
|
||||
runtime::@end_benchmark();
|
||||
}
|
||||
113
benchmarks/stdlib/crypto/crypto_shootout.c3
Normal file
113
benchmarks/stdlib/crypto/crypto_shootout.c3
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module crypto_hash_benchmarks;
|
||||
|
||||
import std::collections::pair;
|
||||
|
||||
|
||||
const usz COMMON_ITERATIONS = 1 << 17;
|
||||
|
||||
char* common_1mib_ptr;
|
||||
char[] common_16;
|
||||
char[] common_256;
|
||||
char[] common_4kib;
|
||||
char[] common_1mib;
|
||||
|
||||
fn void initialize_bench() @init
|
||||
{
|
||||
set_benchmark_warmup_iterations(3);
|
||||
set_benchmark_max_iterations(COMMON_ITERATIONS + 3);
|
||||
|
||||
common_1mib_ptr = mem::alloc_array(char, 1024*1024);
|
||||
common_1mib = common_1mib_ptr[:1024*1024];
|
||||
common_1mib[..] = 0xA5;
|
||||
|
||||
common_16 = common_1mib[:16];
|
||||
common_256 = common_1mib[:256];
|
||||
common_4kib = common_1mib[:4096];
|
||||
|
||||
static String[] function_prefixes = {
|
||||
$qnameof(md5_16)[..^4],
|
||||
$qnameof(sha1_16)[..^4],
|
||||
$qnameof(sha2_256_16)[..^4],
|
||||
$qnameof(sha2_512_16)[..^4],
|
||||
$qnameof(blake2s_256_16)[..^4],
|
||||
$qnameof(blake2b_256_16)[..^4],
|
||||
$qnameof(blake3_16)[..^4],
|
||||
$qnameof(ripemd_160_16)[..^4],
|
||||
$qnameof(whirlpool_16)[..^4],
|
||||
$qnameof(streebog_256_16)[..^4],
|
||||
$qnameof(streebog_512_16)[..^4],
|
||||
};
|
||||
|
||||
static Pair{ String, uint }[] to_iters = {
|
||||
{ "_4kib", 1 << 15 },
|
||||
{ "_1mib", 1024 },
|
||||
};
|
||||
|
||||
foreach (p : to_iters)
|
||||
{
|
||||
foreach (name : function_prefixes) set_benchmark_func_iterations(name.tconcat(p.first), p.second);
|
||||
}
|
||||
}
|
||||
|
||||
fn void teardown_bench() @finalizer
|
||||
{
|
||||
mem::free(common_1mib_ptr);
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================================
|
||||
module crypto_hash_benchmarks @benchmark;
|
||||
|
||||
import std::hash;
|
||||
|
||||
|
||||
fn void md5_16() => md5::hash(common_16);
|
||||
fn void sha1_16() => sha1::hash(common_16);
|
||||
fn void sha2_256_16() => sha256::hash(common_16);
|
||||
fn void sha2_512_16() => sha512::hash(common_16);
|
||||
fn void blake2s_256_16() => blake2::s(256, common_16);
|
||||
fn void blake2b_256_16() => blake2::b(256, common_16);
|
||||
fn void blake3_16() => blake3::hash(common_16);
|
||||
fn void ripemd_160_16() => ripemd::hash{160}(common_16);
|
||||
fn void whirlpool_16() => whirlpool::hash(common_16);
|
||||
fn void streebog_256_16() => streebog::hash_256(common_16);
|
||||
fn void streebog_512_16() => streebog::hash_512(common_16);
|
||||
|
||||
fn void md5_256() => md5::hash(common_256);
|
||||
fn void sha1_256() => sha1::hash(common_256);
|
||||
fn void sha2_256_256() => sha256::hash(common_256);
|
||||
fn void sha2_512_256() => sha512::hash(common_256);
|
||||
fn void blake2s_256_256() => blake2::s(256, common_256);
|
||||
fn void blake2b_256_256() => blake2::b(256, common_256);
|
||||
fn void blake3_256() => blake3::hash(common_256);
|
||||
fn void ripemd_160_256() => ripemd::hash{160}(common_256);
|
||||
fn void whirlpool_256() => whirlpool::hash(common_256);
|
||||
fn void streebog_256_256() => streebog::hash_256(common_256);
|
||||
fn void streebog_512_256() => streebog::hash_512(common_256);
|
||||
|
||||
fn void md5_4kib() => md5::hash(common_4kib);
|
||||
fn void sha1_4kib() => sha1::hash(common_4kib);
|
||||
fn void sha2_256_4kib() => sha256::hash(common_4kib);
|
||||
fn void sha2_512_4kib() => sha512::hash(common_4kib);
|
||||
fn void blake2s_256_4kib() => blake2::s(256, common_4kib);
|
||||
fn void blake2b_256_4kib() => blake2::b(256, common_4kib);
|
||||
fn void blake3_4kib() => blake3::hash(common_4kib);
|
||||
fn void ripemd_160_4kib() => ripemd::hash{160}(common_4kib);
|
||||
fn void whirlpool_4kib() => whirlpool::hash(common_4kib);
|
||||
fn void streebog_256_4kib() => streebog::hash_256(common_4kib);
|
||||
fn void streebog_512_4kib() => streebog::hash_512(common_4kib);
|
||||
|
||||
fn void md5_1mib() => md5::hash(common_1mib);
|
||||
fn void sha1_1mib() => sha1::hash(common_1mib);
|
||||
fn void sha2_256_1mib() => sha256::hash(common_1mib);
|
||||
fn void sha2_512_1mib() => sha512::hash(common_1mib);
|
||||
fn void blake2s_256_1mib() => blake2::s(256, common_1mib);
|
||||
fn void blake2b_256_1mib() => blake2::b(256, common_1mib);
|
||||
fn void blake3_1mib() => blake3::hash(common_1mib);
|
||||
fn void ripemd_160_1mib() => ripemd::hash{160}(common_1mib);
|
||||
fn void whirlpool_1mib() => whirlpool::hash(common_1mib);
|
||||
fn void streebog_256_1mib() => streebog::hash_256(common_1mib);
|
||||
fn void streebog_512_1mib() => streebog::hash_512(common_1mib);
|
||||
76
benchmarks/stdlib/hash/ripemd.c3
Normal file
76
benchmarks/stdlib/hash/ripemd.c3
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module ripemd_bench;
|
||||
|
||||
fn void initialize_bench() @init
|
||||
{
|
||||
set_benchmark_warmup_iterations(3);
|
||||
set_benchmark_max_iterations(256);
|
||||
|
||||
input = mem::alloc_array(char, BUFSZ);
|
||||
input[:BUFSZ] = (char[]){ [0..BUFSZ-1] = 0xA5 }[..];
|
||||
input_slice = input[:BUFSZ];
|
||||
}
|
||||
|
||||
fn void teardown_bench() @finalizer
|
||||
{
|
||||
mem::free(input);
|
||||
input = null;
|
||||
}
|
||||
|
||||
char* input;
|
||||
char[] input_slice;
|
||||
const usz BUFSZ = 1024 * 1024;
|
||||
|
||||
module ripemd_bench @benchmark;
|
||||
|
||||
import std::hash;
|
||||
|
||||
fn void ripemd_128()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = ripemd::hash{128}(input_slice);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void ripemd_160()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = ripemd::hash{160}(input_slice);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void ripemd_256()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = ripemd::hash{256}(input_slice);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void ripemd_320()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = ripemd::hash{320}(input_slice);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void compared_with_sha256()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = sha256::hash(input_slice);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void compared_with_whirlpool()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = whirlpool::hash(input_slice);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
51
benchmarks/stdlib/hash/streebog.c3
Normal file
51
benchmarks/stdlib/hash/streebog.c3
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module streebog_bench;
|
||||
|
||||
fn void initialize_bench() @init
|
||||
{
|
||||
set_benchmark_warmup_iterations(3);
|
||||
set_benchmark_max_iterations(256);
|
||||
}
|
||||
|
||||
const char[] INPUT = { [0..1024*1024] = 0xA5 };
|
||||
const char[*] EXPECTED_256 = x'694676905b7cf099755db1cc186f741f0fd1877aaaa4badcbfb305537f986971';
|
||||
const char[*] EXPECTED_512 = x'fe21d08857ea97e79035d1e5c9ba5130786e8d1875bc74d628349560d94d6bdff0b0dcd2f6347eb8b3f0239b6cca76b5028c0ff45f631fcdf77b1d551dd079f3';
|
||||
|
||||
|
||||
module streebog_bench @benchmark;
|
||||
|
||||
import std::hash;
|
||||
|
||||
fn void get_in_the_bog_256()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = streebog::hash_256(INPUT);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void get_in_the_bog_512()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = streebog::hash_512(INPUT);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void compared_with_sha256()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = sha256::hash(INPUT);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
|
||||
fn void compared_with_whirlpool()
|
||||
{
|
||||
runtime::@start_benchmark();
|
||||
char[*] myset = whirlpool::hash(INPUT);
|
||||
runtime::@end_benchmark();
|
||||
mem::zero_volatile(myset[..]);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023-2025 Eduardo José Gómez Hernández. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::atomic::types{Type};
|
||||
module std::atomic::types <Type>;
|
||||
|
||||
struct Atomic
|
||||
{
|
||||
|
||||
@@ -70,7 +70,7 @@ fn any? AnyList.last_any(&self) @inline => InterfaceList {any}.last(self);
|
||||
*>
|
||||
macro AnyList.pop(&self, $Type)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
return *anycast(self.entries[--self.size], $Type);
|
||||
}
|
||||
@@ -85,7 +85,7 @@ macro AnyList.pop(&self, $Type)
|
||||
*>
|
||||
macro AnyList.pop_first(&self, $Type)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.remove_at(0);
|
||||
return *anycast(self.entries[0], $Type);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<*
|
||||
@require SIZE > 0 : "The size of the bitset in bits must be at least 1"
|
||||
*>
|
||||
module std::collections::bitset {SIZE};
|
||||
module std::collections::bitset <SIZE>;
|
||||
|
||||
const BITS = uint.sizeof * 8;
|
||||
const SZ = (SIZE + BITS - 1) / BITS;
|
||||
@@ -172,7 +172,7 @@ fn void BitSet.set_bool(&self, usz i, bool value) @operator([]=) @inline
|
||||
<*
|
||||
@require Type.kindof == UNSIGNED_INT
|
||||
*>
|
||||
module std::collections::growablebitset{Type};
|
||||
module std::collections::growablebitset <Type>;
|
||||
import std::collections::list;
|
||||
|
||||
const BITS = Type.sizeof * 8;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<*
|
||||
@require MAX_SIZE >= 1 : `The size must be at least 1 element big.`
|
||||
*>
|
||||
module std::collections::elastic_array {Type, MAX_SIZE};
|
||||
module std::collections::elastic_array <Type, MAX_SIZE>;
|
||||
import std::io, std::math, std::collections::list_common;
|
||||
|
||||
alias ElementPredicate = fn bool(Type *type);
|
||||
@@ -46,7 +46,7 @@ fn String ElasticArray.to_tstring(&self)
|
||||
|
||||
fn void? ElasticArray.push_try(&self, Type element) @inline
|
||||
{
|
||||
if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY?;
|
||||
if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY~;
|
||||
self.entries[self.size++] = element;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ fn void ElasticArray.push(&self, Type element) @inline
|
||||
|
||||
fn Type? ElasticArray.pop(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
return self.entries[--self.size];
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fn void ElasticArray.clear(&self)
|
||||
*>
|
||||
fn Type? ElasticArray.pop_first(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.remove_at(0);
|
||||
return self.entries[0];
|
||||
}
|
||||
@@ -241,7 +241,7 @@ fn void? ElasticArray.push_front_try(&self, Type type) @inline
|
||||
*>
|
||||
fn void? ElasticArray.insert_at_try(&self, usz index, Type value)
|
||||
{
|
||||
if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY?;
|
||||
if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY~;
|
||||
self.insert_at(index, value);
|
||||
}
|
||||
|
||||
@@ -269,25 +269,25 @@ fn void ElasticArray.set_at(&self, usz index, Type type)
|
||||
|
||||
fn void? ElasticArray.remove_last(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
self.size--;
|
||||
}
|
||||
|
||||
fn void? ElasticArray.remove_first(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
self.remove_at(0);
|
||||
}
|
||||
|
||||
fn Type? ElasticArray.first(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
return self.entries[0];
|
||||
}
|
||||
|
||||
fn Type? ElasticArray.last(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
return self.entries[self.size - 1];
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ fn usz? ElasticArray.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz? ElasticArray.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
@@ -377,7 +377,7 @@ fn usz? ElasticArray.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn bool ElasticArray.equals(&self, ElasticArray other_list) @if(ELEMENT_IS_EQUATABLE)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<*
|
||||
@require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enummap"
|
||||
@require Enum.values.len > 0 : "Only non-empty enums may be used with enummap"
|
||||
*>
|
||||
module std::collections::enummap{Enum, ValueType};
|
||||
module std::collections::enummap <Enum, ValueType>;
|
||||
import std::io;
|
||||
|
||||
struct EnumMap (Printable)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<*
|
||||
@require Enum.kindof == TypeKind.ENUM : "Only enums may be used with an enumset"
|
||||
*>
|
||||
module std::collections::enumset{Enum};
|
||||
module std::collections::enumset <Enum>;
|
||||
import std::io;
|
||||
|
||||
const ENUM_COUNT @private = Enum.values.len;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<*
|
||||
@require $defined((Key){}.hash()) : `No .hash function found on the key`
|
||||
*>
|
||||
module std::collections::map{Key, Value};
|
||||
module std::collections::map <Key, Value>;
|
||||
import std::math;
|
||||
import std::io @norecurse;
|
||||
|
||||
@@ -175,13 +175,13 @@ fn usz HashMap.len(&map) @inline
|
||||
|
||||
fn Value*? HashMap.get_ref(&map, Key key)
|
||||
{
|
||||
if (!map.count) return NOT_FOUND?;
|
||||
if (!map.count) return NOT_FOUND~;
|
||||
uint hash = rehash(key.hash());
|
||||
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
|
||||
{
|
||||
if (e.hash == hash && equals(key, e.key)) return &e.value;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn Value* HashMap.get_or_create_ref(&map, Key key) @operator(&[])
|
||||
@@ -204,13 +204,13 @@ fn Value* HashMap.get_or_create_ref(&map, Key key) @operator(&[])
|
||||
|
||||
fn Entry*? HashMap.get_entry(&map, Key key)
|
||||
{
|
||||
if (!map.count) return NOT_FOUND?;
|
||||
if (!map.count) return NOT_FOUND~;
|
||||
uint hash = rehash(key.hash());
|
||||
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
|
||||
{
|
||||
if (e.hash == hash && equals(key, e.key)) return e;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -275,7 +275,7 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
|
||||
|
||||
fn void? HashMap.remove(&map, Key key) @maydiscard
|
||||
{
|
||||
if (!map.remove_entry_for_key(key)) return NOT_FOUND?;
|
||||
if (!map.remove_entry_for_key(key)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn void HashMap.clear(&map)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<*
|
||||
@require $defined((Value){}.hash()) : `No .hash function found on the value`
|
||||
*>
|
||||
module std::collections::set {Value};
|
||||
module std::collections::set <Value>;
|
||||
import std::math;
|
||||
import std::io @norecurse;
|
||||
|
||||
@@ -32,7 +32,7 @@ struct HashSet (Printable)
|
||||
float load_factor;
|
||||
}
|
||||
|
||||
fn int HashSet.len(&self) @operator(len) => (int) self.count;
|
||||
fn usz HashSet.len(&self) @operator(len) => self.count;
|
||||
|
||||
<*
|
||||
@param [&inout] allocator : "The allocator to use"
|
||||
@@ -258,7 +258,7 @@ fn bool HashSet.contains(&set, Value value)
|
||||
*>
|
||||
fn void? HashSet.remove(&set, Value value) @maydiscard
|
||||
{
|
||||
if (!set.remove_entry_for_value(value)) return NOT_FOUND?;
|
||||
if (!set.remove_entry_for_value(value)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz HashSet.remove_all(&set, Value[] values)
|
||||
@@ -634,7 +634,7 @@ fn Value? HashSetIterator.next(&self)
|
||||
}
|
||||
}
|
||||
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz HashSetIterator.len(&self) @operator(len)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<*
|
||||
@require Type.kindof == INTERFACE || Type.kindof == ANY : "The kind of an interfacelist must be an interface or `any`"
|
||||
*>
|
||||
module std::collections::interfacelist {Type};
|
||||
module std::collections::interfacelist <Type>;
|
||||
import std::io,std::math;
|
||||
|
||||
alias InterfacePredicate = fn bool(Type value);
|
||||
@@ -93,7 +93,7 @@ fn void InterfaceList.free_element(&self, Type element) @inline
|
||||
*>
|
||||
fn Type? InterfaceList.copy_pop(&self, Allocator allocator)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
return (Type)allocator::clone_any(allocator, self.entries[--self.size]);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ fn Type? InterfaceList.tcopy_pop(&self) => self.copy_pop(tmem);
|
||||
*>
|
||||
fn Type? InterfaceList.pop_retained(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
return self.entries[--self.size];
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ fn void InterfaceList.clear(&self)
|
||||
*>
|
||||
fn Type? InterfaceList.pop_first_retained(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.remove_at(0);
|
||||
return self.entries[0];
|
||||
}
|
||||
@@ -152,7 +152,7 @@ fn Type? InterfaceList.pop_first_retained(&self)
|
||||
*>
|
||||
fn Type? InterfaceList.copy_pop_first(&self, Allocator allocator)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
defer self.remove_at(0);
|
||||
return (Type)allocator::clone_any(allocator, self.entries[0]);
|
||||
@@ -276,7 +276,7 @@ fn void InterfaceList.remove_first(&self)
|
||||
*>
|
||||
fn Type? InterfaceList.first(&self) @inline
|
||||
{
|
||||
return self.size ? self.entries[0] : NO_MORE_ELEMENT?;
|
||||
return self.size ? self.entries[0] : NO_MORE_ELEMENT~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -287,7 +287,7 @@ fn Type? InterfaceList.first(&self) @inline
|
||||
*>
|
||||
fn Type? InterfaceList.last(&self) @inline
|
||||
{
|
||||
return self.size ? self.entries[self.size - 1] : NO_MORE_ELEMENT?;
|
||||
return self.size ? self.entries[self.size - 1] : NO_MORE_ELEMENT~;
|
||||
}
|
||||
|
||||
<*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::collections::blockingqueue { Value };
|
||||
module std::collections::blockingqueue <Value>;
|
||||
import std::thread, std::time;
|
||||
|
||||
|
||||
@@ -70,9 +70,9 @@ fn void LinkedBlockingQueue.free(&self)
|
||||
}
|
||||
};
|
||||
|
||||
(void)self.lock.destroy();
|
||||
(void)self.not_empty.destroy();
|
||||
(void)self.not_full.destroy();
|
||||
self.lock.destroy();
|
||||
self.not_empty.destroy();
|
||||
self.not_full.destroy();
|
||||
}
|
||||
|
||||
fn void LinkedBlockingQueue.link_entry(&self, QueueEntry* entry) @private
|
||||
@@ -126,7 +126,7 @@ fn void LinkedBlockingQueue.push(&self, Value value)
|
||||
{
|
||||
while (self.capacity > 0 && self.count >= self.capacity)
|
||||
{
|
||||
self.not_full.wait(&self.lock)!!;
|
||||
self.not_full.wait(&self.lock);
|
||||
}
|
||||
|
||||
QueueEntry* entry = allocator::new(self.allocator, QueueEntry, {
|
||||
@@ -137,7 +137,7 @@ fn void LinkedBlockingQueue.push(&self, Value value)
|
||||
self.link_entry(entry);
|
||||
|
||||
// Signal that queue is no longer empty
|
||||
self.not_empty.signal()!!;
|
||||
self.not_empty.signal();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ fn Value LinkedBlockingQueue.poll(&self)
|
||||
{
|
||||
while (self.count == 0)
|
||||
{
|
||||
self.not_empty.wait(&self.lock)!!;
|
||||
self.not_empty.wait(&self.lock);
|
||||
}
|
||||
|
||||
QueueEntry* entry = self.unlink_head();
|
||||
@@ -161,7 +161,7 @@ fn Value LinkedBlockingQueue.poll(&self)
|
||||
allocator::free(self.allocator, entry);
|
||||
if (self.capacity > 0)
|
||||
{
|
||||
self.not_full.signal()!!;
|
||||
self.not_full.signal();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
@@ -178,7 +178,7 @@ fn Value? LinkedBlockingQueue.pop(&self)
|
||||
{
|
||||
self.lock.@in_lock()
|
||||
{
|
||||
if (self.count == 0) return NO_MORE_ELEMENT?;
|
||||
if (self.count == 0) return NO_MORE_ELEMENT~;
|
||||
|
||||
QueueEntry* entry = self.unlink_head();
|
||||
Value value = entry.value;
|
||||
@@ -186,7 +186,7 @@ fn Value? LinkedBlockingQueue.pop(&self)
|
||||
|
||||
if (self.capacity > 0)
|
||||
{
|
||||
self.not_full.signal()!!;
|
||||
self.not_full.signal();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
@@ -214,7 +214,7 @@ fn Value? LinkedBlockingQueue.poll_timeout(&self, Duration timeout)
|
||||
if (end <= time::now()) break;
|
||||
if (catch self.not_empty.wait_until(&self.lock, end)) break;
|
||||
}
|
||||
if (!self.count) return NO_MORE_ELEMENT?;
|
||||
if (!self.count) return NO_MORE_ELEMENT~;
|
||||
}
|
||||
|
||||
QueueEntry* entry = self.unlink_head();
|
||||
@@ -224,7 +224,7 @@ fn Value? LinkedBlockingQueue.poll_timeout(&self, Duration timeout)
|
||||
// Must signal not_full after removing an item
|
||||
if (self.capacity > 0)
|
||||
{
|
||||
self.not_full.signal()!!;
|
||||
self.not_full.signal();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
@@ -266,7 +266,7 @@ fn void? LinkedBlockingQueue.try_push(&self, Value value)
|
||||
{
|
||||
self.lock.@in_lock()
|
||||
{
|
||||
if (self.capacity > 0 && self.count >= self.capacity) return CAPACITY_EXCEEDED?;
|
||||
if (self.capacity > 0 && self.count >= self.capacity) return CAPACITY_EXCEEDED~;
|
||||
|
||||
QueueEntry* entry = allocator::new(self.allocator, QueueEntry, {
|
||||
.value = value,
|
||||
@@ -274,7 +274,7 @@ fn void? LinkedBlockingQueue.try_push(&self, Value value)
|
||||
.prev = null
|
||||
});
|
||||
self.link_entry(entry);
|
||||
self.not_empty.signal()!!;
|
||||
self.not_empty.signal();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ fn void? LinkedBlockingQueue.push_timeout(&self, Value value, Duration timeout)
|
||||
if (end <= time::now()) break;
|
||||
if (catch self.not_empty.wait_until(&self.lock, end)) break;
|
||||
}
|
||||
if (self.capacity > 0 && self.count >= self.capacity) return CAPACITY_EXCEEDED?;
|
||||
if (self.capacity > 0 && self.count >= self.capacity) return CAPACITY_EXCEEDED~;
|
||||
}
|
||||
|
||||
QueueEntry* entry = allocator::new(self.allocator, QueueEntry, {
|
||||
@@ -308,19 +308,19 @@ fn void? LinkedBlockingQueue.push_timeout(&self, Value value, Duration timeout)
|
||||
.prev = null
|
||||
});
|
||||
self.link_entry(entry);
|
||||
self.not_empty.signal()!!;
|
||||
self.not_empty.signal();
|
||||
};
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.is_initialized() : "Queue must be initialized"
|
||||
@return "The head value or NO_MORE_ELEMENT? if queue is empty"
|
||||
@return "The head value or NO_MORE_ELEMENT~ if queue is empty"
|
||||
*>
|
||||
fn Value? LinkedBlockingQueue.peek(&self)
|
||||
{
|
||||
self.lock.@in_lock()
|
||||
{
|
||||
return (self.head != null) ? self.head.value : NO_MORE_ELEMENT?;
|
||||
return (self.head != null) ? self.head.value : NO_MORE_ELEMENT~;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<*
|
||||
@require $defined((Key){}.hash()) : `No .hash function found on the key`
|
||||
*>
|
||||
module std::collections::map{Key, Value};
|
||||
module std::collections::map <Key, Value>;
|
||||
import std::math;
|
||||
import std::io @norecurse;
|
||||
|
||||
@@ -172,24 +172,24 @@ fn usz LinkedHashMap.len(&map) @inline => map.count;
|
||||
|
||||
fn Value*? LinkedHashMap.get_ref(&map, Key key)
|
||||
{
|
||||
if (!map.count) return NOT_FOUND?;
|
||||
if (!map.count) return NOT_FOUND~;
|
||||
uint hash = rehash(key.hash());
|
||||
for (LinkedEntry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
|
||||
{
|
||||
if (e.hash == hash && equals(key, e.key)) return &e.value;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn LinkedEntry*? LinkedHashMap.get_entry(&map, Key key)
|
||||
{
|
||||
if (!map.count) return NOT_FOUND?;
|
||||
if (!map.count) return NOT_FOUND~;
|
||||
uint hash = rehash(key.hash());
|
||||
for (LinkedEntry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
|
||||
{
|
||||
if (e.hash == hash && equals(key, e.key)) return e;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -248,7 +248,7 @@ fn bool LinkedHashMap.set(&map, Key key, Value value) @operator([]=)
|
||||
|
||||
fn void? LinkedHashMap.remove(&map, Key key) @maydiscard
|
||||
{
|
||||
if (!map.remove_entry_for_key(key)) return NOT_FOUND?;
|
||||
if (!map.remove_entry_for_key(key)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn void LinkedHashMap.clear(&map)
|
||||
@@ -375,17 +375,17 @@ fn bool LinkedHashMapIterator.next(&self)
|
||||
|
||||
fn LinkedEntry*? LinkedHashMapIterator.get(&self)
|
||||
{
|
||||
return self.current ? self.current : NOT_FOUND?;
|
||||
return self.current ? self.current : NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn Value*? LinkedHashMapValueIterator.get(&self)
|
||||
{
|
||||
return self.current ? &self.current.value : NOT_FOUND?;
|
||||
return self.current ? &self.current.value : NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn Key*? LinkedHashMapKeyIterator.get(&self)
|
||||
{
|
||||
return self.current ? &self.current.key : NOT_FOUND?;
|
||||
return self.current ? &self.current.key : NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn bool LinkedHashMapIterator.has_next(&self)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<*
|
||||
@require $defined((Value){}.hash()) : `No .hash function found on the value`
|
||||
*>
|
||||
module std::collections::set {Value};
|
||||
module std::collections::set <Value>;
|
||||
import std::math;
|
||||
import std::io @norecurse;
|
||||
|
||||
@@ -34,7 +34,7 @@ struct LinkedHashSet (Printable)
|
||||
LinkedEntry* tail;
|
||||
}
|
||||
|
||||
fn int LinkedHashSet.len(&self) @operator(len) => (int) self.count;
|
||||
fn usz LinkedHashSet.len(&self) @operator(len) => self.count;
|
||||
|
||||
<*
|
||||
@param [&inout] allocator : "The allocator to use"
|
||||
@@ -266,7 +266,7 @@ fn bool LinkedHashSet.contains(&set, Value value)
|
||||
*>
|
||||
fn void? LinkedHashSet.remove(&set, Value value) @maydiscard
|
||||
{
|
||||
if (!set.remove_entry_for_value(value)) return NOT_FOUND?;
|
||||
if (!set.remove_entry_for_value(value)) return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz LinkedHashSet.remove_all(&set, Value[] values)
|
||||
@@ -713,7 +713,7 @@ fn bool LinkedHashSetIterator.next(&self)
|
||||
|
||||
fn Value*? LinkedHashSetIterator.get(&self)
|
||||
{
|
||||
return self.current ? &self.current.value : NOT_FOUND?;
|
||||
return self.current ? &self.current.value : NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn bool LinkedHashSetIterator.has_next(&self)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::linkedlist{Type};
|
||||
module std::collections::linkedlist <Type>;
|
||||
import std::io;
|
||||
|
||||
const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type);
|
||||
@@ -24,9 +24,9 @@ struct LinkedList
|
||||
fn usz? LinkedList.to_format(&self, Formatter* f) @dynamic
|
||||
{
|
||||
usz len = f.print("{ ")!;
|
||||
for (Node* node = self._first; node != null; node.next)
|
||||
for (Node* node = self._first; node != null; node = node.next)
|
||||
{
|
||||
len += f.printf(node.next ? "%s, " : "s", node.value)!;
|
||||
len += f.printf(node.next ? "%s, " : "%s", node.value)!;
|
||||
}
|
||||
return len + f.print(" }");
|
||||
}
|
||||
@@ -124,13 +124,13 @@ fn Type? LinkedList.peek_last(&self) => self.last() @inline;
|
||||
|
||||
fn Type? LinkedList.first(&self)
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT?;
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
return self._first.value;
|
||||
}
|
||||
|
||||
fn Type? LinkedList.last(&self)
|
||||
{
|
||||
if (!self._last) return NO_MORE_ELEMENT?;
|
||||
if (!self._last) return NO_MORE_ELEMENT~;
|
||||
return self._last.value;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ fn usz? LinkedList.index_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
if (node.value == t) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz? LinkedList.rindex_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
@@ -208,7 +208,7 @@ fn usz? LinkedList.rindex_of(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
if (node.value == t) return i;
|
||||
if (i == 0) break;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
|
||||
|
||||
fn Type? LinkedList.pop(&self)
|
||||
{
|
||||
if (!self._last) return NO_MORE_ELEMENT?;
|
||||
if (!self._last) return NO_MORE_ELEMENT~;
|
||||
defer self.unlink_last();
|
||||
return self._last.value;
|
||||
}
|
||||
@@ -308,20 +308,20 @@ fn bool LinkedList.is_empty(&self)
|
||||
|
||||
fn Type? LinkedList.pop_front(&self)
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT?;
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
defer self.unlink_first();
|
||||
return self._first.value;
|
||||
}
|
||||
|
||||
fn void? LinkedList.remove_last(&self) @maydiscard
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT?;
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
self.unlink_last();
|
||||
}
|
||||
|
||||
fn void? LinkedList.remove_first(&self) @maydiscard
|
||||
{
|
||||
if (!self._first) return NO_MORE_ELEMENT?;
|
||||
if (!self._first) return NO_MORE_ELEMENT~;
|
||||
self.unlink_first();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::list{Type};
|
||||
module std::collections::list <Type>;
|
||||
import std::io, std::math, std::collections::list_common;
|
||||
|
||||
alias ElementPredicate = fn bool(Type *type);
|
||||
@@ -115,7 +115,7 @@ fn void List.push(&self, Type element) @inline
|
||||
|
||||
fn Type? List.pop(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.set_size(self.size - 1);
|
||||
return self.entries[self.size - 1];
|
||||
}
|
||||
@@ -127,7 +127,7 @@ fn void List.clear(&self)
|
||||
|
||||
fn Type? List.pop_first(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
defer self.remove_at(0);
|
||||
return self.entries[0];
|
||||
}
|
||||
@@ -250,25 +250,25 @@ fn void List.set_at(&self, usz index, Type type)
|
||||
|
||||
fn void? List.remove_last(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
self.set_size(self.size - 1);
|
||||
}
|
||||
|
||||
fn void? List.remove_first(&self) @maydiscard
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
self.remove_at(0);
|
||||
}
|
||||
|
||||
fn Type? List.first(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
return self.entries[0];
|
||||
}
|
||||
|
||||
fn Type? List.last(&self)
|
||||
{
|
||||
if (!self.size) return NO_MORE_ELEMENT?;
|
||||
if (!self.size) return NO_MORE_ELEMENT~;
|
||||
return self.entries[self.size - 1];
|
||||
}
|
||||
|
||||
@@ -461,22 +461,22 @@ macro void List.post_alloc(&self) @private
|
||||
// Functions for equatable types
|
||||
|
||||
|
||||
fn usz? List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
fn usz? List.index_of(&self, Type type) @if (ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz? List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
fn usz? List.rindex_of(&self, Type type) @if (ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach_r (i, v : self)
|
||||
{
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::collections::maybe{Type};
|
||||
module std::collections::maybe <Type>;
|
||||
import std::io;
|
||||
|
||||
struct Maybe (Printable)
|
||||
@@ -32,7 +32,7 @@ const Maybe EMPTY = { };
|
||||
|
||||
macro Type? Maybe.get(self)
|
||||
{
|
||||
return self.has_value ? self.value : NOT_FOUND?;
|
||||
return self.has_value ? self.value : NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn bool Maybe.equals(self, Maybe other) @operator(==) @if(types::is_equatable_type(Type))
|
||||
|
||||
@@ -242,8 +242,7 @@ macro Object* Object.push(&self, value)
|
||||
<*
|
||||
@require self.is_keyable()
|
||||
*>
|
||||
fn Object*? Object.get(&self, String key) => self.is_empty() ? NOT_FOUND? : self.map.get(key);
|
||||
|
||||
fn Object*? Object.get(&self, String key) => self.is_empty() ? NOT_FOUND~ : self.map.get(key);
|
||||
|
||||
fn bool Object.has_key(&self, String key) => self.is_map() && self.map.has_key(key);
|
||||
|
||||
@@ -308,7 +307,7 @@ macro get_integer_value(Object* value, $Type)
|
||||
return ($Type)value.s.to_uint128();
|
||||
$endif
|
||||
}
|
||||
if (!value.is_int()) return string::MALFORMED_INTEGER?;
|
||||
if (!value.is_int()) return string::MALFORMED_INTEGER~;
|
||||
return ($Type)value.i;
|
||||
}
|
||||
|
||||
@@ -361,7 +360,7 @@ fn uint128? Object.get_uint128_at(&self, usz index) => self.get_integer_at(uint1
|
||||
fn String? Object.get_string(&self, String key)
|
||||
{
|
||||
Object* value = self.get(key)!;
|
||||
if (!value.is_string()) return TYPE_MISMATCH?;
|
||||
if (!value.is_string()) return TYPE_MISMATCH~;
|
||||
return value.s;
|
||||
}
|
||||
|
||||
@@ -371,7 +370,7 @@ fn String? Object.get_string(&self, String key)
|
||||
fn String? Object.get_string_at(&self, usz index)
|
||||
{
|
||||
Object* value = self.get_at(index);
|
||||
if (!value.is_string()) return TYPE_MISMATCH?;
|
||||
if (!value.is_string()) return TYPE_MISMATCH~;
|
||||
return value.s;
|
||||
}
|
||||
|
||||
@@ -381,7 +380,7 @@ fn String? Object.get_string_at(&self, usz index)
|
||||
macro String? Object.get_enum(&self, $EnumType, String key)
|
||||
{
|
||||
Object value = self.get(key)!;
|
||||
if ($EnumType.typeid != value.type) return TYPE_MISMATCH?;
|
||||
if ($EnumType.typeid != value.type) return TYPE_MISMATCH~;
|
||||
return ($EnumType)value.i;
|
||||
}
|
||||
|
||||
@@ -391,7 +390,7 @@ macro String? Object.get_enum(&self, $EnumType, String key)
|
||||
macro String? Object.get_enum_at(&self, $EnumType, usz index)
|
||||
{
|
||||
Object value = self.get_at(index);
|
||||
if ($EnumType.typeid != value.type) return TYPE_MISMATCH?;
|
||||
if ($EnumType.typeid != value.type) return TYPE_MISMATCH~;
|
||||
return ($EnumType)value.i;
|
||||
}
|
||||
|
||||
@@ -401,7 +400,7 @@ macro String? Object.get_enum_at(&self, $EnumType, usz index)
|
||||
fn bool? Object.get_bool(&self, String key)
|
||||
{
|
||||
Object* value = self.get(key)!;
|
||||
if (!value.is_bool()) return TYPE_MISMATCH?;
|
||||
if (!value.is_bool()) return TYPE_MISMATCH~;
|
||||
return value.b;
|
||||
}
|
||||
|
||||
@@ -412,7 +411,7 @@ fn bool? Object.get_bool(&self, String key)
|
||||
fn bool? Object.get_bool_at(&self, usz index)
|
||||
{
|
||||
Object* value = self.get_at(index);
|
||||
if (!value.is_bool()) return TYPE_MISMATCH?;
|
||||
if (!value.is_bool()) return TYPE_MISMATCH~;
|
||||
return value.b;
|
||||
}
|
||||
|
||||
@@ -431,7 +430,7 @@ fn double? Object.get_float(&self, String key)
|
||||
case FLOAT:
|
||||
return value.f;
|
||||
default:
|
||||
return TYPE_MISMATCH?;
|
||||
return TYPE_MISMATCH~;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +449,7 @@ fn double? Object.get_float_at(&self, usz index)
|
||||
case FLOAT:
|
||||
return value.f;
|
||||
default:
|
||||
return TYPE_MISMATCH?;
|
||||
return TYPE_MISMATCH~;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,13 @@
|
||||
// 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.
|
||||
module std::collections::priorityqueue{Type};
|
||||
import std::collections::priorityqueue::private;
|
||||
|
||||
typedef PriorityQueue = inline PrivatePriorityQueue{Type, false};
|
||||
typedef PriorityQueueMax = inline PrivatePriorityQueue{Type, true};
|
||||
|
||||
module std::collections::priorityqueue::private{Type, MAX};
|
||||
module std::collections::priorityqueue;
|
||||
import std::collections::list, std::io;
|
||||
|
||||
struct PrivatePriorityQueue (Printable)
|
||||
typedef PriorityQueue <Type> = inline PrivatePriorityQueue{Type, false};
|
||||
typedef PriorityQueueMax <Type> = inline PrivatePriorityQueue{Type, true};
|
||||
|
||||
struct PrivatePriorityQueue (Printable) <Type, MAX>
|
||||
{
|
||||
List{Type} heap;
|
||||
}
|
||||
@@ -86,7 +83,7 @@ fn Type? PrivatePriorityQueue.pop(&self)
|
||||
{
|
||||
usz i = 0;
|
||||
usz len = self.heap.len();
|
||||
if (!len) return NO_MORE_ELEMENT?;
|
||||
if (!len) return NO_MORE_ELEMENT~;
|
||||
usz new_count = len - 1;
|
||||
self.heap.swap(0, new_count);
|
||||
while OUTER: ((2 * i + 1) < new_count)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<*
|
||||
@require Type.is_ordered : "The type must be ordered"
|
||||
*>
|
||||
module std::collections::range{Type};
|
||||
module std::collections::range <Type>;
|
||||
import std::io;
|
||||
|
||||
struct Range (Printable)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<*
|
||||
@require Type.kindof == ARRAY : "Required an array type"
|
||||
*>
|
||||
module std::collections::ringbuffer{Type};
|
||||
module std::collections::ringbuffer <Type>;
|
||||
import std::io;
|
||||
|
||||
alias Element = $typeof((Type){}[0]);
|
||||
@@ -48,7 +48,7 @@ fn Element? RingBuffer.pop(&self)
|
||||
switch
|
||||
{
|
||||
case self.written == 0:
|
||||
return NO_MORE_ELEMENT?;
|
||||
return NO_MORE_ELEMENT~;
|
||||
case self.written < self.buf.len:
|
||||
self.written--;
|
||||
return self.buf[self.written];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::collections::pair{Type1, Type2};
|
||||
module std::collections::pair <Type1, Type2>;
|
||||
import std::io;
|
||||
|
||||
struct Pair (Printable)
|
||||
@@ -29,9 +29,7 @@ fn bool Pair.equal(self, Pair other) @operator(==) @if (types::has_equals(Type1)
|
||||
return self.first == other.first && self.second == other.second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module std::collections::triple{Type1, Type2, Type3};
|
||||
module std::collections::triple <Type1, Type2, Type3>;
|
||||
import std::io;
|
||||
|
||||
struct Triple (Printable)
|
||||
@@ -65,11 +63,10 @@ fn bool Triple.equal(self, Triple other) @operator(==) @if (types::has_equals(Ty
|
||||
return self.first == other.first && self.second == other.second && self.third == other.third;
|
||||
}
|
||||
|
||||
|
||||
module std::collections::tuple{Type1, Type2};
|
||||
module std::collections::tuple <Type1, Type2>;
|
||||
|
||||
struct Tuple @deprecated("Use 'Pair' instead")
|
||||
{
|
||||
Type1 first;
|
||||
Type2 second;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ fn usz? write(String filename, char[] input, QOIDesc* desc) => @pool()
|
||||
fn char[]? read(Allocator allocator, String filename, QOIDesc* desc, QOIChannels channels = AUTO) => @pool()
|
||||
{
|
||||
// read file
|
||||
char[] data = file::load_temp(filename) ?? FILE_OPEN_FAILED?!;
|
||||
char[] data = file::load_temp(filename) ?? FILE_OPEN_FAILED~!;
|
||||
// pass data to decode function
|
||||
return decode(allocator, data, desc, channels);
|
||||
}
|
||||
@@ -128,14 +128,14 @@ import std::bits;
|
||||
fn char[]? encode(Allocator allocator, char[] input, QOIDesc* desc) @nodiscard
|
||||
{
|
||||
// check info in desc
|
||||
if (desc.width == 0 || desc.height == 0) return INVALID_PARAMETERS?;
|
||||
if (desc.channels == AUTO) return INVALID_PARAMETERS?;
|
||||
if (desc.width == 0 || desc.height == 0) return INVALID_PARAMETERS~;
|
||||
if (desc.channels == AUTO) return INVALID_PARAMETERS~;
|
||||
uint pixels = desc.width * desc.height;
|
||||
if (pixels > PIXELS_MAX) return TOO_MANY_PIXELS?;
|
||||
if (pixels > PIXELS_MAX) return TOO_MANY_PIXELS~;
|
||||
|
||||
// check input data size
|
||||
uint image_size = pixels * desc.channels;
|
||||
if (image_size != input.len) return INVALID_DATA?;
|
||||
if (image_size != input.len) return INVALID_DATA~;
|
||||
|
||||
// allocate memory for encoded data (output)
|
||||
// header + chunk tag and RGB(A) data for each pixel + end of stream
|
||||
@@ -283,27 +283,27 @@ fn char[]? encode(Allocator allocator, char[] input, QOIDesc* desc) @nodiscard
|
||||
fn char[]? decode(Allocator allocator, char[] data, QOIDesc* desc, QOIChannels channels = AUTO) @nodiscard
|
||||
{
|
||||
// check input data
|
||||
if (data.len < Header.sizeof + END_OF_STREAM.len) return INVALID_DATA?;
|
||||
if (data.len < Header.sizeof + END_OF_STREAM.len) return INVALID_DATA~;
|
||||
|
||||
// get header
|
||||
Header* header = (Header*)data.ptr;
|
||||
|
||||
// check magic bytes (FourCC)
|
||||
if (bswap(header.be_magic) != 'qoif') return INVALID_DATA?;
|
||||
if (bswap(header.be_magic) != 'qoif') return INVALID_DATA~;
|
||||
|
||||
// copy header data to desc
|
||||
desc.width = bswap(header.be_width);
|
||||
desc.height = bswap(header.be_height);
|
||||
desc.channels = header.channels;
|
||||
uint width = desc.width = bswap(header.be_width);
|
||||
uint height = desc.height = bswap(header.be_height);
|
||||
QOIChannels desc_channels = desc.channels = header.channels;
|
||||
desc.colorspace = header.colorspace;
|
||||
if (desc.channels == AUTO) return INVALID_DATA?; // Channels must be specified in the header
|
||||
if (desc_channels == AUTO) return INVALID_DATA~; // Channels must be specified in the header
|
||||
|
||||
// check width and height
|
||||
if (desc.width == 0 || desc.height == 0) return INVALID_DATA?;
|
||||
if (width == 0 || height == 0) return INVALID_DATA~;
|
||||
|
||||
// check pixel count
|
||||
ulong pixels = (ulong)desc.width * (ulong)desc.height;
|
||||
if (pixels > PIXELS_MAX) return TOO_MANY_PIXELS?;
|
||||
ulong pixels = (ulong)width * (ulong)height;
|
||||
if (pixels > PIXELS_MAX) return TOO_MANY_PIXELS~;
|
||||
|
||||
uint pos = Header.sizeof; // Current position in data
|
||||
uint loc; // Current position in image (top-left corner)
|
||||
@@ -313,7 +313,7 @@ fn char[]? decode(Allocator allocator, char[] data, QOIDesc* desc, QOIChannels c
|
||||
Pixel[64] palette; // Zero-initialized by default
|
||||
Pixel p = { 0, 0, 0, 255 };
|
||||
|
||||
if (channels == AUTO) channels = desc.channels;
|
||||
if (channels == AUTO) channels = desc_channels;
|
||||
|
||||
// allocate memory for image data
|
||||
usz image_size = (usz)pixels * channels;
|
||||
|
||||
@@ -90,12 +90,12 @@ fn void*? ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz a
|
||||
{
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
usz total_len = self.data.len;
|
||||
if (size > total_len) return mem::INVALID_ALLOC_SIZE?;
|
||||
if (size > total_len) return mem::INVALID_ALLOC_SIZE~;
|
||||
void* start_mem = self.data.ptr;
|
||||
void* unaligned_pointer_to_offset = start_mem + self.used + ArenaAllocatorHeader.sizeof;
|
||||
void* mem = mem::aligned_pointer(unaligned_pointer_to_offset, alignment);
|
||||
usz end = (usz)(mem - self.data.ptr) + size;
|
||||
if (end > total_len) return mem::OUT_OF_MEMORY?;
|
||||
if (end > total_len) return mem::OUT_OF_MEMORY~;
|
||||
self.used = end;
|
||||
ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof;
|
||||
header.size = size;
|
||||
@@ -117,7 +117,7 @@ fn void*? ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignmen
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
assert(old_pointer >= self.data.ptr, "Pointer originates from a different allocator.");
|
||||
usz total_len = self.data.len;
|
||||
if (size > total_len) return mem::INVALID_ALLOC_SIZE?;
|
||||
if (size > total_len) return mem::INVALID_ALLOC_SIZE~;
|
||||
ArenaAllocatorHeader* header = old_pointer - ArenaAllocatorHeader.sizeof;
|
||||
usz old_size = header.size;
|
||||
// Do last allocation and alignment match?
|
||||
@@ -130,7 +130,7 @@ fn void*? ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignmen
|
||||
else
|
||||
{
|
||||
usz new_used = self.used + size - old_size;
|
||||
if (new_used > total_len) return mem::OUT_OF_MEMORY?;
|
||||
if (new_used > total_len) return mem::OUT_OF_MEMORY~;
|
||||
self.used = new_used;
|
||||
}
|
||||
header.size = size;
|
||||
|
||||
@@ -153,7 +153,7 @@ fn void*? DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca
|
||||
if (catch err = page)
|
||||
{
|
||||
allocator::free(self.backing_allocator, mem);
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
page.memory = mem;
|
||||
void* mem_start = mem::aligned_pointer(mem + DynamicArenaChunk.sizeof, alignment);
|
||||
|
||||
@@ -23,22 +23,22 @@ fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
|
||||
void* data @noinit;
|
||||
if (alignment > mem::DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
if (posix::posix_memalign(&data, alignment, bytes)) return mem::OUT_OF_MEMORY?;
|
||||
if (posix::posix_memalign(&data, alignment, bytes)) return mem::OUT_OF_MEMORY~;
|
||||
mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
}
|
||||
return libc::calloc(1, bytes) ?: mem::OUT_OF_MEMORY?;
|
||||
return libc::calloc(1, bytes) ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* data @noinit;
|
||||
if (alignment > mem::DEFAULT_MEM_ALIGNMENT)
|
||||
{
|
||||
if (posix::posix_memalign(&data, alignment, bytes)) return mem::OUT_OF_MEMORY?;
|
||||
if (posix::posix_memalign(&data, alignment, bytes)) return mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(data = libc::malloc(bytes))) return mem::OUT_OF_MEMORY?;
|
||||
if (!(data = libc::malloc(bytes))) return mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
$if env::TESTING:
|
||||
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
|
||||
@@ -49,9 +49,9 @@ fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
|
||||
|
||||
fn void*? LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
|
||||
{
|
||||
if (alignment <= mem::DEFAULT_MEM_ALIGNMENT) return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY?;
|
||||
if (alignment <= mem::DEFAULT_MEM_ALIGNMENT) return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY~;
|
||||
void* new_ptr;
|
||||
if (posix::posix_memalign(&new_ptr, alignment, new_bytes)) return mem::OUT_OF_MEMORY?;
|
||||
if (posix::posix_memalign(&new_ptr, alignment, new_bytes)) return mem::OUT_OF_MEMORY~;
|
||||
|
||||
$switch:
|
||||
$case env::DARWIN:
|
||||
@@ -83,12 +83,12 @@ fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
|
||||
{
|
||||
if (alignment > 0)
|
||||
{
|
||||
return win32::_aligned_recalloc(null, 1, bytes, alignment) ?: mem::OUT_OF_MEMORY?;
|
||||
return win32::_aligned_recalloc(null, 1, bytes, alignment) ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
return libc::calloc(1, bytes) ?: mem::OUT_OF_MEMORY?;
|
||||
return libc::calloc(1, bytes) ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
void* data = alignment > 0 ? win32::_aligned_malloc(bytes, alignment) : libc::malloc(bytes);
|
||||
if (!data) return mem::OUT_OF_MEMORY?;
|
||||
if (!data) return mem::OUT_OF_MEMORY~;
|
||||
$if env::TESTING:
|
||||
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
|
||||
$endif
|
||||
@@ -99,9 +99,9 @@ fn void*? LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignmen
|
||||
{
|
||||
if (alignment)
|
||||
{
|
||||
return win32::_aligned_realloc(old_ptr, new_bytes, alignment) ?: mem::OUT_OF_MEMORY?;
|
||||
return win32::_aligned_realloc(old_ptr, new_bytes, alignment) ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY?;
|
||||
return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
|
||||
fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
|
||||
@@ -122,12 +122,12 @@ fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
|
||||
if (init_type == ZERO)
|
||||
{
|
||||
void* data = alignment ? @aligned_alloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment)!! : libc::calloc(bytes, 1);
|
||||
return data ?: mem::OUT_OF_MEMORY?;
|
||||
return data ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* data = alignment ? @aligned_alloc(libc::malloc, bytes, alignment)!! : libc::malloc(bytes);
|
||||
if (!data) return mem::OUT_OF_MEMORY?;
|
||||
if (!data) return mem::OUT_OF_MEMORY~;
|
||||
$if env::TESTING:
|
||||
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
|
||||
$endif
|
||||
@@ -141,9 +141,9 @@ fn void*? LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignmen
|
||||
if (alignment)
|
||||
{
|
||||
void* data = @aligned_realloc(fn void*(usz bytes) => libc::malloc(bytes), libc::free, old_ptr, new_bytes, alignment)!!;
|
||||
return data ?: mem::OUT_OF_MEMORY?;
|
||||
return data ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY?;
|
||||
return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ struct TrackingAllocator (Allocator)
|
||||
AllocMap map;
|
||||
usz mem_total;
|
||||
usz allocs_total;
|
||||
usz usage;
|
||||
usz max_usage;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -70,6 +72,11 @@ fn usz TrackingAllocator.total_allocated(&self) => self.mem_total;
|
||||
*>
|
||||
fn usz TrackingAllocator.total_allocation_count(&self) => self.allocs_total;
|
||||
|
||||
<*
|
||||
@return "the maximum amount of memory allocated"
|
||||
*>
|
||||
fn usz TrackingAllocator.max_allocated(&self) => self.max_usage;
|
||||
|
||||
fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator)
|
||||
{
|
||||
return self.map.tvalues();
|
||||
@@ -88,27 +95,34 @@ fn void*? TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, us
|
||||
backtrace::capture_current(&bt);
|
||||
self.map.set((uptr)data, { data, size, bt });
|
||||
self.mem_total += size;
|
||||
self.usage += size;
|
||||
if (self.usage > self.max_usage) self.max_usage = self.usage;
|
||||
return data;
|
||||
}
|
||||
|
||||
fn void*? TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
|
||||
{
|
||||
void* data = self.inner_allocator.resize(old_pointer, size, alignment)!;
|
||||
self.usage -= self.map[(uptr)old_pointer]!!.size;
|
||||
self.map.remove((uptr)old_pointer);
|
||||
void*[MAX_BACKTRACE] bt;
|
||||
backtrace::capture_current(&bt);
|
||||
self.map.set((uptr)data, { data, size, bt });
|
||||
self.mem_total += size;
|
||||
self.usage += size;
|
||||
if (self.usage > self.max_usage) self.max_usage = self.usage;
|
||||
self.allocs_total++;
|
||||
return data;
|
||||
}
|
||||
|
||||
fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned) @dynamic
|
||||
{
|
||||
usz? old_size = self.map[(uptr)old_pointer].size;
|
||||
if (catch self.map.remove((uptr)old_pointer))
|
||||
{
|
||||
unreachable("Attempt to release untracked pointer %p, this is likely a bug.", old_pointer);
|
||||
}
|
||||
self.usage -= old_size!!;
|
||||
self.inner_allocator.release(old_pointer, is_aligned);
|
||||
}
|
||||
|
||||
@@ -177,6 +191,7 @@ fn void? TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
|
||||
io::fprintfn(out, "- Total current allocations: %d", entries)!;
|
||||
io::fprintfn(out, "- Total allocations (freed and retained): %d", self.allocs_total)!;
|
||||
io::fprintfn(out, "- Total allocated memory (freed and retained): %d", self.mem_total)!;
|
||||
io::fprintfn(out, "- Maximum memory usage: %d", self.max_usage)!;
|
||||
if (leaks)
|
||||
{
|
||||
io::fprintn(out)!;
|
||||
|
||||
@@ -45,7 +45,7 @@ fn void? Vmem.init(&self, usz preferred_size, usz reserve_page_size = 0, VmemOpt
|
||||
if (page_size < reserve_page_size) page_size = reserve_page_size;
|
||||
preferred_size = mem::aligned_offset(preferred_size, page_size);
|
||||
if (!min_size) min_size = max(preferred_size / 1024, 1);
|
||||
VirtualMemory? memory = mem::OUT_OF_MEMORY?;
|
||||
VirtualMemory? memory = mem::OUT_OF_MEMORY~;
|
||||
while (preferred_size >= min_size)
|
||||
{
|
||||
memory = vm::virtual_alloc(preferred_size, PROTECTED);
|
||||
@@ -62,7 +62,7 @@ fn void? Vmem.init(&self, usz preferred_size, usz reserve_page_size = 0, VmemOpt
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (catch memory) return VMEM_RESERVE_FAILED?;
|
||||
if (catch memory) return VMEM_RESERVE_FAILED~;
|
||||
if (page_size > preferred_size) page_size = preferred_size;
|
||||
$if env::ADDRESS_SANITIZER:
|
||||
asan::poison_memory_region(memory.ptr, memory.size);
|
||||
@@ -87,12 +87,12 @@ fn void*? Vmem.acquire(&self, usz size, AllocInitType init_type, usz alignment)
|
||||
{
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
usz total_len = self.memory.size;
|
||||
if (size > total_len) return mem::INVALID_ALLOC_SIZE?;
|
||||
if (size > total_len) return mem::INVALID_ALLOC_SIZE~;
|
||||
void* start_mem = self.memory.ptr;
|
||||
void* unaligned_pointer_to_offset = start_mem + self.allocated + VmemHeader.sizeof;
|
||||
void* mem = mem::aligned_pointer(unaligned_pointer_to_offset, alignment);
|
||||
usz after = (usz)(mem - start_mem) + size;
|
||||
if (after > total_len) return mem::OUT_OF_MEMORY?;
|
||||
if (after > total_len) return mem::OUT_OF_MEMORY~;
|
||||
if (init_type == ZERO && self.high_water <= self.allocated)
|
||||
{
|
||||
init_type = NO_ZERO;
|
||||
@@ -119,7 +119,7 @@ fn bool Vmem.owns_pointer(&self, void* ptr) @inline
|
||||
*>
|
||||
fn void*? Vmem.resize(&self, void *old_pointer, usz size, usz alignment) @dynamic
|
||||
{
|
||||
if (size > self.memory.size) return mem::INVALID_ALLOC_SIZE?;
|
||||
if (size > self.memory.size) return mem::INVALID_ALLOC_SIZE~;
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
assert(self.owns_pointer(old_pointer), "Pointer originates from a different allocator: %p, not in %p - %p", old_pointer, self.memory.ptr, self.memory.ptr + self.allocated);
|
||||
VmemHeader* header = old_pointer - VmemHeader.sizeof;
|
||||
@@ -135,7 +135,7 @@ fn void*? Vmem.resize(&self, void *old_pointer, usz size, usz alignment) @dynami
|
||||
else
|
||||
{
|
||||
usz allocated = self.allocated + size - old_size;
|
||||
if (allocated > self.memory.size) return mem::OUT_OF_MEMORY?;
|
||||
if (allocated > self.memory.size) return mem::OUT_OF_MEMORY~;
|
||||
protect(self, allocated)!;
|
||||
}
|
||||
header.size = size;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::core::string::ansi;
|
||||
import std::io;
|
||||
|
||||
enum Ansi : const inline String
|
||||
{
|
||||
@@ -56,6 +57,37 @@ enum Ansi : const inline String
|
||||
BG_BRIGHT_WHITE = "\e[107m",
|
||||
}
|
||||
|
||||
struct AnsiColor (Printable)
|
||||
{
|
||||
char r, g, b;
|
||||
bool bg;
|
||||
}
|
||||
|
||||
fn usz? AnsiColor.to_format(&self, Formatter* fmt) @dynamic
|
||||
{
|
||||
return fmt.printf("\e[%s8;2;%s;%s;%sm", self.bg ? 4 : 3, self.r, self.g, self.b);
|
||||
}
|
||||
|
||||
<*
|
||||
24-bit color code
|
||||
|
||||
@return `A struct that, when formatted with '%s', sets the foreground or background colour to the specified rgb value`
|
||||
*>
|
||||
fn AnsiColor get_color_rgb(char r, char g, char b, bool bg = false)
|
||||
{
|
||||
return {r, g, b, bg};
|
||||
}
|
||||
|
||||
<*
|
||||
24-bit color code
|
||||
|
||||
@return `A struct that, when formatted with '%s', sets the foreground or background colour of printed text to the specified rgb value`
|
||||
*>
|
||||
fn AnsiColor get_color(uint rgb, bool bg = false)
|
||||
{
|
||||
return {(char)(rgb >> 16), (char)((rgb & 0x00FF00) >> 8), (char)rgb, bg};
|
||||
}
|
||||
|
||||
<*
|
||||
8-bit color code
|
||||
|
||||
@@ -96,7 +128,7 @@ macro String color(uint $rgb, bool $bg = false) @const
|
||||
@require rgb <= 0xFF_FF_FF : `Expected a 24 bit RGB value`
|
||||
@return `the string char for the given foreground color`
|
||||
*>
|
||||
fn String make_color(Allocator mem, uint rgb, bool bg = false)
|
||||
fn String make_color(Allocator mem, uint rgb, bool bg = false) @deprecated("use get_color instead")
|
||||
{
|
||||
return make_color_rgb(mem, (char)(rgb >> 16), (char)((rgb & 0xFF00) >> 8), (char)rgb, bg);
|
||||
}
|
||||
@@ -107,7 +139,7 @@ fn String make_color(Allocator mem, uint rgb, bool bg = false)
|
||||
@require rgb <= 0xFF_FF_FF : `Expected a 24 bit RGB value`
|
||||
@return `the string char for the given foreground color`
|
||||
*>
|
||||
fn String make_tcolor(uint rgb, bool bg = false)
|
||||
fn String make_tcolor(uint rgb, bool bg = false) @deprecated("use get_color instead")
|
||||
{
|
||||
return make_color_rgb(tmem, (char)(rgb >> 16), (char)((rgb & 0xFF00) >> 8), (char)rgb, bg);
|
||||
}
|
||||
@@ -117,7 +149,7 @@ fn String make_tcolor(uint rgb, bool bg = false)
|
||||
|
||||
@return `the string char for the given foreground color`
|
||||
*>
|
||||
fn String make_color_rgb(Allocator mem, char r, char g, char b, bool bg = false)
|
||||
fn String make_color_rgb(Allocator mem, char r, char g, char b, bool bg = false) @deprecated("use get_color_rgb instead")
|
||||
{
|
||||
return string::format(mem, "\e[%s8;2;%s;%s;%sm", bg ? 4 : 3, r, g, b);
|
||||
}
|
||||
@@ -127,7 +159,7 @@ fn String make_color_rgb(Allocator mem, char r, char g, char b, bool bg = false)
|
||||
|
||||
@return `the string char for the given foreground color`
|
||||
*>
|
||||
fn String make_tcolor_rgb(char r, char g, char b, bool bg = false)
|
||||
fn String make_tcolor_rgb(char r, char g, char b, bool bg = false) @deprecated("use get_color_rgb instead")
|
||||
{
|
||||
return string::format(tmem, "\e[%s8;2;%s;%s;%sm", bg ? 4 : 3, r, g, b);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ macro usz? index_of(array, element)
|
||||
{
|
||||
if (*e == element) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ macro usz? rindex_of(array, element)
|
||||
{
|
||||
if (*e == element) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -130,9 +130,27 @@ fn AsciiCharset create_set(String string)
|
||||
return set;
|
||||
}
|
||||
|
||||
macro bool AsciiCharset.@contains($set, char $c) @const => !!($c < 128) & !!($set & (AsciiCharset)(1ULL << $c));
|
||||
|
||||
macro AsciiCharset @combine_sets(AsciiCharset $first, AsciiCharset... $sets) @const
|
||||
{
|
||||
var $res = $first;
|
||||
$foreach $c : $sets:
|
||||
$res |= $c;
|
||||
$endforeach
|
||||
return $res;
|
||||
}
|
||||
fn AsciiCharset combine_sets(AsciiCharset first, AsciiCharset... sets)
|
||||
{
|
||||
foreach (c : sets) first |= c;
|
||||
return first;
|
||||
}
|
||||
|
||||
macro bool AsciiCharset.contains(set, char c) => !!(c < 128) & !!(set & (AsciiCharset)(1ULL << c));
|
||||
|
||||
const AsciiCharset WHITESPACE_SET = @create_set("\t\n\v\f\r ");
|
||||
const AsciiCharset NUMBER_SET = @create_set("0123456789");
|
||||
|
||||
|
||||
const AsciiCharset ALPHA_UPPER_SET = @create_set("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
const AsciiCharset ALPHA_LOWER_SET = @create_set("abcdefghijklmnopqrstuvwxyz");
|
||||
const AsciiCharset ALPHA_SET = @combine_sets(ALPHA_UPPER_SET, ALPHA_LOWER_SET);
|
||||
const AsciiCharset ALPHANUMERIC_SET = @combine_sets(ALPHA_SET, NUMBER_SET);
|
||||
|
||||
@@ -90,33 +90,35 @@ bitstruct UInt128LE : uint128 @littleendian
|
||||
<*
|
||||
@require @is_array_or_slice_of_char(bytes) : "argument must be an array, a pointer to an array or a slice of char"
|
||||
@require is_bitorder($Type) : "type must be a bitorder integer"
|
||||
@require $defined(*bytes) ||| $defined(bytes[:$Type.sizeof]) : "Data is too short to contain value"
|
||||
*>
|
||||
macro read(bytes, $Type)
|
||||
{
|
||||
char[] s;
|
||||
char *ptr;
|
||||
$switch $kindof(bytes):
|
||||
$case POINTER:
|
||||
s = (*bytes)[:$Type.sizeof];
|
||||
ptr = bytes;
|
||||
$default:
|
||||
s = bytes[:$Type.sizeof];
|
||||
ptr = bytes[..].ptr;
|
||||
$endswitch
|
||||
return bitcast(*(char[$Type.sizeof]*)s.ptr, $Type).val;
|
||||
return bitcast(mem::load((char[$Type.sizeof]*)ptr, $align: 1), $Type).val;
|
||||
}
|
||||
|
||||
<*
|
||||
@require @is_arrayptr_or_slice_of_char(bytes) : "argument must be a pointer to an array or a slice of char"
|
||||
@require is_bitorder($Type) : "type must be a bitorder integer"
|
||||
@require $defined(*bytes) ||| $defined(bytes[:$Type.sizeof]) : "Data is not sufficent to hold value"
|
||||
*>
|
||||
macro write(x, bytes, $Type)
|
||||
{
|
||||
char[] s;
|
||||
char *ptr;
|
||||
$switch $kindof(bytes):
|
||||
$case POINTER:
|
||||
s = (*bytes)[:$Type.sizeof];
|
||||
ptr = bytes;
|
||||
$default:
|
||||
s = bytes[:$Type.sizeof];
|
||||
ptr = bytes[..].ptr;
|
||||
$endswitch
|
||||
*($typeof(x)*)s.ptr = bitcast(x, $Type).val;
|
||||
mem::store(($typeof(x)*)ptr, bitcast(x, $Type).val, 1);
|
||||
}
|
||||
|
||||
macro bool is_bitorder($Type)
|
||||
|
||||
@@ -24,11 +24,15 @@ macro foo(a, #b = EMPTY_MACRO_SLOT)
|
||||
$endif
|
||||
}
|
||||
*>
|
||||
const EmptySlot EMPTY_MACRO_SLOT @builtin = null;
|
||||
const EmptySlot EMPTY_MACRO_SLOT @builtin @deprecated("Use `#arg = ...` instead.") = null;
|
||||
|
||||
typedef EmptySlot = void*;
|
||||
macro bool @is_empty_macro_slot(#arg) @const @builtin => $typeof(#arg) == EmptySlot;
|
||||
macro bool @is_valid_macro_slot(#arg) @const @builtin => $typeof(#arg) != EmptySlot;
|
||||
macro bool @is_empty_macro_slot(#arg) @const @builtin
|
||||
@deprecated("Use `#arg = ...` to define an optional macro slot, and `$defined(#arg)` to detect whether the argument is set.")
|
||||
=> $typeof(#arg) == EmptySlot;
|
||||
macro bool @is_valid_macro_slot(#arg) @const @builtin
|
||||
@deprecated("Use `#arg = ...` to define an optional macro slot, and `$defined(#arg)` to detect whether the argument is set.")
|
||||
=> $typeof(#arg) != EmptySlot;
|
||||
|
||||
<*
|
||||
Returns a random value at compile time.
|
||||
@@ -93,6 +97,21 @@ macro usz bitsizeof($Type) @builtin @const => $Type.sizeof * 8u;
|
||||
|
||||
macro usz @bitsizeof(#expr) @builtin @const => $sizeof(#expr) * 8u;
|
||||
|
||||
<*
|
||||
Compile-time check for whether a set of constants contains a certain expression.
|
||||
|
||||
@param #needle : "The expression whose value should be located."
|
||||
*>
|
||||
macro bool @in(#needle, ...) @builtin @const
|
||||
{
|
||||
$for var $x = 0; $x < $vacount; $x++:
|
||||
$assert $defined(#needle == $vaconst[$x])
|
||||
: "Index %s: types '%s' (needle) and '%s' are not equatable", $x, $typeof(#needle), $typeof($vaconst[$x]);
|
||||
$if #needle == $vaconst[$x]: return true; $endif
|
||||
$endfor
|
||||
return false;
|
||||
}
|
||||
|
||||
<*
|
||||
Convert an `any` type to a type, returning an failure if there is a type mismatch.
|
||||
|
||||
@@ -104,10 +123,29 @@ macro usz @bitsizeof(#expr) @builtin @const => $sizeof(#expr) * 8u;
|
||||
*>
|
||||
macro anycast(any v, $Type) @builtin
|
||||
{
|
||||
if (v.type != $Type.typeid) return TYPE_MISMATCH?;
|
||||
if (v.type != $Type.typeid) return TYPE_MISMATCH~;
|
||||
return ($Type*)v.ptr;
|
||||
}
|
||||
|
||||
<*
|
||||
@return "The value in the pointer"
|
||||
@return? TYPE_MISMATCH
|
||||
*>
|
||||
macro any.to(self, $Type)
|
||||
{
|
||||
if (self.type != $Type.typeid) return TYPE_MISMATCH~;
|
||||
return *($Type*)self.ptr;
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.type == $Type : "The 'any' contained an unexpected type."
|
||||
@return "The value in the pointer"
|
||||
*>
|
||||
macro any.as(self, $Type)
|
||||
{
|
||||
return *($Type*)self.ptr;
|
||||
}
|
||||
|
||||
macro bool @assignable_to(#foo, $Type) @const @builtin @deprecated("use '$defined($Type x = #foo)'") => $defined(*&&($Type){} = #foo);
|
||||
|
||||
macro @addr(#val) @builtin
|
||||
@@ -143,7 +181,7 @@ fn bool print_backtrace(String message, int backtraces_to_ignore, void *added_ba
|
||||
{
|
||||
backtraces[++backtraces_to_ignore] = added_backtrace;
|
||||
}
|
||||
@stack_mem(2048; Allocator mem)
|
||||
@stack_mem(4096; Allocator mem)
|
||||
{
|
||||
BacktraceList? backtrace = backtrace::symbolize_backtrace(mem, backtraces);
|
||||
if (catch backtrace) return false;
|
||||
@@ -174,6 +212,7 @@ fn bool print_backtrace(String message, int backtraces_to_ignore, void *added_ba
|
||||
|
||||
fn void default_panic(String message, String file, String function, uint line) @if(env::NATIVE_STACKTRACE)
|
||||
{
|
||||
in_panic = true;
|
||||
$if $defined(io::stderr) && env::PANIC_MSG:
|
||||
if (!print_backtrace(message, 2))
|
||||
{
|
||||
@@ -190,7 +229,7 @@ macro void abort(String string = "Unrecoverable error reached", ...) @format(0)
|
||||
$$trap();
|
||||
}
|
||||
|
||||
bool in_panic @local = false;
|
||||
bool in_panic @private = false;
|
||||
|
||||
fn void default_panic(String message, String file, String function, uint line) @if (!env::NATIVE_STACKTRACE)
|
||||
{
|
||||
@@ -315,7 +354,7 @@ macro enum_by_name($Type, String enum_name) @builtin
|
||||
{
|
||||
if (name == enum_name) return $Type.from_ordinal(i);
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -332,7 +371,7 @@ macro @enum_from_value($Type, #value, value) @builtin @deprecated("Use Enum.look
|
||||
{
|
||||
if (e.#value == value) return e;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -416,11 +455,25 @@ macro @prefetch(void* ptr, PrefetchLocality $locality = VERY_NEAR, bool $write =
|
||||
$endif
|
||||
}
|
||||
|
||||
<*
|
||||
Shuffle a vector by its index
|
||||
|
||||
int[<4>] a = { 1, 2, 3, 4 };
|
||||
assert(swizzle(a, 0, 1, 1, 3) == (int[<4>]) { 1, 2, 2, 4 });
|
||||
*>
|
||||
macro swizzle(v, ...) @builtin
|
||||
{
|
||||
return $$swizzle(v, $vasplat);
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Shuffle two vectors by a common index from arranging the vectors sequentially in memory
|
||||
|
||||
int[<4>] a = { 1, 2, 3, 4 };
|
||||
int[<4>] b = { 100, 1000, 10000, 100000 };
|
||||
assert(swizzle2(a, b, 0, 1, 4, 6, 2) == (int[<5>]) { 1, 2, 100, 10000, 3 });
|
||||
*>
|
||||
macro swizzle2(v, v2, ...) @builtin
|
||||
{
|
||||
return $$swizzle2(v, v2, $vasplat);
|
||||
@@ -488,7 +541,7 @@ macro bool @ok(#expr) @builtin
|
||||
macro void? @try(#v, #expr) @builtin @maydiscard
|
||||
{
|
||||
var res = #expr;
|
||||
if (catch err = res) return err?;
|
||||
if (catch err = res) return err~;
|
||||
#v = res;
|
||||
}
|
||||
|
||||
@@ -532,7 +585,7 @@ macro bool? @try_catch(#v, #expr, fault expected_fault) @builtin
|
||||
var res = #expr;
|
||||
if (catch err = res)
|
||||
{
|
||||
return err == expected_fault ? true : err?;
|
||||
return err == expected_fault ? true : err~;
|
||||
}
|
||||
#v = res;
|
||||
return false;
|
||||
@@ -651,7 +704,7 @@ macro uint hash_array(array_ptr) @local
|
||||
*>
|
||||
macro uint hash_vec(vec) @local
|
||||
{
|
||||
var $len = $sizeof(vec.len * $typeof(vec).inner.sizeof);
|
||||
var $len = $sizeof(vec);
|
||||
|
||||
$if $len > 16:
|
||||
return (uint)komi::hash(((char*)&&vec)[:$len]);
|
||||
@@ -963,7 +1016,7 @@ fn void sig_bus_error(CInt i, void* info, void* context)
|
||||
}
|
||||
$endif
|
||||
$endif
|
||||
$$trap();
|
||||
os::fastexit(128 + i);
|
||||
}
|
||||
|
||||
fn void sig_segmentation_fault(CInt i, void* p1, void* context)
|
||||
@@ -978,15 +1031,39 @@ fn void sig_segmentation_fault(CInt i, void* p1, void* context)
|
||||
}
|
||||
$endif
|
||||
$endif
|
||||
$$trap();
|
||||
os::fastexit(128 + i);
|
||||
}
|
||||
|
||||
fn void sig_illegal_instruction(CInt i, void* p1, void* context)
|
||||
{
|
||||
if (in_panic) os::fastexit(128 + i);
|
||||
$if !env::NATIVE_STACKTRACE:
|
||||
sig_panic("Illegal instruction.");
|
||||
$else
|
||||
$if $defined(io::stderr):
|
||||
if (!print_backtrace("Illegal instruction.", 2, posix::stack_instruction(context)))
|
||||
{
|
||||
io::eprintn("\nERROR: Illegal instruction.");
|
||||
}
|
||||
$endif
|
||||
$endif
|
||||
os::fastexit(128 + i);
|
||||
}
|
||||
|
||||
char[64 * 1024] sig_stack @local @if(env::BACKTRACE && env::LINUX);
|
||||
|
||||
// Clean this up
|
||||
fn void install_signal_handlers() @init(101) @local @if(env::BACKTRACE)
|
||||
{
|
||||
$if env::LINUX:
|
||||
Stack_t ss = {
|
||||
.ss_sp = &sig_stack,
|
||||
.ss_size = sig_stack.len
|
||||
};
|
||||
libc::sigaltstack(&ss, null);
|
||||
$endif
|
||||
|
||||
posix::install_signal_handler(libc::SIGBUS, &sig_bus_error);
|
||||
posix::install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
|
||||
posix::install_signal_handler(libc::SIGILL, &sig_illegal_instruction);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,25 +16,25 @@ const uint UTF16_SURROGATE_HIGH_VALUE @private = 0xD800;
|
||||
*>
|
||||
fn usz? char32_to_utf8(Char32 c, char[] output)
|
||||
{
|
||||
if (!output.len) return string::CONVERSION_FAILED?;
|
||||
if (!output.len) return string::CONVERSION_FAILED~;
|
||||
switch (true)
|
||||
{
|
||||
case c <= 0x7f:
|
||||
output[0] = (char)c;
|
||||
return 1;
|
||||
case c <= 0x7ff:
|
||||
if (output.len < 2) return string::CONVERSION_FAILED?;
|
||||
if (output.len < 2) return string::CONVERSION_FAILED~;
|
||||
output[0] = (char)(0xC0 | c >> 6);
|
||||
output[1] = (char)(0x80 | (c & 0x3F));
|
||||
return 2;
|
||||
case c <= 0xffff:
|
||||
if (output.len < 3) return string::CONVERSION_FAILED?;
|
||||
if (output.len < 3) return string::CONVERSION_FAILED~;
|
||||
output[0] = (char)(0xE0 | c >> 12);
|
||||
output[1] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
output[2] = (char)(0x80 | (c & 0x3F));
|
||||
return 3;
|
||||
case c <= 0x10ffff:
|
||||
if (output.len < 4) return string::CONVERSION_FAILED?;
|
||||
if (output.len < 4) return string::CONVERSION_FAILED~;
|
||||
output[0] = (char)(0xF0 | c >> 18);
|
||||
output[1] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
output[2] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
@@ -42,7 +42,7 @@ fn usz? char32_to_utf8(Char32 c, char[] output)
|
||||
return 4;
|
||||
default:
|
||||
// 0x10FFFF and above is not defined.
|
||||
return string::CONVERSION_FAILED?;
|
||||
return string::CONVERSION_FAILED~;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,15 +84,15 @@ fn void? char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output)
|
||||
return;
|
||||
}
|
||||
// Low surrogate first is an error
|
||||
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return string::INVALID_UTF16?;
|
||||
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return string::INVALID_UTF16~;
|
||||
|
||||
// Unmatched high surrogate is an error
|
||||
if (*available == 1) return string::INVALID_UTF16?;
|
||||
if (*available == 1) return string::INVALID_UTF16~;
|
||||
|
||||
Char16 low = ptr[1];
|
||||
|
||||
// Unmatched high surrogate, invalid
|
||||
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return string::INVALID_UTF16?;
|
||||
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return string::INVALID_UTF16~;
|
||||
|
||||
// The high bits of the codepoint are the value bits of the high surrogate
|
||||
// The low bits of the codepoint are the value bits of the low surrogate
|
||||
@@ -138,7 +138,7 @@ fn usz char32_to_utf8_unsafe(Char32 c, char** output)
|
||||
fn Char32? utf8_to_char32(char* ptr, usz* size)
|
||||
{
|
||||
usz max_size = *size;
|
||||
if (max_size < 1) return string::INVALID_UTF8?;
|
||||
if (max_size < 1) return string::INVALID_UTF8~;
|
||||
char c = (ptr++)[0];
|
||||
|
||||
if ((c & 0x80) == 0)
|
||||
@@ -148,40 +148,40 @@ fn Char32? utf8_to_char32(char* ptr, usz* size)
|
||||
}
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
{
|
||||
if (max_size < 2) return string::INVALID_UTF8?;
|
||||
if (max_size < 2) return string::INVALID_UTF8~;
|
||||
*size = 2;
|
||||
Char32 uc = (c & 0x1F) << 6;
|
||||
c = *ptr;
|
||||
// Overlong sequence or invalid second.
|
||||
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8?;
|
||||
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8~;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
if ((c & 0xF0) == 0xE0)
|
||||
{
|
||||
if (max_size < 3) return string::INVALID_UTF8?;
|
||||
if (max_size < 3) return string::INVALID_UTF8~;
|
||||
*size = 3;
|
||||
Char32 uc = (c & 0x0F) << 12;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return string::INVALID_UTF8?;
|
||||
if (c & 0xC0 != 0x80) return string::INVALID_UTF8~;
|
||||
uc += (c & 0x3F) << 6;
|
||||
c = ptr++[0];
|
||||
// Overlong sequence or invalid last
|
||||
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8?;
|
||||
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8~;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
if (max_size < 4) return string::INVALID_UTF8?;
|
||||
if ((c & 0xF8) != 0xF0) return string::INVALID_UTF8?;
|
||||
if (max_size < 4) return string::INVALID_UTF8~;
|
||||
if ((c & 0xF8) != 0xF0) return string::INVALID_UTF8~;
|
||||
*size = 4;
|
||||
Char32 uc = (c & 0x07) << 18;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return string::INVALID_UTF8?;
|
||||
if (c & 0xC0 != 0x80) return string::INVALID_UTF8~;
|
||||
uc += (c & 0x3F) << 12;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return string::INVALID_UTF8?;
|
||||
if (c & 0xC0 != 0x80) return string::INVALID_UTF8~;
|
||||
uc += (c & 0x3F) << 6;
|
||||
c = ptr++[0];
|
||||
// Overlong sequence or invalid last
|
||||
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8?;
|
||||
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8~;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ fn usz? utf8to32(String utf8, Char32[] utf32_buffer)
|
||||
usz buf_len = utf32_buffer.len;
|
||||
for (usz i = 0; i < len;)
|
||||
{
|
||||
if (len32 == buf_len) return string::CONVERSION_FAILED?;
|
||||
if (len32 == buf_len) return string::CONVERSION_FAILED~;
|
||||
usz width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!;
|
||||
i += width;
|
||||
|
||||
@@ -95,7 +95,7 @@ fn void DString.replace(&self, String needle, String replacement)
|
||||
match++;
|
||||
if (match == needle_len)
|
||||
{
|
||||
self.append_chars(replacement);
|
||||
self.append_string(replacement);
|
||||
match = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -103,12 +103,12 @@ fn void DString.replace(&self, String needle, String replacement)
|
||||
}
|
||||
if (match > 0)
|
||||
{
|
||||
self.append_chars(str[i - match:match]);
|
||||
self.append_string(str[i - match:match]);
|
||||
match = 0;
|
||||
}
|
||||
self.append_char(c);
|
||||
}
|
||||
if (match > 0) self.append_chars(str[^match:match]);
|
||||
if (match > 0) self.append_string(str[^match:match]);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -305,18 +305,23 @@ fn bool DString.less(self, DString other_string)
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void DString.append_chars(&self, String str)
|
||||
fn void DString.append_chars(&self, String str) @deprecated("Use append_string")
|
||||
{
|
||||
usz other_len = str.len;
|
||||
self.append_bytes(str);
|
||||
}
|
||||
|
||||
fn void DString.append_bytes(&self, char[] bytes)
|
||||
{
|
||||
usz other_len = bytes.len;
|
||||
if (!other_len) return;
|
||||
if (!*self)
|
||||
{
|
||||
*self = temp(str);
|
||||
*self = temp((String)bytes);
|
||||
return;
|
||||
}
|
||||
self.reserve(other_len);
|
||||
StringData* data = self.data();
|
||||
mem::copy(&data.chars[data.len], str.ptr, other_len);
|
||||
mem::copy(&data.chars[data.len], bytes.ptr, other_len);
|
||||
data.len += other_len;
|
||||
}
|
||||
|
||||
@@ -325,7 +330,24 @@ fn Char32[] DString.copy_utf32(&self, Allocator allocator)
|
||||
return self.str_view().to_utf32(allocator) @inline!!;
|
||||
}
|
||||
|
||||
fn void DString.append_string(&self, DString str)
|
||||
<*
|
||||
@require $typeof(str) == String || $typeof(str) == DString : "Expected string or DString"
|
||||
*>
|
||||
macro void DString.append_string(&self, str)
|
||||
{
|
||||
$if $typeof(str) == String:
|
||||
self.append_bytes(str);
|
||||
$else
|
||||
self.append_string_deprecated(str);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro void DString.append_string_deprecated(&self, DString str) @deprecated("Use .append_dstring()")
|
||||
{
|
||||
self.append_dstring(str);
|
||||
}
|
||||
|
||||
fn void DString.append_dstring(&self, DString str)
|
||||
{
|
||||
StringData* other = str.data();
|
||||
if (!other) return;
|
||||
@@ -340,7 +362,7 @@ fn void DString.clear(self)
|
||||
|
||||
fn usz? DString.write(&self, char[] buffer) @dynamic
|
||||
{
|
||||
self.append_chars((String)buffer);
|
||||
self.append_bytes(buffer);
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
@@ -400,9 +422,9 @@ macro void DString.append(&self, value)
|
||||
$case ichar:
|
||||
self.append_char(value);
|
||||
$case DString:
|
||||
self.append_string(value);
|
||||
self.append_dstring(value);
|
||||
$case String:
|
||||
self.append_chars(value);
|
||||
self.append_string(value);
|
||||
$case Char32:
|
||||
self.append_char32(value);
|
||||
$default:
|
||||
@@ -410,7 +432,7 @@ macro void DString.append(&self, value)
|
||||
$case $defined((Char32)value):
|
||||
self.append_char32((Char32)value);
|
||||
$case $defined((String)value):
|
||||
self.append_chars((String)value);
|
||||
self.append_string((String)value);
|
||||
$default:
|
||||
$error "Unsupported type for append – use appendf instead.";
|
||||
$endswitch
|
||||
|
||||
@@ -124,7 +124,8 @@ const usz MAX_VECTOR_SIZE = $$MAX_VECTOR_SIZE;
|
||||
const bool ARCH_32_BIT = $$REGISTER_SIZE == 32;
|
||||
const bool ARCH_64_BIT = $$REGISTER_SIZE == 64;
|
||||
const bool LIBC = $$COMPILER_LIBC_AVAILABLE;
|
||||
const bool NO_LIBC = !$$COMPILER_LIBC_AVAILABLE;
|
||||
const bool NO_LIBC = !LIBC && !CUSTOM_LIBC;
|
||||
const bool CUSTOM_LIBC = $$CUSTOM_LIBC;
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = CompilerOptLevel.from_ordinal($$COMPILER_OPT_LEVEL);
|
||||
const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN;
|
||||
const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED;
|
||||
@@ -153,19 +154,20 @@ const bool FREEBSD = LIBC && OS_TYPE == FREEBSD;
|
||||
const bool NETBSD = LIBC && OS_TYPE == NETBSD;
|
||||
const bool BSD_FAMILY = env::FREEBSD || env::OPENBSD || env::NETBSD;
|
||||
const bool WASI = LIBC && OS_TYPE == WASI;
|
||||
const bool WASM = ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
|
||||
const bool ANDROID = LIBC && OS_TYPE == ANDROID;
|
||||
const bool WASM_NOLIBC @builtin @deprecated("Use 'FREESTANDING_WASM' instead") = !LIBC && ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64;
|
||||
const bool FREESTANDING_PE32 = NO_LIBC && OS_TYPE == WIN32;
|
||||
const bool FREESTANDING_MACHO = NO_LIBC && OS_TYPE == MACOS;
|
||||
const bool FREESTANDING_ELF = NO_LIBC && !env::FREESTANDING_PE32 && !env::FREESTANDING_MACHO && !env::FREESTANDING_WASM;
|
||||
const bool FREESTANDING_WASM = NO_LIBC && (ARCH_TYPE == ArchType.WASM32 || ARCH_TYPE == ArchType.WASM64);
|
||||
const bool FREESTANDING_WASM = NO_LIBC && WASM;
|
||||
const bool FREESTANDING = env::FREESTANDING_PE32 || env::FREESTANDING_MACHO || env::FREESTANDING_ELF || env::FREESTANDING_WASM;
|
||||
const bool ADDRESS_SANITIZER = $$ADDRESS_SANITIZER;
|
||||
const bool MEMORY_SANITIZER = $$MEMORY_SANITIZER;
|
||||
const bool THREAD_SANITIZER = $$THREAD_SANITIZER;
|
||||
const bool ANY_SANITIZER = ADDRESS_SANITIZER || MEMORY_SANITIZER || THREAD_SANITIZER;
|
||||
const int LANGUAGE_DEV_VERSION = $$LANGUAGE_DEV_VERSION;
|
||||
const bool HAS_NATIVE_ERRNO = env::LINUX || env::ANDROID || env::OPENBSD || env::DARWIN || env::WIN32;
|
||||
const bool HAS_NATIVE_ERRNO = env::LINUX || env::ANDROID || env::OPENBSD || env::DARWIN || env::WIN32 || env::NETBSD;
|
||||
|
||||
macro bool os_is_darwin() @const
|
||||
{
|
||||
|
||||
@@ -148,17 +148,18 @@ fn void call_log_internal(LogPriority prio, LogCategory category, String file, S
|
||||
LogPriority priority = mem::@atomic_load(config_priorities[category], UNORDERED);
|
||||
if (priority > prio) return;
|
||||
init();
|
||||
bool locked = logger_mutex.is_initialized() && @ok(logger_mutex.lock());
|
||||
bool locked = logger_mutex.is_initialized();
|
||||
if (locked) logger_mutex.lock();
|
||||
Logger logger = current_logger;
|
||||
LogFn logfn = current_logfn;
|
||||
defer if (locked) (void)logger_mutex.unlock();
|
||||
defer if (locked) logger_mutex.unlock();
|
||||
logfn(logger.ptr, prio, category, current_tag, file, func, line, fmt, args);
|
||||
}
|
||||
|
||||
fn String? get_category_name(LogCategory category)
|
||||
{
|
||||
String val = category_names[category];
|
||||
return val ?: NOT_FOUND?;
|
||||
return val ?: NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn void set_category_name(LogCategory category, String name)
|
||||
|
||||
@@ -7,7 +7,7 @@ import std::os::posix, std::os::win32;
|
||||
import std::math;
|
||||
|
||||
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
|
||||
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
|
||||
const DEFAULT_MEM_ALIGNMENT = env::WASM ? 16 : (void*.alignof) * 2;
|
||||
const ulong KB = 1024;
|
||||
const ulong MB = KB * 1024;
|
||||
const ulong GB = MB * 1024;
|
||||
@@ -200,7 +200,7 @@ macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment)
|
||||
*>
|
||||
macro @unaligned_load(#x, usz $alignment) @builtin
|
||||
{
|
||||
return $$unaligned_load(&#x, $alignment);
|
||||
return $$unaligned_load(&#x, $alignment, false);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -215,9 +215,10 @@ macro @unaligned_load(#x, usz $alignment) @builtin
|
||||
*>
|
||||
macro @unaligned_store(#x, value, usz $alignment) @builtin
|
||||
{
|
||||
return $$unaligned_store(&#x, ($typeof(#x))value, $alignment);
|
||||
return $$unaligned_store(&#x, ($typeof(#x))value, $alignment, false);
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
@param #x : "The variable or dereferenced pointer to load."
|
||||
@return "The value of the variable"
|
||||
@@ -242,6 +243,36 @@ macro @volatile_store(#x, value) @builtin
|
||||
return $$volatile_store(&#x, ($typeof(#x))value);
|
||||
}
|
||||
|
||||
<*
|
||||
@param ptr : "The pointer to load from"
|
||||
@param $align : "The alignment to assume for the load"
|
||||
@param $volatile : "Whether the load is volatile or not, defaults to false"
|
||||
@return "The value of the variable"
|
||||
|
||||
@require $defined(*ptr) : "This must be a typed pointer"
|
||||
@require @constant_is_power_of_2($align) : "The alignment must be a power of two"
|
||||
*>
|
||||
macro load(ptr, usz $align, bool $volatile = false)
|
||||
{
|
||||
return $$unaligned_load(ptr, $align, $volatile);
|
||||
}
|
||||
|
||||
<*
|
||||
@param ptr : "The pointer to store to."
|
||||
@param value : "The value to store."
|
||||
@param $align : "The alignment to assume for the store"
|
||||
@param $volatile : "Whether the store is volatile, defaults to false"
|
||||
@return "The value stored"
|
||||
|
||||
@require $defined(*ptr) : "This must be a typed pointer"
|
||||
@require $defined(*ptr = value) : "The value doesn't match the variable"
|
||||
@require @constant_is_power_of_2($align) : "The alignment must be a power of two"
|
||||
*>
|
||||
macro store(ptr, value, usz $align, bool $volatile = false)
|
||||
{
|
||||
return $$unaligned_store(ptr, ($typeof(*ptr))value, $align, $volatile);
|
||||
}
|
||||
|
||||
<*
|
||||
All possible atomic orderings
|
||||
*>
|
||||
@@ -807,6 +838,7 @@ macro new_aligned($Type, #init = ...) @nodiscard @safemacro
|
||||
<*
|
||||
@param $Type : "The type to allocate"
|
||||
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
|
||||
@return "A pointer to uninitialized data for the type $Type"
|
||||
*>
|
||||
@@ -819,7 +851,8 @@ macro alloc($Type) @nodiscard
|
||||
@param $Type : "The type to allocate"
|
||||
@param padding : "The padding to add after the allocation"
|
||||
|
||||
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
|
||||
@return "A pointer to uninitialized data for the type $Type"
|
||||
*>
|
||||
macro alloc_with_padding($Type, usz padding) @nodiscard
|
||||
@@ -833,6 +866,7 @@ macro alloc_with_padding($Type, usz padding) @nodiscard
|
||||
exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
|
||||
|
||||
@param $Type : "The type to allocate"
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@return "A pointer to uninitialized data for the type $Type with the proper alignment"
|
||||
*>
|
||||
macro alloc_aligned($Type) @nodiscard
|
||||
@@ -844,6 +878,7 @@ macro alloc_aligned($Type) @nodiscard
|
||||
@param $Type : "The type to allocate"
|
||||
@param #init : "The optional initializer"
|
||||
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@require !$defined(#init) ||| $defined($Type a = #init) : "#init must be an initializer for the type"
|
||||
@return "A pointer to temporary data of type $Type."
|
||||
*>
|
||||
@@ -863,6 +898,7 @@ macro tnew($Type, #init = ...) @nodiscard @safemacro
|
||||
@param padding : "The padding to add after the allocation"
|
||||
@param #init : "The optional initializer"
|
||||
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@require !$defined(#init) ||| $defined($Type a = #init) : "#init must be an initializer for the type"
|
||||
@return "A pointer to temporary data of type $Type with added padding at the end."
|
||||
*>
|
||||
@@ -877,17 +913,24 @@ macro temp_with_padding($Type, usz padding, #init = ...) @nodiscard @safemacro
|
||||
$endif
|
||||
}
|
||||
|
||||
<*
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
*>
|
||||
macro talloc($Type) @nodiscard
|
||||
{
|
||||
return tmalloc($Type.sizeof, $Type.alignof);
|
||||
}
|
||||
|
||||
<*
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
*>
|
||||
macro talloc_with_padding($Type, usz padding) @nodiscard
|
||||
{
|
||||
return tmalloc($Type.sizeof + padding, $Type.alignof);
|
||||
}
|
||||
|
||||
<*
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead"
|
||||
*>
|
||||
macro new_array($Type, usz elements) @nodiscard
|
||||
@@ -898,6 +941,8 @@ macro new_array($Type, usz elements) @nodiscard
|
||||
<*
|
||||
Allocate using an aligned allocation. This is necessary for types with a default memory alignment
|
||||
exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
|
||||
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
*>
|
||||
macro new_array_aligned($Type, usz elements) @nodiscard
|
||||
{
|
||||
@@ -905,6 +950,7 @@ macro new_array_aligned($Type, usz elements) @nodiscard
|
||||
}
|
||||
|
||||
<*
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead"
|
||||
*>
|
||||
macro alloc_array($Type, usz elements) @nodiscard
|
||||
@@ -915,6 +961,8 @@ macro alloc_array($Type, usz elements) @nodiscard
|
||||
<*
|
||||
Allocate using an aligned allocation. This is necessary for types with a default memory alignment
|
||||
exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
|
||||
|
||||
@require $Type.kindof != OPTIONAL : "Expected a non-optional type"
|
||||
*>
|
||||
macro alloc_array_aligned($Type, usz elements) @nodiscard
|
||||
{
|
||||
@@ -1029,7 +1077,7 @@ fn void* __memcpy(void* dst, void* src, usz n) @weak @export("memcpy")
|
||||
}
|
||||
|
||||
|
||||
module std::core::mem::volatile { Type };
|
||||
module std::core::mem::volatile <Type>;
|
||||
|
||||
typedef Volatile @structlike = Type;
|
||||
|
||||
@@ -1046,7 +1094,7 @@ macro Type Volatile.set(&self, Type val)
|
||||
<*
|
||||
@require mem::@constant_is_power_of_2(ALIGNMENT) : "The alignment must be a power of 2"
|
||||
*>
|
||||
module std::core::mem::alignment { Type, ALIGNMENT };
|
||||
module std::core::mem::alignment <Type, ALIGNMENT>;
|
||||
import std::core::mem @public;
|
||||
|
||||
<*
|
||||
@@ -1056,10 +1104,10 @@ typedef UnalignedRef = Type*;
|
||||
|
||||
macro Type UnalignedRef.get(self)
|
||||
{
|
||||
return @unaligned_load(*(Type*)self, ALIGNMENT);
|
||||
return @unaligned_load(*(Type*)self, ALIGNMENT, false);
|
||||
}
|
||||
|
||||
macro Type UnalignedRef.set(&self, Type val)
|
||||
{
|
||||
return @unaligned_store(*(Type*)self, val, ALIGNMENT);
|
||||
return @unaligned_store(*(Type*)self, val, ALIGNMENT, false);
|
||||
}
|
||||
|
||||
@@ -304,6 +304,31 @@ macro alloc_array_try(Allocator allocator, $Type, usz elements) @nodiscard
|
||||
return (($Type*)malloc_try(allocator, $Type.sizeof * elements))[:elements];
|
||||
}
|
||||
|
||||
<*
|
||||
@require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead"
|
||||
*>
|
||||
macro realloc_array(Allocator allocator, void* ptr, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return realloc_array_try(allocator, ptr, $Type, elements)!!;
|
||||
}
|
||||
|
||||
<*
|
||||
Allocate using an aligned allocation. This is necessary for types with a default memory alignment
|
||||
exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
|
||||
*>
|
||||
macro realloc_array_aligned(Allocator allocator, void* ptr, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return (($Type*)realloc_aligned(allocator, ptr, $Type.sizeof * elements, $Type.alignof))[:elements]!!;
|
||||
}
|
||||
|
||||
<*
|
||||
@require $Type.alignof <= mem::DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_array_aligned' instead"
|
||||
*>
|
||||
macro realloc_array_try(Allocator allocator, void* ptr, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return (($Type*)realloc_try(allocator, ptr, $Type.sizeof * elements))[:elements];
|
||||
}
|
||||
|
||||
<*
|
||||
Clone a value.
|
||||
|
||||
@@ -326,6 +351,8 @@ macro clone(Allocator allocator, value) @nodiscard
|
||||
*>
|
||||
macro clone_slice(Allocator allocator, slice) @nodiscard
|
||||
{
|
||||
if (!lengthof(slice)) return {};
|
||||
|
||||
var $Type = $typeof(slice[0]);
|
||||
|
||||
$Type[] new_arr = new_array(allocator, $Type, slice.len);
|
||||
@@ -556,12 +583,12 @@ typedef NullAllocator (Allocator) = uptr;
|
||||
|
||||
fn void*? NullAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
|
||||
{
|
||||
return mem::OUT_OF_MEMORY?;
|
||||
return mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
|
||||
fn void*? NullAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
|
||||
{
|
||||
return mem::OUT_OF_MEMORY?;
|
||||
return mem::OUT_OF_MEMORY~;
|
||||
}
|
||||
|
||||
fn void NullAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
|
||||
|
||||
@@ -54,11 +54,11 @@ fn void*? alloc(usz size, VirtualMemoryAccess access)
|
||||
if (ptr != posix::MAP_FAILED) return ptr;
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::ENOMEM: return mem::OUT_OF_MEMORY?;
|
||||
case errno::EOVERFLOW: return RANGE_OVERFLOW?;
|
||||
case errno::EPERM: return ACCESS_DENIED?;
|
||||
case errno::EINVAL: return INVALID_ARGS?;
|
||||
default: return UNKNOWN_ERROR?;
|
||||
case errno::ENOMEM: return mem::OUT_OF_MEMORY~;
|
||||
case errno::EOVERFLOW: return RANGE_OVERFLOW~;
|
||||
case errno::EPERM: return ACCESS_DENIED~;
|
||||
case errno::EINVAL: return INVALID_ARGS~;
|
||||
default: return UNKNOWN_ERROR~;
|
||||
}
|
||||
$case env::WIN32:
|
||||
void* ptr = win32::virtualAlloc(null, aligned_alloc_size(size), MEM_RESERVE, access.to_win32());
|
||||
@@ -66,8 +66,8 @@ fn void*? alloc(usz size, VirtualMemoryAccess access)
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_NOT_ENOUGH_MEMORY:
|
||||
case win32::ERROR_COMMITMENT_LIMIT: return mem::OUT_OF_MEMORY?;
|
||||
default: return UNKNOWN_ERROR?;
|
||||
case win32::ERROR_COMMITMENT_LIMIT: return mem::OUT_OF_MEMORY~;
|
||||
default: return UNKNOWN_ERROR~;
|
||||
}
|
||||
$default:
|
||||
unsupported("Virtual alloc only available on Win32 and Posix");
|
||||
@@ -89,18 +89,18 @@ fn void? release(void* ptr, usz size)
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EINVAL: return INVALID_ARGS?; // Not a valid mapping or size
|
||||
case errno::ENOMEM: return UNMAPPED_ACCESS?; // Address not mapped
|
||||
default: return RELEASE_FAILED?;
|
||||
case errno::EINVAL: return INVALID_ARGS~; // Not a valid mapping or size
|
||||
case errno::ENOMEM: return UNMAPPED_ACCESS~; // Address not mapped
|
||||
default: return RELEASE_FAILED~;
|
||||
}
|
||||
}
|
||||
$case env::WIN32:
|
||||
if (win32::virtualFree(ptr, 0, MEM_RELEASE)) return;
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_INVALID_ADDRESS: return INVALID_ARGS?;
|
||||
case win32::ERROR_NOT_ENOUGH_MEMORY: return mem::OUT_OF_MEMORY?;
|
||||
default: return RELEASE_FAILED?;
|
||||
case win32::ERROR_INVALID_ADDRESS: return INVALID_ARGS~;
|
||||
case win32::ERROR_NOT_ENOUGH_MEMORY: return mem::OUT_OF_MEMORY~;
|
||||
default: return RELEASE_FAILED~;
|
||||
}
|
||||
$default:
|
||||
unsupported("Virtual free only available on Win32 and Posix");
|
||||
@@ -124,21 +124,21 @@ fn void? protect(void* ptr, usz len, VirtualMemoryAccess access)
|
||||
if (!posix::mprotect(ptr, len, access.to_posix())) return;
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EACCES: return ACCESS_DENIED?;
|
||||
case errno::EINVAL: return UNALIGNED_ADDRESS?;
|
||||
case errno::EOVERFLOW: return RANGE_OVERFLOW?;
|
||||
case errno::ENOMEM: return UNMAPPED_ACCESS?;
|
||||
default: return UPDATE_FAILED?;
|
||||
case errno::EACCES: return ACCESS_DENIED~;
|
||||
case errno::EINVAL: return UNALIGNED_ADDRESS~;
|
||||
case errno::EOVERFLOW: return RANGE_OVERFLOW~;
|
||||
case errno::ENOMEM: return UNMAPPED_ACCESS~;
|
||||
default: return UPDATE_FAILED~;
|
||||
}
|
||||
$case env::WIN32:
|
||||
Win32_Protect old;
|
||||
if (win32::virtualProtect(ptr, len, access.to_win32(), &old)) return;
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_INVALID_ADDRESS: return UNALIGNED_ADDRESS?;
|
||||
case win32::ERROR_ACCESS_DENIED: return ACCESS_DENIED?;
|
||||
case win32::ERROR_INVALID_PARAMETER: return INVALID_ARGS?;
|
||||
default: return UPDATE_FAILED?;
|
||||
case win32::ERROR_INVALID_ADDRESS: return UNALIGNED_ADDRESS~;
|
||||
case win32::ERROR_ACCESS_DENIED: return ACCESS_DENIED~;
|
||||
case win32::ERROR_INVALID_PARAMETER: return INVALID_ARGS~;
|
||||
default: return UPDATE_FAILED~;
|
||||
}
|
||||
$default:
|
||||
unsupported("'virtual_protect' is only available on Win32 and Posix.");
|
||||
@@ -165,12 +165,12 @@ fn void? commit(void* ptr, usz len, VirtualMemoryAccess access = READWRITE)
|
||||
if (result) return;
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_INVALID_ADDRESS: return UNALIGNED_ADDRESS?;
|
||||
case win32::ERROR_ACCESS_DENIED: return ACCESS_DENIED?;
|
||||
case win32::ERROR_INVALID_ADDRESS: return UNALIGNED_ADDRESS~;
|
||||
case win32::ERROR_ACCESS_DENIED: return ACCESS_DENIED~;
|
||||
case win32::ERROR_COMMITMENT_LIMIT:
|
||||
case win32::ERROR_NOT_ENOUGH_MEMORY: return mem::OUT_OF_MEMORY?;
|
||||
case win32::ERROR_INVALID_PARAMETER: return INVALID_ARGS?;
|
||||
default: return UNKNOWN_ERROR?;
|
||||
case win32::ERROR_NOT_ENOUGH_MEMORY: return mem::OUT_OF_MEMORY~;
|
||||
case win32::ERROR_INVALID_PARAMETER: return INVALID_ARGS~;
|
||||
default: return UNKNOWN_ERROR~;
|
||||
}
|
||||
$default:
|
||||
unsupported("'virtual_commit' is only available on Win32 and Posix.");
|
||||
@@ -197,9 +197,9 @@ fn void? decommit(void* ptr, usz len, bool block = true)
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EINVAL: return UNALIGNED_ADDRESS?;
|
||||
case errno::ENOMEM: return UNMAPPED_ACCESS?;
|
||||
default: return UPDATE_FAILED?;
|
||||
case errno::EINVAL: return UNALIGNED_ADDRESS~;
|
||||
case errno::ENOMEM: return UNMAPPED_ACCESS~;
|
||||
default: return UPDATE_FAILED~;
|
||||
}
|
||||
}
|
||||
if (block) (void)protect(ptr, len, PROTECTED) @inline;
|
||||
@@ -208,10 +208,10 @@ fn void? decommit(void* ptr, usz len, bool block = true)
|
||||
{
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_INVALID_ADDRESS: return UNALIGNED_ADDRESS?;
|
||||
case win32::ERROR_INVALID_PARAMETER: return INVALID_ARGS?;
|
||||
case win32::ERROR_ACCESS_DENIED: return ACCESS_DENIED?;
|
||||
default: return UPDATE_FAILED?;
|
||||
case win32::ERROR_INVALID_ADDRESS: return UNALIGNED_ADDRESS~;
|
||||
case win32::ERROR_INVALID_PARAMETER: return INVALID_ARGS~;
|
||||
case win32::ERROR_ACCESS_DENIED: return ACCESS_DENIED~;
|
||||
default: return UPDATE_FAILED~;
|
||||
}
|
||||
}
|
||||
$default:
|
||||
@@ -237,15 +237,15 @@ fn void*? mmap_file(Fd fd, usz size, usz offset = 0, VirtualMemoryAccess access
|
||||
if (ptr != posix::MAP_FAILED) return ptr;
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::ENOMEM: return mem::OUT_OF_MEMORY?;
|
||||
case errno::EOVERFLOW: return RANGE_OVERFLOW?;
|
||||
case errno::EPERM: return ACCESS_DENIED?;
|
||||
case errno::EINVAL: return INVALID_ARGS?;
|
||||
case errno::EACCES: return io::NO_PERMISSION?;
|
||||
case errno::EBADF: return io::FILE_NOT_VALID?;
|
||||
case errno::EAGAIN: return io::WOULD_BLOCK?;
|
||||
case errno::ENXIO: return io::FILE_NOT_FOUND?;
|
||||
default: return UNKNOWN_ERROR?;
|
||||
case errno::ENOMEM: return mem::OUT_OF_MEMORY~;
|
||||
case errno::EOVERFLOW: return RANGE_OVERFLOW~;
|
||||
case errno::EPERM: return ACCESS_DENIED~;
|
||||
case errno::EINVAL: return INVALID_ARGS~;
|
||||
case errno::EACCES: return io::NO_PERMISSION~;
|
||||
case errno::EBADF: return io::FILE_NOT_VALID~;
|
||||
case errno::EAGAIN: return io::WOULD_BLOCK~;
|
||||
case errno::ENXIO: return io::FILE_NOT_FOUND~;
|
||||
default: return UNKNOWN_ERROR~;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ fn char[]? WasmMemory.allocate_block(&self, usz bytes)
|
||||
}
|
||||
|
||||
usz blocks_required = (bytes_required + WASM_BLOCK_SIZE + 1) / WASM_BLOCK_SIZE;
|
||||
if ($$wasm_memory_grow(0, blocks_required) == -1) return mem::OUT_OF_MEMORY?;
|
||||
if ($$wasm_memory_grow(0, blocks_required) == -1) return mem::OUT_OF_MEMORY~;
|
||||
self.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE;
|
||||
defer self.use += bytes;
|
||||
return ((char*)self.use)[:bytes];
|
||||
|
||||
@@ -79,7 +79,7 @@ fn SegmentCommand64*? find_segment(MachHeader* header, char* segname)
|
||||
}
|
||||
command = (void*)command + command.cmdsize;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
fn Section64*? find_section(SegmentCommand64* command, char* sectname)
|
||||
{
|
||||
@@ -89,7 +89,7 @@ fn Section64*? find_section(SegmentCommand64* command, char* sectname)
|
||||
if (name_cmp(sectname, §ion.sectname)) return section;
|
||||
section++;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
macro find_segment_section_body(MachHeader* header, char* segname, char* sectname, $Type)
|
||||
|
||||
@@ -12,7 +12,10 @@ macro int @main_to_err_main(#m, int, char**)
|
||||
if (catch #m()) return 1;
|
||||
return 0;
|
||||
}
|
||||
macro int @main_to_int_main(#m, int, char**) => #m();
|
||||
macro int @main_to_int_main(#m, int, char**)
|
||||
{
|
||||
return #m();
|
||||
}
|
||||
macro int @main_to_void_main(#m, int, char**)
|
||||
{
|
||||
#m();
|
||||
@@ -63,6 +66,17 @@ macro int @main_to_void_main_args(#m, int argc, char** argv)
|
||||
}
|
||||
|
||||
module std::core::main_stub @if(env::WIN32);
|
||||
import std::os::win32;
|
||||
|
||||
macro win32_set_utf8_codepage() @local
|
||||
{
|
||||
// By default windows uses an OEM codepage that differs based on locale
|
||||
// and does not support printing utf-8 characters. This allows both
|
||||
// printing utf-8 characters from strings and reading them from stdin.
|
||||
win32::setConsoleCP(UTF8);
|
||||
win32::setConsoleOutputCP(UTF8);
|
||||
}
|
||||
|
||||
|
||||
extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @cname("CommandLineToArgvW");
|
||||
|
||||
@@ -93,18 +107,26 @@ macro void release_wargs(String[] list) @private
|
||||
|
||||
macro int @win_to_err_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
if (catch #m()) return 1;
|
||||
return 0;
|
||||
}
|
||||
macro int @win_to_int_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd) => #m();
|
||||
macro int @win_to_int_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
return #m();
|
||||
}
|
||||
|
||||
macro int @win_to_void_main_noargs(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
#m();
|
||||
return 0;
|
||||
}
|
||||
|
||||
macro int @win_to_err_main_args(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
if (catch #m(args)) return 1;
|
||||
@@ -113,6 +135,7 @@ macro int @win_to_err_main_args(#m, void* handle, void* prev_handle, Char16* cmd
|
||||
|
||||
macro int @win_to_int_main_args(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
return #m(args);
|
||||
@@ -120,6 +143,7 @@ macro int @win_to_int_main_args(#m, void* handle, void* prev_handle, Char16* cmd
|
||||
|
||||
macro int @win_to_void_main_args(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
#m(args);
|
||||
@@ -128,6 +152,7 @@ macro int @win_to_void_main_args(#m, void* handle, void* prev_handle, Char16* cm
|
||||
|
||||
macro int @win_to_err_main(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
if (catch #m(handle, prev_handle, args, show_cmd)) return 1;
|
||||
@@ -136,6 +161,7 @@ macro int @win_to_err_main(#m, void* handle, void* prev_handle, Char16* cmd_line
|
||||
|
||||
macro int @win_to_int_main(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
return #m(handle, prev_handle, args, show_cmd);
|
||||
@@ -143,6 +169,7 @@ macro int @win_to_int_main(#m, void* handle, void* prev_handle, Char16* cmd_line
|
||||
|
||||
macro int @win_to_void_main(#m, void* handle, void* prev_handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
#m(handle, prev_handle, args, show_cmd);
|
||||
@@ -151,6 +178,7 @@ macro int @win_to_void_main(#m, void* handle, void* prev_handle, Char16* cmd_lin
|
||||
|
||||
macro int @wmain_to_err_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
if (catch #m(args)) return 1;
|
||||
@@ -159,6 +187,7 @@ macro int @wmain_to_err_main_args(#m, int argc, Char16** argv)
|
||||
|
||||
macro int @wmain_to_int_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
return #m(args);
|
||||
@@ -166,6 +195,7 @@ macro int @wmain_to_int_main_args(#m, int argc, Char16** argv)
|
||||
|
||||
macro int @_wmain_runner(#m, int argc, Char16** argv)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
return #m(args) ? 0 : 1;
|
||||
@@ -173,6 +203,7 @@ macro int @_wmain_runner(#m, int argc, Char16** argv)
|
||||
|
||||
macro int @wmain_to_void_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
win32_set_utf8_codepage();
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
#m(args);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@require !$defined(Type.dealloc) ||| $defined(Type.dealloc(&&(Type){})) : "'dealloc' must only take a pointer to the underlying type"
|
||||
@require !$defined(Type.dealloc) ||| $typeof((Type){}.dealloc()) == void : "'dealloc' must return 'void'"
|
||||
*>
|
||||
module std::core::mem::ref { Type };
|
||||
module std::core::mem::ref <Type>;
|
||||
import std::thread, std::atomic;
|
||||
|
||||
const OVERALIGNED @private = Type.alignof > mem::DEFAULT_MEM_ALIGNMENT;
|
||||
|
||||
@@ -27,7 +27,7 @@ macro @enum_lookup($Type, #value, value)
|
||||
$foreach $val : $Type.values:
|
||||
if ($val.#value == value) return $val;
|
||||
$endforeach
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
macro @enum_lookup_new($Type, $name, value)
|
||||
@@ -35,7 +35,7 @@ macro @enum_lookup_new($Type, $name, value)
|
||||
$foreach $val : $Type.values:
|
||||
if ($val.$eval($name) == value) return $val;
|
||||
$endforeach
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ struct TestContext
|
||||
bool is_in_panic;
|
||||
bool is_quiet_mode;
|
||||
bool is_no_capture;
|
||||
bool sort;
|
||||
bool check_leaks;
|
||||
String current_test_name;
|
||||
TestFn setup_fn;
|
||||
TestFn teardown_fn;
|
||||
@@ -185,8 +187,6 @@ fn void unmute_output(bool has_error) @local
|
||||
fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
{
|
||||
usz max_name;
|
||||
bool sort_tests = true;
|
||||
bool check_leaks = true;
|
||||
if (!tests.len)
|
||||
{
|
||||
io::printn("There are no test units to run.");
|
||||
@@ -204,6 +204,8 @@ $endif
|
||||
{
|
||||
.assert_print_backtrace = true,
|
||||
.breakpoint_on_assert = false,
|
||||
.sort = true,
|
||||
.check_leaks = true,
|
||||
.log_level = LogPriority.ERROR,
|
||||
.test_filter = "",
|
||||
.has_ansi_codes = terminal_has_ansi_codes(),
|
||||
@@ -218,9 +220,9 @@ $endif
|
||||
case "--test-breakpoint":
|
||||
context.breakpoint_on_assert = true;
|
||||
case "--test-nosort":
|
||||
sort_tests = false;
|
||||
context.sort = false;
|
||||
case "--test-noleak":
|
||||
check_leaks = false;
|
||||
context.check_leaks = false;
|
||||
case "--test-nocapture":
|
||||
case "--test-show-output":
|
||||
context.is_no_capture = true;
|
||||
@@ -261,7 +263,7 @@ $endif
|
||||
test_context = &context;
|
||||
log::set_priority_all(test_context.log_level);
|
||||
|
||||
if (sort_tests)
|
||||
if (context.sort)
|
||||
{
|
||||
quicksort(tests, &cmp_test_unit);
|
||||
}
|
||||
@@ -321,14 +323,17 @@ $endif
|
||||
{
|
||||
mute_output();
|
||||
mem.clear();
|
||||
if (check_leaks) allocator::thread_allocator = &mem;
|
||||
unit.func();
|
||||
if (context.check_leaks) allocator::thread_allocator = &mem;
|
||||
@pool()
|
||||
{
|
||||
unit.func();
|
||||
};
|
||||
// track cleanup that may take place in teardown_fn
|
||||
if (context.teardown_fn)
|
||||
{
|
||||
context.teardown_fn();
|
||||
}
|
||||
if (check_leaks) allocator::thread_allocator = context.stored.allocator;
|
||||
if (context.check_leaks) allocator::thread_allocator = context.stored.allocator;
|
||||
|
||||
unmute_output(false); // all good, discard output
|
||||
if (mem.has_leaks())
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module std::core::array::slice {Type};
|
||||
module std::core::array;
|
||||
|
||||
<*
|
||||
A slice2d allows slicing an array like int[10][10] into an arbitrary "int[][]"-like counterpart
|
||||
Typically you'd use array::slice2d(...) to create one.
|
||||
*>
|
||||
struct Slice2d
|
||||
struct Slice2d <Type>
|
||||
{
|
||||
Type* ptr;
|
||||
usz inner_len;
|
||||
|
||||
@@ -120,7 +120,7 @@ fn String bformat(char[] buffer, String fmt, args...) @format(1)
|
||||
OutputFn format_fn = fn void?(void* buf, char c) {
|
||||
char[]* buffer_ref = buf;
|
||||
char[] buffer = *buffer_ref;
|
||||
if (buffer.len == 0) return io::BUFFER_EXCEEDED?;
|
||||
if (buffer.len == 0) return io::BUFFER_EXCEEDED~;
|
||||
buffer[0] = c;
|
||||
*buffer_ref = buffer[1..];
|
||||
};
|
||||
@@ -190,13 +190,18 @@ fn String join(Allocator allocator, String[] s, String joiner)
|
||||
@param [&inout] allocator : `The allocator to use for the String`
|
||||
@return "The new string with the elements replaced"
|
||||
*>
|
||||
fn String String.replace(self, Allocator allocator, String needle, String new_str) @nodiscard
|
||||
fn String String.replace(self, Allocator allocator, String needle, String new_str) @nodiscard => @pool()
|
||||
{
|
||||
@pool()
|
||||
Splitter s = self.tokenize_all(needle);
|
||||
DString d;
|
||||
d.init(tmem, new_str.len * 2 + self.len + 16);
|
||||
(void)d.append(s.next());
|
||||
while (try element = s.next())
|
||||
{
|
||||
String[] split = self.tsplit(needle);
|
||||
return dstring::join(tmem, split, new_str).copy_str(allocator);
|
||||
};
|
||||
d.append(new_str);
|
||||
d.append(element);
|
||||
}
|
||||
return d.copy_str(allocator);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -209,8 +214,16 @@ fn String String.replace(self, Allocator allocator, String needle, String new_st
|
||||
*>
|
||||
fn String String.treplace(self, String needle, String new_str)
|
||||
{
|
||||
String[] split = self.tsplit(needle);
|
||||
return dstring::join(tmem, split, new_str).str_view();
|
||||
Splitter s = self.tokenize_all(needle);
|
||||
DString d;
|
||||
d.init(tmem, new_str.len * 2 + self.len + 16);
|
||||
(void)d.append(s.next());
|
||||
while (try element = s.next())
|
||||
{
|
||||
d.append(new_str);
|
||||
d.append(element);
|
||||
}
|
||||
return d.str_view();
|
||||
}
|
||||
|
||||
|
||||
@@ -355,7 +368,7 @@ fn String[] String.split(self, Allocator allocator, String delimiter, usz max =
|
||||
bool no_more = false;
|
||||
while (!no_more)
|
||||
{
|
||||
usz? index = i == max - 1 ? NOT_FOUND? : self.index_of(delimiter);
|
||||
usz? index = i == max - 1 ? NOT_FOUND~ : self.index_of(delimiter);
|
||||
String res @noinit;
|
||||
if (try index)
|
||||
{
|
||||
@@ -414,7 +427,7 @@ fn String[]? String.split_to_buffer(s, String delimiter, String[] buffer, usz ma
|
||||
bool no_more = false;
|
||||
while (!no_more)
|
||||
{
|
||||
usz? index = i == max - 1 ? NOT_FOUND? : s.index_of(delimiter);
|
||||
usz? index = i == max - 1 ? NOT_FOUND~ : s.index_of(delimiter);
|
||||
String res @noinit;
|
||||
if (try index)
|
||||
{
|
||||
@@ -432,7 +445,7 @@ fn String[]? String.split_to_buffer(s, String delimiter, String[] buffer, usz ma
|
||||
}
|
||||
if (i == max_capacity)
|
||||
{
|
||||
return BUFFER_EXCEEDED?;
|
||||
return BUFFER_EXCEEDED~;
|
||||
}
|
||||
buffer[i++] = res;
|
||||
}
|
||||
@@ -513,7 +526,7 @@ fn usz? String.index_of_char(self, char character)
|
||||
{
|
||||
if (c == character) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -536,7 +549,7 @@ fn usz? String.index_of_chars(String self, char[] characters)
|
||||
}
|
||||
}
|
||||
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -553,12 +566,12 @@ fn usz? String.index_of_chars(String self, char[] characters)
|
||||
fn usz? String.index_of_char_from(self, char character, usz start_index)
|
||||
{
|
||||
usz len = self.len;
|
||||
if (len <= start_index) return NOT_FOUND?;
|
||||
if (len <= start_index) return NOT_FOUND~;
|
||||
for (usz i = start_index; i < len; i++)
|
||||
{
|
||||
if (self[i] == character) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -577,7 +590,7 @@ fn usz? String.rindex_of_char(self, char character)
|
||||
{
|
||||
if (c == character) return i;
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -602,7 +615,7 @@ fn usz? String.index_of(self, String substr)
|
||||
if (c == first && self[i : needed] == substr) return i;
|
||||
}
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -627,7 +640,7 @@ fn usz? String.rindex_of(self, String substr)
|
||||
if (c == first && self[i : needed] == substr) return i;
|
||||
}
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn bool ZString.eq(self, ZString other) @operator(==)
|
||||
@@ -1013,12 +1026,12 @@ macro String.to_integer(self, $Type, int base = 10)
|
||||
usz index = 0;
|
||||
char* ptr = self.ptr;
|
||||
while (index < len && ptr[index].is_blank()) index++;
|
||||
if (len == index) return EMPTY_STRING?;
|
||||
if (len == index) return EMPTY_STRING~;
|
||||
bool is_negative;
|
||||
switch (self[index])
|
||||
{
|
||||
case '-':
|
||||
if ($Type.min == 0) return NEGATIVE_VALUE?;
|
||||
if ($Type.min == 0) return NEGATIVE_VALUE~;
|
||||
is_negative = true;
|
||||
index++;
|
||||
case '+':
|
||||
@@ -1026,7 +1039,7 @@ macro String.to_integer(self, $Type, int base = 10)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (len == index) return MALFORMED_INTEGER?;
|
||||
if (len == index) return MALFORMED_INTEGER~;
|
||||
$Type base_used = ($Type)base;
|
||||
if (self[index] == '0' && base == 10)
|
||||
{
|
||||
@@ -1049,7 +1062,7 @@ macro String.to_integer(self, $Type, int base = 10)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (len == index) return MALFORMED_INTEGER?;
|
||||
if (len == index) return MALFORMED_INTEGER~;
|
||||
}
|
||||
$Type value = 0;
|
||||
while (index != len)
|
||||
@@ -1059,18 +1072,18 @@ macro String.to_integer(self, $Type, int base = 10)
|
||||
{
|
||||
case base_used < 10 || c < 'A': c -= '0';
|
||||
case c <= 'F': c -= 'A' - 10;
|
||||
case c < 'a' || c > 'f': return MALFORMED_INTEGER?;
|
||||
case c < 'a' || c > 'f': return MALFORMED_INTEGER~;
|
||||
default: c -= 'a' - 10;
|
||||
}
|
||||
if (c >= base_used) return MALFORMED_INTEGER?;
|
||||
if (c >= base_used) return MALFORMED_INTEGER~;
|
||||
do
|
||||
{
|
||||
if (is_negative)
|
||||
{
|
||||
value = value.overflow_mul(base_used).overflow_sub(c) ?? INTEGER_OVERFLOW?!;
|
||||
value = value.overflow_mul(base_used).overflow_sub(c) ?? INTEGER_OVERFLOW~!;
|
||||
break;
|
||||
}
|
||||
value = value.overflow_mul(base_used).overflow_add(c) ?? INTEGER_OVERFLOW?!;
|
||||
value = value.overflow_mul(base_used).overflow_add(c) ?? INTEGER_OVERFLOW~!;
|
||||
};
|
||||
}
|
||||
return value;
|
||||
@@ -1184,16 +1197,21 @@ fn void Splitter.reset(&self)
|
||||
self.current = 0;
|
||||
}
|
||||
|
||||
fn bool Splitter.at_end(&self)
|
||||
{
|
||||
return self.current > self.string.len;
|
||||
}
|
||||
|
||||
fn String? Splitter.next(&self)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
usz len = self.string.len;
|
||||
usz current = self.current;
|
||||
if (current > len) return NO_MORE_ELEMENT?;
|
||||
if (current > len) return NO_MORE_ELEMENT~;
|
||||
if (current == len)
|
||||
{
|
||||
if (self.type != TOKENIZE_ALL) return NO_MORE_ELEMENT?;
|
||||
if (self.type != TOKENIZE_ALL) return NO_MORE_ELEMENT~;
|
||||
self.current++;
|
||||
return self.string[current - 1:0];
|
||||
}
|
||||
@@ -1205,7 +1223,7 @@ fn String? Splitter.next(&self)
|
||||
if (!next && self.type == TOKENIZE) continue;
|
||||
return remaining[:next];
|
||||
}
|
||||
self.current = len;
|
||||
self.current = len + 1;
|
||||
return remaining;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2024-2025 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
|
||||
@@ -22,43 +22,57 @@ faultdef INVALID_ESCAPE_SEQUENCE, UNTERMINATED_STRING, INVALID_HEX_ESCAPE, INVAL
|
||||
*>
|
||||
fn String String.escape(String s, Allocator allocator, bool strip_quotes = true)
|
||||
{
|
||||
// Conservative allocation: most strings need minimal escaping
|
||||
usz initial_capacity = s.len + s.len / 5 + 2; // ~1.2x + quotes
|
||||
DString result = dstring::new_with_capacity(allocator, initial_capacity);
|
||||
// Conservative allocation: most strings need minimal escaping
|
||||
usz initial_capacity = s.len + s.len / 5 + 2; // ~1.2x + quotes
|
||||
|
||||
if (!strip_quotes) result.append_char('"');
|
||||
|
||||
foreach (char c : s)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"': result.append(`\"`);
|
||||
case '\\': result.append(`\\`);
|
||||
case '\b': result.append(`\b`);
|
||||
case '\f': result.append(`\f`);
|
||||
case '\n': result.append(`\n`);
|
||||
case '\r': result.append(`\r`);
|
||||
case '\t': result.append(`\t`);
|
||||
case '\v': result.append(`\v`);
|
||||
case '\0': result.append(`\0`);
|
||||
default:
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
// Printable ASCII
|
||||
result.append_char(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-printable, use hex escape
|
||||
result.appendf("\\x%02x", (uint)c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!strip_quotes) result.append_char('"');
|
||||
return result.copy_str(allocator);
|
||||
if (allocator == tmem)
|
||||
{
|
||||
DString result = dstring::new_with_capacity(tmem, initial_capacity);
|
||||
escape_dstring(s, result, strip_quotes);
|
||||
return result.str_view();
|
||||
}
|
||||
@pool()
|
||||
{
|
||||
DString result = dstring::temp_with_capacity(initial_capacity);
|
||||
escape_dstring(s, result, strip_quotes);
|
||||
return result.copy_str(allocator);
|
||||
};
|
||||
}
|
||||
|
||||
fn void escape_dstring(String s, DString result, bool strip_quotes) @private
|
||||
{
|
||||
if (!strip_quotes) result.append_char('"');
|
||||
|
||||
foreach (char c : s)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"': result.append(`\"`);
|
||||
case '\\': result.append(`\\`);
|
||||
case '\b': result.append(`\b`);
|
||||
case '\f': result.append(`\f`);
|
||||
case '\n': result.append(`\n`);
|
||||
case '\r': result.append(`\r`);
|
||||
case '\t': result.append(`\t`);
|
||||
case '\v': result.append(`\v`);
|
||||
case '\0': result.append(`\0`);
|
||||
default:
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
// Printable ASCII
|
||||
result.append_char(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-printable, use hex escape
|
||||
result.appendf("\\x%02x", (uint)c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!strip_quotes) result.append_char('"');
|
||||
|
||||
}
|
||||
<*
|
||||
Escape a string using the temp allocator.
|
||||
|
||||
@@ -76,33 +90,33 @@ fn String String.tescape(String s, bool strip_quotes = false) => s.escape(tmem,
|
||||
*>
|
||||
fn usz escape_len(String s)
|
||||
{
|
||||
usz len = 2; // For quotes
|
||||
foreach (char c : s)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\0':
|
||||
len += 2; // \X
|
||||
default:
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len += 4; // \xHH
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
usz len = 2; // For quotes
|
||||
foreach (char c : s)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\0':
|
||||
len += 2; // \X
|
||||
default:
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
len += 4; // \xHH
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -111,90 +125,103 @@ fn usz escape_len(String s)
|
||||
@param allocator : "The allocator to use for the result"
|
||||
@param s : "The quoted string to unescape"
|
||||
@param allow_unquoted : "Set to true to unescape strings not surrounded by quotes, defaults to false"
|
||||
@param lenient : "Be lenient with escapes, resolving unknown sequences to the escape character, defaults to false"
|
||||
@return "The unescaped string without quotes, safe to convert to ZString"
|
||||
@return? UNTERMINATED_STRING, INVALID_ESCAPE_SEQUENCE, INVALID_HEX_ESCAPE, INVALID_UNICODE_ESCAPE
|
||||
*>
|
||||
fn String? String.unescape(String s, Allocator allocator, bool allow_unquoted = false)
|
||||
fn String? String.unescape(String s, Allocator allocator, bool allow_unquoted = false, bool lenient = false)
|
||||
{
|
||||
if (s.len >= 2 && s[0] == '"' && s[^1] == '"')
|
||||
{
|
||||
// Remove quotes.
|
||||
s = s[1:^2];
|
||||
}
|
||||
else if (!allow_unquoted) return UNTERMINATED_STRING?;
|
||||
else if (!allow_unquoted) return UNTERMINATED_STRING~;
|
||||
|
||||
// Handle empty string case
|
||||
if (!s.len)
|
||||
{
|
||||
return "".copy(allocator);
|
||||
}
|
||||
|
||||
DString result = dstring::new_with_capacity(allocator, s.len);
|
||||
// Handle empty string case
|
||||
if (!s.len)
|
||||
{
|
||||
return "".copy(allocator);
|
||||
}
|
||||
if (allocator == tmem)
|
||||
{
|
||||
DString result = dstring::new_with_capacity(tmem, s.len);
|
||||
unescape_dstring(s, result, allow_unquoted, lenient)!;
|
||||
return result.str_view();
|
||||
}
|
||||
@pool()
|
||||
{
|
||||
DString result = dstring::temp_with_capacity(s.len);
|
||||
unescape_dstring(s, result, allow_unquoted, lenient)!;
|
||||
return result.copy_str(allocator);
|
||||
};
|
||||
}
|
||||
|
||||
fn void? unescape_dstring(String s, DString result, bool allow_unquoted = false, bool lenient = false) @private
|
||||
{
|
||||
usz len = s.len;
|
||||
for (usz i = 0; i < len; i++)
|
||||
{
|
||||
char c = s[i];
|
||||
if (c != '\\')
|
||||
{
|
||||
result.append_char(c);
|
||||
continue;
|
||||
}
|
||||
if (c != '\\')
|
||||
{
|
||||
result.append_char(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle escape sequence
|
||||
if (i + 1 >= len) return INVALID_ESCAPE_SEQUENCE?;
|
||||
// Handle escape sequence
|
||||
if (i + 1 >= len) return INVALID_ESCAPE_SEQUENCE~;
|
||||
|
||||
char escape_char = s[++i];
|
||||
switch (escape_char)
|
||||
{
|
||||
case '"': result.append_char('"');
|
||||
case '\\': result.append_char('\\');
|
||||
case '/': result.append_char('/');
|
||||
case 'b': result.append_char('\b');
|
||||
case 'f': result.append_char('\f');
|
||||
case 'n': result.append_char('\n');
|
||||
case 'r': result.append_char('\r');
|
||||
case 't': result.append_char('\t');
|
||||
case 'v': result.append_char('\v');
|
||||
case '0': result.append_char('\0');
|
||||
case 'x':
|
||||
// Hex escape \xHH
|
||||
if (i + 2 >= len) return INVALID_HEX_ESCAPE?;
|
||||
char h1 = s[++i];
|
||||
char h2 = s[++i];
|
||||
if (!h1.is_xdigit() || !h2.is_xdigit()) return INVALID_HEX_ESCAPE?;
|
||||
uint val = h1 > '9' ? (h1 | 32) - 'a' + 10 : h1 - '0';
|
||||
val = val << 4;
|
||||
val += h2 > '9' ? (h2 | 32) - 'a' + 10 : h2 - '0';
|
||||
result.append_char((char)val);
|
||||
case 'u':
|
||||
// Unicode escape \uHHHH
|
||||
if (i + 4 >= len) return INVALID_UNICODE_ESCAPE?;
|
||||
uint val;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
char hex_char = s[++i];
|
||||
if (!hex_char.is_xdigit()) return INVALID_UNICODE_ESCAPE?;
|
||||
val = val << 4 + (hex_char > '9' ? (hex_char | 32) - 'a' + 10 : hex_char - '0');
|
||||
}
|
||||
result.append_char32(val);
|
||||
case 'U':
|
||||
// Unicode escape \UHHHHHHHH
|
||||
if (i + 8 >= len) return INVALID_UNICODE_ESCAPE?;
|
||||
uint val;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
char hex_char = s[++i];
|
||||
if (!hex_char.is_xdigit()) return INVALID_UNICODE_ESCAPE?;
|
||||
val = val << 4 + (hex_char > '9' ? (hex_char | 32) - 'a' + 10 : hex_char - '0');
|
||||
}
|
||||
result.append_char32(val);
|
||||
default:
|
||||
return INVALID_ESCAPE_SEQUENCE?;
|
||||
}
|
||||
}
|
||||
|
||||
return result.copy_str(allocator);
|
||||
char escape_char = s[++i];
|
||||
switch (escape_char)
|
||||
{
|
||||
case '"': result.append_char('"');
|
||||
case '\\': result.append_char('\\');
|
||||
case '/': result.append_char('/');
|
||||
case 'b': result.append_char('\b');
|
||||
case 'f': result.append_char('\f');
|
||||
case 'n': result.append_char('\n');
|
||||
case 'r': result.append_char('\r');
|
||||
case 't': result.append_char('\t');
|
||||
case 'v': result.append_char('\v');
|
||||
case '0': result.append_char('\0');
|
||||
case 'x':
|
||||
// Hex escape \xHH
|
||||
if (i + 2 >= len) return INVALID_HEX_ESCAPE~;
|
||||
char h1 = s[++i];
|
||||
char h2 = s[++i];
|
||||
if (!h1.is_xdigit() || !h2.is_xdigit()) return INVALID_HEX_ESCAPE~;
|
||||
uint val = h1 > '9' ? (h1 | 32) - 'a' + 10 : h1 - '0';
|
||||
val = val << 4;
|
||||
val += h2 > '9' ? (h2 | 32) - 'a' + 10 : h2 - '0';
|
||||
result.append_char((char)val);
|
||||
case 'u':
|
||||
// Unicode escape \uHHHH
|
||||
if (i + 4 >= len) return INVALID_UNICODE_ESCAPE~;
|
||||
uint val;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
char hex_char = s[++i];
|
||||
if (!hex_char.is_xdigit()) return INVALID_UNICODE_ESCAPE~;
|
||||
val = val << 4 + (hex_char > '9' ? (hex_char | 32) - 'a' + 10 : hex_char - '0');
|
||||
}
|
||||
result.append_char32(val);
|
||||
case 'U':
|
||||
// Unicode escape \UHHHHHHHH
|
||||
if (i + 8 >= len) return INVALID_UNICODE_ESCAPE~;
|
||||
uint val;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
char hex_char = s[++i];
|
||||
if (!hex_char.is_xdigit()) return INVALID_UNICODE_ESCAPE~;
|
||||
val = val << 4 + (hex_char > '9' ? (hex_char | 32) - 'a' + 10 : hex_char - '0');
|
||||
}
|
||||
result.append_char32(val);
|
||||
default:
|
||||
if (!lenient) return INVALID_ESCAPE_SEQUENCE~;
|
||||
result.append_char(escape_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -202,10 +229,11 @@ fn String? String.unescape(String s, Allocator allocator, bool allow_unquoted =
|
||||
|
||||
@param s : "The quoted string to unescape"
|
||||
@param allow_unquoted : "Set to true to unescape strings not surrounded by quotes, defaults to false"
|
||||
@param lenient : "Be lenient with escapes, resolving unknown sequences to the escape character, defaults to false"
|
||||
@return "The unescaped string without quotes"
|
||||
@return? UNTERMINATED_STRING, INVALID_ESCAPE_SEQUENCE, INVALID_HEX_ESCAPE, INVALID_UNICODE_ESCAPE
|
||||
*>
|
||||
fn String? String.tunescape(String s, bool allow_unquoted = false) => s.unescape(tmem, allow_unquoted);
|
||||
fn String? String.tunescape(String s, bool allow_unquoted = false, bool lenient = false) => s.unescape(tmem, allow_unquoted, lenient);
|
||||
|
||||
<*
|
||||
Check if a character needs to be escaped in a string literal.
|
||||
@@ -215,19 +243,19 @@ fn String? String.tunescape(String s, bool allow_unquoted = false) => s.unescape
|
||||
*>
|
||||
fn bool needs_escape(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\0':
|
||||
return true;
|
||||
default:
|
||||
return c < 32 || c > 126;
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case '\v':
|
||||
case '\0':
|
||||
return true;
|
||||
default:
|
||||
return c < 32 || c > 126;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ fn Char32? StringIterator.next(&self)
|
||||
{
|
||||
usz len = self.utf8.len;
|
||||
usz current = self.current;
|
||||
if (current >= len) return NO_MORE_ELEMENT?;
|
||||
if (current >= len) return NO_MORE_ELEMENT~;
|
||||
usz read = (len - current < 4 ? len - current : 4);
|
||||
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
|
||||
self.current += read;
|
||||
@@ -26,7 +26,7 @@ fn Char32? StringIterator.peek(&self)
|
||||
{
|
||||
usz len = self.utf8.len;
|
||||
usz current = self.current;
|
||||
if (current >= len) return NO_MORE_ELEMENT?;
|
||||
if (current >= len) return NO_MORE_ELEMENT~;
|
||||
usz read = (len - current < 4 ? len - current : 4);
|
||||
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
|
||||
return res;
|
||||
@@ -43,7 +43,7 @@ fn Char32? StringIterator.get(&self)
|
||||
usz current = self.current;
|
||||
usz read = (len - current < 4 ? len - current : 4);
|
||||
usz index = current > read ? current - read : 0;
|
||||
if (index >= len) return NO_MORE_ELEMENT?;
|
||||
if (index >= len) return NO_MORE_ELEMENT~;
|
||||
Char32 res = conv::utf8_to_char32(&self.utf8[index], &read)!;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ macro double? decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
got_rad = true;
|
||||
if (index == last_char)
|
||||
{
|
||||
if (!got_digit) return MALFORMED_FLOAT?;
|
||||
if (!got_digit) return MALFORMED_FLOAT~;
|
||||
return sign * 0.0;
|
||||
}
|
||||
if (index != last_char && (c = chars[++index]) == '0')
|
||||
@@ -83,7 +83,7 @@ macro double? decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
switch
|
||||
{
|
||||
case c == '.':
|
||||
if (got_rad) return MALFORMED_FLOAT?;
|
||||
if (got_rad) return MALFORMED_FLOAT~;
|
||||
got_rad = true;
|
||||
lrp = dc;
|
||||
case k < KMAX - 3:
|
||||
@@ -113,24 +113,24 @@ macro double? decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
c = chars[++index];
|
||||
}
|
||||
if (!got_rad) lrp = dc;
|
||||
if (!got_digit) return MALFORMED_FLOAT?;
|
||||
if (!got_digit) return MALFORMED_FLOAT~;
|
||||
if ((c | 32) == 'e')
|
||||
{
|
||||
if (last_char == index) return MALFORMED_FLOAT?;
|
||||
long e10 = String.to_long((String)chars[index + 1..]) ?? MALFORMED_FLOAT?!;
|
||||
if (last_char == index) return MALFORMED_FLOAT~;
|
||||
long e10 = String.to_long((String)chars[index + 1..]) ?? MALFORMED_FLOAT~!;
|
||||
lrp += e10;
|
||||
}
|
||||
else if (index != last_char)
|
||||
{
|
||||
return MALFORMED_FLOAT?;
|
||||
return MALFORMED_FLOAT~;
|
||||
}
|
||||
// Handle zero specially to avoid nasty special cases later
|
||||
if (!x[0]) return sign * 0.0;
|
||||
|
||||
// Optimize small integers (w/no exponent) and over/under-flow
|
||||
if (lrp == dc && dc < 10 && ($bits > 30 || (ulong)x[0] >> $bits == 0)) return sign * (double)x[0];
|
||||
if (lrp > - $emin / 2) return FLOAT_OUT_OF_RANGE?;
|
||||
if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return FLOAT_OUT_OF_RANGE?;
|
||||
if (lrp > - $emin / 2) return FLOAT_OUT_OF_RANGE~;
|
||||
if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return FLOAT_OUT_OF_RANGE~;
|
||||
|
||||
// Align incomplete final B1B digit
|
||||
if (j)
|
||||
@@ -320,7 +320,7 @@ macro double? decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
y *= 0.5;
|
||||
e2++;
|
||||
}
|
||||
if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return MALFORMED_FLOAT?;
|
||||
if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return MALFORMED_FLOAT~;
|
||||
}
|
||||
return math::scalbn(y, e2);
|
||||
}
|
||||
@@ -351,7 +351,7 @@ macro double? hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
got_rad = true;
|
||||
if (index == last_char)
|
||||
{
|
||||
if (!got_digit) return MALFORMED_FLOAT?;
|
||||
if (!got_digit) return MALFORMED_FLOAT~;
|
||||
return sign * 0.0;
|
||||
}
|
||||
if (index != last_char && (c = chars[++index]) == '0')
|
||||
@@ -369,7 +369,7 @@ macro double? hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
{
|
||||
if (c == '.')
|
||||
{
|
||||
if (got_rad) return MALFORMED_FLOAT?;
|
||||
if (got_rad) return MALFORMED_FLOAT~;
|
||||
got_rad = true;
|
||||
rp = dc;
|
||||
}
|
||||
@@ -393,20 +393,20 @@ macro double? hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
if (index == last_char) break;
|
||||
c = chars[++index];
|
||||
}
|
||||
if (!got_digit) return MALFORMED_FLOAT?;
|
||||
if (!got_digit) return MALFORMED_FLOAT~;
|
||||
if (!got_rad) rp = dc;
|
||||
for (; dc < 8; dc++) x *= 16;
|
||||
|
||||
long e2;
|
||||
if ((c | 32) == 'p')
|
||||
{
|
||||
long e2val = String.to_long((String)chars[index + 1..]) ?? (MALFORMED_FLOAT?)!;
|
||||
long e2val = String.to_long((String)chars[index + 1..]) ?? MALFORMED_FLOAT~!;
|
||||
e2 = e2val;
|
||||
}
|
||||
e2 += 4 * rp - 32;
|
||||
if (!x) return sign * 0.0;
|
||||
if (e2 > -$emin) return FLOAT_OUT_OF_RANGE?;
|
||||
if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return FLOAT_OUT_OF_RANGE?;
|
||||
if (e2 > -$emin) return FLOAT_OUT_OF_RANGE~;
|
||||
if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return FLOAT_OUT_OF_RANGE~;
|
||||
|
||||
while (x < 0x80000000)
|
||||
{
|
||||
@@ -441,7 +441,7 @@ macro double? hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
}
|
||||
y = bias + sign * (double)x + sign * y;
|
||||
y -= bias;
|
||||
if (!y) return FLOAT_OUT_OF_RANGE?;
|
||||
if (!y) return FLOAT_OUT_OF_RANGE~;
|
||||
|
||||
return math::scalbn(y, (int)e2);
|
||||
}
|
||||
@@ -463,7 +463,7 @@ macro String.to_real(chars, $Type) @private
|
||||
$endswitch
|
||||
|
||||
chars = chars.trim();
|
||||
if (!chars.len) return MALFORMED_FLOAT?;
|
||||
if (!chars.len) return MALFORMED_FLOAT~;
|
||||
|
||||
if (chars.len != 1)
|
||||
{
|
||||
@@ -477,7 +477,7 @@ macro String.to_real(chars, $Type) @private
|
||||
}
|
||||
}
|
||||
chars = chars.trim();
|
||||
if (!chars.len) return MALFORMED_FLOAT?;
|
||||
if (!chars.len) return MALFORMED_FLOAT~;
|
||||
|
||||
if (chars == "infinity" || chars == "INFINITY") return sign * $Type.inf;
|
||||
if (chars == "NAN" || chars == "nan") return $Type.nan;
|
||||
|
||||
@@ -12,7 +12,7 @@ faultdef DIVISION_BY_ZERO;
|
||||
|
||||
fn double? divide(int a, int b)
|
||||
{
|
||||
if (b == 0) return MathError.DIVISION_BY_ZERO?;
|
||||
if (b == 0) return MathError.DIVISION_BY_ZERO~;
|
||||
return (double)(a) / (double)(b);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,47 +29,47 @@ macro any_to_int(any v, $Type)
|
||||
{
|
||||
case ichar:
|
||||
ichar c = *(char*)v.ptr;
|
||||
if (is_mixed_signed && c < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (is_mixed_signed && c < 0) return VALUE_OUT_OF_UNSIGNED_RANGE~;
|
||||
return ($Type)c;
|
||||
case short:
|
||||
short s = *(short*)v.ptr;
|
||||
if (is_mixed_signed && s < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (s > max || s < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && s < 0) return VALUE_OUT_OF_UNSIGNED_RANGE~;
|
||||
if (s > max || s < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)s;
|
||||
case int:
|
||||
int i = *(int*)v.ptr;
|
||||
if (is_mixed_signed && i < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && i < 0) return VALUE_OUT_OF_UNSIGNED_RANGE~;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)i;
|
||||
case long:
|
||||
long l = *(long*)v.ptr;
|
||||
if (is_mixed_signed && l < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (l > max || l < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && l < 0) return VALUE_OUT_OF_UNSIGNED_RANGE~;
|
||||
if (l > max || l < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)l;
|
||||
case int128:
|
||||
int128 i = *(int128*)v.ptr;
|
||||
if (is_mixed_signed && i < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && i < 0) return VALUE_OUT_OF_UNSIGNED_RANGE~;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)i;
|
||||
case char:
|
||||
char c = *(char*)v.ptr;
|
||||
if (c > max) return VALUE_OUT_OF_RANGE?;
|
||||
if (c > max) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)c;
|
||||
case ushort:
|
||||
ushort s = *(ushort*)v.ptr;
|
||||
if (s > max || s < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (s > max || s < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)s;
|
||||
case uint:
|
||||
uint i = *(uint*)v.ptr;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)i;
|
||||
case ulong:
|
||||
ulong l = *(ulong*)v.ptr;
|
||||
if (l > max || l < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (l > max || l < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)l;
|
||||
case uint128:
|
||||
uint128 i = *(uint128*)v.ptr;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
|
||||
if (i > max || i < min) return VALUE_OUT_OF_RANGE~;
|
||||
return ($Type)i;
|
||||
default:
|
||||
unreachable();
|
||||
@@ -329,8 +329,8 @@ macro lower_to_atomic_compatible_type($Type) @const
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro bool is_promotable_to_floatlike($Type) @const => types::is_floatlike($Type) || types::is_int($Type);
|
||||
macro bool is_promotable_to_float($Type) @const => types::is_float($Type) || types::is_int($Type);
|
||||
macro bool is_promotable_to_floatlike($Type) @const => types::is_floatlike($Type) ||| types::is_int($Type);
|
||||
macro bool is_promotable_to_float($Type) @const => types::is_float($Type) ||| types::is_int($Type);
|
||||
|
||||
macro bool is_same_vector_type($Type1, $Type2) @const
|
||||
{
|
||||
@@ -345,7 +345,7 @@ macro bool has_equals($Type) @const => $defined(($Type){} == ($Type){});
|
||||
|
||||
macro bool is_equatable_type($Type) @const
|
||||
{
|
||||
$if $defined($Type.less) || $defined($Type.compare_to) || $defined($Type.equals):
|
||||
$if $defined($Type.less) ||| $defined($Type.compare_to) ||| $defined($Type.equals):
|
||||
return true;
|
||||
$else
|
||||
return $Type.is_eq;
|
||||
@@ -357,7 +357,7 @@ macro bool is_equatable_type($Type) @const
|
||||
*>
|
||||
macro bool implements_copy($Type) @const
|
||||
{
|
||||
return $defined($Type.copy) && $defined($Type.free);
|
||||
return $defined($Type.copy) &&& $defined($Type.free);
|
||||
}
|
||||
|
||||
macro bool @equatable_value(#value) @const
|
||||
@@ -367,7 +367,7 @@ macro bool @equatable_value(#value) @const
|
||||
|
||||
macro bool @comparable_value(#value) @const
|
||||
{
|
||||
$if $defined(#value.less) || $defined(#value.compare_to):
|
||||
$if $defined(#value.less) ||| $defined(#value.compare_to):
|
||||
return true;
|
||||
$else
|
||||
return $typeof(#value).is_ordered;
|
||||
|
||||
233
lib/std/crypto/chacha20.c3
Normal file
233
lib/std/crypto/chacha20.c3
Normal file
@@ -0,0 +1,233 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// ChaCha20 code dedicated from repo: https://github.com/NotsoanoNimus/chacha20_aead.c3l (but massively cleaned)
|
||||
module std::crypto::chacha20;
|
||||
|
||||
|
||||
<* The typical cipher block size in bytes. *>
|
||||
const BLOCK_SIZE = 64;
|
||||
|
||||
<* Required key size in bytes. *>
|
||||
const KEY_SIZE = 32;
|
||||
|
||||
<* ChaCha20 "nonce" (initialization vector) size. *>
|
||||
const NONCE_SIZE = 12;
|
||||
|
||||
<* A required ChaCha20 "magic" value used for state initialization. *>
|
||||
const char[] MAGIC = "expand 32-byte k";
|
||||
|
||||
<*
|
||||
Once a single ChaCha20 context has processed this many bytes, a new nonce MUST be used,
|
||||
unless the static `permit_overflow` runtime module variable is set to true.
|
||||
*>
|
||||
const CHACHA20_NONCE_REUSE_LIMIT = 64 * (1ull << 32);
|
||||
|
||||
<*
|
||||
SECURITY WARNING:
|
||||
This boolean should always remain 'false'. If set to 'true', you accept the security
|
||||
implications of nonce re-use caused by an overflow in the cipher's 'counter' field.
|
||||
|
||||
This security warning is only applicable when a single ChaCha20 context is being used
|
||||
to process more than about 256 GiB of data.
|
||||
*>
|
||||
bool permit_overflow = false;
|
||||
|
||||
|
||||
<* A context structure used to track an ongoing ChaCha20 transformation. *>
|
||||
struct ChaCha20
|
||||
{
|
||||
<* The position within a block before permuting the rounds. *>
|
||||
usz position;
|
||||
<* Count of bytes processed. Useful to track an approach to the 256GiB limit of a single context. *>
|
||||
ulong bytes_processed;
|
||||
<* The key stream or state used during cipher block operations. *>
|
||||
uint[16] key_stream @align(ulong.sizeof);
|
||||
<* The secret key for the context. *>
|
||||
char[32] key;
|
||||
<* The one-time nonce (or IV - initialization vector) used for the context. *>
|
||||
char[12] nonce;
|
||||
<* Internal state of the cipher. *>
|
||||
uint[16] state;
|
||||
}
|
||||
|
||||
|
||||
<* The meat and potatoes of the ChaCha20 stream cipher. *>
|
||||
macro quarter_round(uint* x, int a, int b, int c, int d) @local
|
||||
{
|
||||
x[a] += x[b]; x[d] = (x[d] ^ x[a]).rotl(16);
|
||||
x[c] += x[d]; x[b] = (x[b] ^ x[c]).rotl(12);
|
||||
x[a] += x[b]; x[d] = (x[d] ^ x[a]).rotl(8);
|
||||
x[c] += x[d]; x[b] = (x[b] ^ x[c]).rotl(7);
|
||||
}
|
||||
|
||||
<* Process the next (or final) chunk of ingested data. *>
|
||||
fn void ChaCha20.mutate_keystream(&self) @local @inline
|
||||
{
|
||||
self.key_stream[..] = self.state[..];
|
||||
|
||||
for (usz i = 0; i < 10; i++) // unrolling this does not improve performance measurably
|
||||
{
|
||||
quarter_round(&self.key_stream[0], 0, 4, 8, 12);
|
||||
quarter_round(&self.key_stream[0], 1, 5, 9, 13);
|
||||
quarter_round(&self.key_stream[0], 2, 6, 10, 14);
|
||||
quarter_round(&self.key_stream[0], 3, 7, 11, 15);
|
||||
quarter_round(&self.key_stream[0], 0, 5, 10, 15);
|
||||
quarter_round(&self.key_stream[0], 1, 6, 11, 12);
|
||||
quarter_round(&self.key_stream[0], 2, 7, 8, 13);
|
||||
quarter_round(&self.key_stream[0], 3, 4, 9, 14);
|
||||
}
|
||||
|
||||
// NOTE: This would 'feel' like a performance hit, but testing the benchmark doesn't show any noticeable
|
||||
// difference on -O5 between this and a for-loop, or even an unrolled loop with compile-time '$for'.
|
||||
array::@zip_into(self.key_stream[..], self.state[..], fn (a, b) => a + b);
|
||||
|
||||
self.state[12]++; // increment the block counter (rollovers are ok)
|
||||
}
|
||||
|
||||
<*
|
||||
Initialize a ChaCha20 transformation context.
|
||||
|
||||
@param key : `The secret key used for the transformation operation.`
|
||||
@param nonce : `The one-time nonce to use for the transformation operation.`
|
||||
@param counter : `An optional counter value to adjust the stream's position.`
|
||||
|
||||
@require key.len == KEY_SIZE : `Input key slice is not the correct length (32 bytes).`
|
||||
@require nonce.len == NONCE_SIZE : `Input nonce slice is not the correct length (12 bytes).`
|
||||
*>
|
||||
fn void ChaCha20.init(&self, char[KEY_SIZE] key, char[NONCE_SIZE] nonce, uint counter = 0)
|
||||
{
|
||||
// Init block.
|
||||
self.position = BLOCK_SIZE; // start at the "end" of a block on init
|
||||
self.bytes_processed = 0;
|
||||
self.key[..] = key[..];
|
||||
self.nonce[..] = nonce[..];
|
||||
((char*)&self.state[0])[:MAGIC.len] = MAGIC[..];
|
||||
((char*)&self.state[4])[:KEY_SIZE] = key[..];
|
||||
self.state[12] = counter;
|
||||
((char*)&self.state[13])[:NONCE_SIZE] = nonce[..];
|
||||
}
|
||||
|
||||
<*
|
||||
Transform some input data using the current context structure.
|
||||
|
||||
@param[inout] data : `The data to transform (encrypt or decrypt).`
|
||||
*>
|
||||
fn void ChaCha20.transform(&self, char[] data)
|
||||
{
|
||||
if (!data.len) return;
|
||||
|
||||
usz original_length = data.len;
|
||||
char[] key_stream = @as_char_view(self.key_stream);
|
||||
|
||||
// 1. Process remaining bytes in the current keystream block.
|
||||
if (self.position < BLOCK_SIZE)
|
||||
{
|
||||
usz len = data.len < (BLOCK_SIZE - self.position) ? data.len : (BLOCK_SIZE - self.position);
|
||||
for (usz i = 0; i < len; i++) data[i] ^= key_stream[self.position + i];
|
||||
self.position += len;
|
||||
data = data[len..];
|
||||
}
|
||||
|
||||
// 2. Get the amount of bytes offset from the nearest alignment boundary.
|
||||
// Process full blocks at a time, word by word according to the system's architecture.
|
||||
// Any extra bytes on each side are dynamically processed byte-by-byte.
|
||||
usz offset = usz.sizeof - (((usz)data.ptr % usz.sizeof) ?: usz.sizeof);
|
||||
|
||||
for (usz x = offset; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..], x = offset)
|
||||
{
|
||||
self.mutate_keystream();
|
||||
if (offset) foreach (i, &b : data[:offset]) *b ^= key_stream[i];
|
||||
char[] aligned_data = data[offset..];
|
||||
for (; x <= (BLOCK_SIZE - usz.sizeof); x += usz.sizeof)
|
||||
{
|
||||
((usz*)aligned_data.ptr)[x / usz.sizeof] ^= mem::load((usz*)(&key_stream[x]), $align: 1);
|
||||
}
|
||||
for (; x < BLOCK_SIZE; x++) data[x] ^= key_stream[x];
|
||||
}
|
||||
|
||||
// 3. Process any remaining bytes.
|
||||
if (data.len > 0)
|
||||
{
|
||||
self.mutate_keystream();
|
||||
for (usz i = 0; i < data.len; i++) data[i] ^= key_stream[i];
|
||||
self.position = data.len;
|
||||
}
|
||||
|
||||
// All done. Capture the transformed length of data and check limits.
|
||||
self.bytes_processed += original_length;
|
||||
if (@unlikely(self.bytes_processed >= CHACHA20_NONCE_REUSE_LIMIT && !permit_overflow))
|
||||
{
|
||||
abort(
|
||||
"ChaCha20 transform limit (~256 GiB) exceeded. You can set 'chacha20::permit_overflow = true;' at"
|
||||
" runtime to disable this panic, but you accept the terrible SECURITY IMPLICATIONS of doing so."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
<* Destroy the current context structure by zeroing all fields. *>
|
||||
fn void ChaCha20.destroy(&self) => mem::zero_volatile(@as_char_view(*self));
|
||||
|
||||
|
||||
<*
|
||||
Perform an in-place transformation of some data in a buffer, without cloning the data to a new buffer.
|
||||
|
||||
@param[inout] data : `The data to transform (encrypt or decrypt).`
|
||||
@param key : `The secret key used for the transformation operation.`
|
||||
@param nonce : `The one-time nonce to use for the transformation operation.`
|
||||
@param counter : `An optional counter value to adjust the stream's position.`
|
||||
|
||||
@require key.len == KEY_SIZE : `Input key slice is not the correct length (32 bytes).`
|
||||
@require nonce.len == NONCE_SIZE : `Input nonce slice is not the correct length (12 bytes).`
|
||||
*>
|
||||
fn void crypt(char[] data, char[KEY_SIZE] key, char[NONCE_SIZE] nonce, uint counter = 0) @private
|
||||
{
|
||||
if (@unlikely(!data.len)) return;
|
||||
ChaCha20 c @noinit;
|
||||
defer c.destroy();
|
||||
c.init(key, nonce, counter);
|
||||
c.transform(data);
|
||||
}
|
||||
alias encrypt_mut = crypt;
|
||||
alias decrypt_mut = crypt;
|
||||
|
||||
<*
|
||||
Perform a transformation of some data cloned from a source buffer.
|
||||
|
||||
@param[&inout] allocator : `The memory allocator which controls allocation of the cloned input data.`
|
||||
@param[inout] data : `The data to transform (encrypt or decrypt).`
|
||||
@param key : `The secret key used for the transformation operation.`
|
||||
@param nonce : `The one-time nonce to use for the transformation operation.`
|
||||
@param counter : `An optional counter value to adjust the stream's position.`
|
||||
|
||||
@require key.len == KEY_SIZE : `Input key slice is not the correct length (32 bytes).`
|
||||
@require nonce.len == NONCE_SIZE : `Input nonce slice is not the correct length (12 bytes).`
|
||||
*>
|
||||
fn char[] crypt_clone(Allocator allocator, char[] data, char[KEY_SIZE] key, char[NONCE_SIZE] nonce, uint counter = 0) @private
|
||||
{
|
||||
if (@unlikely(!data.len)) return {};
|
||||
char[] buff = allocator::clone_slice(allocator, data);
|
||||
crypt(buff, key, nonce, counter);
|
||||
return buff;
|
||||
}
|
||||
alias encrypt = crypt_clone;
|
||||
alias decrypt = crypt_clone;
|
||||
|
||||
<*
|
||||
Perform a transformation of some data cloned from a source buffer by the temp allocator.
|
||||
|
||||
@param[inout] data : `The data to transform (encrypt or decrypt).`
|
||||
@param key : `The secret key used for the transformation operation.`
|
||||
@param nonce : `The one-time nonce to use for the transformation operation.`
|
||||
@param counter : `An optional counter value to adjust the stream's position.`
|
||||
|
||||
@require key.len == KEY_SIZE : `Input key slice is not the correct length (32 bytes).`
|
||||
@require nonce.len == NONCE_SIZE : `Input nonce slice is not the correct length (12 bytes).`
|
||||
*>
|
||||
fn char[] tcrypt_clone(char[] data, char[KEY_SIZE] key, char[NONCE_SIZE] nonce, uint counter = 0) @private
|
||||
{
|
||||
return crypt_clone(tmem, data, key, nonce, counter);
|
||||
}
|
||||
alias tencrypt = tcrypt_clone;
|
||||
alias tdecrypt = tcrypt_clone;
|
||||
@@ -101,12 +101,12 @@ fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
|
||||
{
|
||||
if (src.len == 0)
|
||||
{
|
||||
if (padding > 0) return encoding::INVALID_PADDING?;
|
||||
if (padding > 0) return encoding::INVALID_PADDING~;
|
||||
break;
|
||||
}
|
||||
if (src[0] == padding) break;
|
||||
buf[i] = alphabet.reverse[src[0]];
|
||||
if (buf[i] == INVALID) return encoding::INVALID_CHARACTER?;
|
||||
if (buf[i] == INVALID) return encoding::INVALID_CHARACTER~;
|
||||
src = src[1..];
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
|
||||
dst[0] = buf[1] >> 2 | buf[0] << 3;
|
||||
n++;
|
||||
default:
|
||||
return encoding::INVALID_CHARACTER?;
|
||||
return encoding::INVALID_CHARACTER~;
|
||||
}
|
||||
if (dst.len < 5) break;
|
||||
dst = dst[5..];
|
||||
|
||||
@@ -87,11 +87,11 @@ fn usz? decode_len(usz n, char padding)
|
||||
usz trailing = n % 4;
|
||||
if (padding)
|
||||
{
|
||||
if (trailing != 0) return encoding::INVALID_PADDING?;
|
||||
if (trailing != 0) return encoding::INVALID_PADDING~;
|
||||
// source size is multiple of 4
|
||||
return dn;
|
||||
}
|
||||
if (trailing == 1) return encoding::INVALID_PADDING?;
|
||||
if (trailing == 1) return encoding::INVALID_PADDING~;
|
||||
return dn + trailing * 3 / 4;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
|
||||
case c1:
|
||||
case c2:
|
||||
case c3:
|
||||
return encoding::INVALID_CHARACTER?;
|
||||
return encoding::INVALID_CHARACTER~;
|
||||
}
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6 | (uint)c3;
|
||||
dst[0] = (char)(group >> 16);
|
||||
@@ -211,7 +211,7 @@ fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
|
||||
src = src[^trailing..];
|
||||
char c0 = alphabet.reverse[src[0]];
|
||||
char c1 = alphabet.reverse[src[1]];
|
||||
if (c0 == 0xFF || c1 == 0xFF) return encoding::INVALID_PADDING?;
|
||||
if (c0 == 0xFF || c1 == 0xFF) return encoding::INVALID_PADDING~;
|
||||
if (!padding)
|
||||
{
|
||||
switch (src.len)
|
||||
@@ -221,7 +221,7 @@ fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
|
||||
dst[0] = (char)(group >> 16);
|
||||
case 3:
|
||||
char c2 = alphabet.reverse[src[2]];
|
||||
if (c2 == 0xFF) return encoding::INVALID_CHARACTER?;
|
||||
if (c2 == 0xFF) return encoding::INVALID_CHARACTER~;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
@@ -235,13 +235,13 @@ fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
|
||||
switch (padding)
|
||||
{
|
||||
case src[2]:
|
||||
if (src[3] != padding) return encoding::INVALID_PADDING?;
|
||||
if (src[3] != padding) return encoding::INVALID_PADDING~;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dn -= 2;
|
||||
case src[3]:
|
||||
char c2 = alphabet.reverse[src[2]];
|
||||
if (c2 == 0xFF) return encoding::INVALID_CHARACTER?;
|
||||
if (c2 == 0xFF) return encoding::INVALID_CHARACTER~;
|
||||
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
|
||||
dst[0] = (char)(group >> 16);
|
||||
dst[1] = (char)(group >> 8);
|
||||
|
||||
@@ -79,7 +79,7 @@ macro void? @each_row(InStream stream, String separator = ",", int max_rows = in
|
||||
if (catch err = s)
|
||||
{
|
||||
if (err == io::EOF) return;
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
@body(s.split(mem, separator));
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ fn usz? decode_bytes(char[] src, char[] dst)
|
||||
{
|
||||
char a = HEXREVERSE[src[j - 1]];
|
||||
char b = HEXREVERSE[src[j]];
|
||||
if (a > 0x0f || b > 0x0f) return encoding::INVALID_CHARACTER?;
|
||||
if (a > 0x0f || b > 0x0f) return encoding::INVALID_CHARACTER~;
|
||||
dst[i] = (a << 4) | b;
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -85,13 +85,13 @@ fn Object*? parse_from_token(JsonContext* context, JsonTokenType token) @local
|
||||
case COMMA:
|
||||
case RBRACE:
|
||||
case RBRACKET:
|
||||
case COLON: return UNEXPECTED_CHARACTER?;
|
||||
case COLON: return UNEXPECTED_CHARACTER~;
|
||||
case STRING: return object::new_string(context.last_string.str_view(), context.allocator);
|
||||
case NUMBER: return object::new_float(context.last_number, context.allocator);
|
||||
case TRUE: return object::new_bool(true);
|
||||
case FALSE: return object::new_bool(false);
|
||||
case NULL: return object::new_null();
|
||||
case EOF: return io::EOF?;
|
||||
case EOF: return io::EOF~;
|
||||
}
|
||||
}
|
||||
fn Object*? parse_any(JsonContext* context) @local
|
||||
@@ -117,7 +117,7 @@ fn JsonTokenType? lex_number(JsonContext *context, char c) @local
|
||||
c = read_next(context)!;
|
||||
if (leading_zero)
|
||||
{
|
||||
if (c.is_digit()) return INVALID_NUMBER?;
|
||||
if (c.is_digit()) return INVALID_NUMBER~;
|
||||
leading_zero = false;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ fn JsonTokenType? lex_number(JsonContext *context, char c) @local
|
||||
t.append(c);
|
||||
c = read_next(context)!;
|
||||
}
|
||||
if (!c.is_digit()) return INVALID_NUMBER?;
|
||||
if (!c.is_digit()) return INVALID_NUMBER~;
|
||||
while (c.is_digit())
|
||||
{
|
||||
t.append(c);
|
||||
@@ -148,7 +148,7 @@ fn JsonTokenType? lex_number(JsonContext *context, char c) @local
|
||||
}
|
||||
}
|
||||
pushback(context, c);
|
||||
double? d = t.str_view().to_double() ?? INVALID_NUMBER?;
|
||||
double? d = t.str_view().to_double() ?? INVALID_NUMBER~;
|
||||
context.last_number = d!;
|
||||
return NUMBER;
|
||||
};
|
||||
@@ -160,14 +160,14 @@ fn Object*? parse_map(JsonContext* context) @local
|
||||
defer catch map.free();
|
||||
JsonTokenType token = advance(context)!;
|
||||
defer context.depth--;
|
||||
if (++context.depth >= max_depth) return json::MAX_DEPTH_REACHED?;
|
||||
if (++context.depth >= max_depth) return json::MAX_DEPTH_REACHED~;
|
||||
|
||||
@stack_mem(256; Allocator mem)
|
||||
{
|
||||
DString temp_key = dstring::new_with_capacity(mem, 32);
|
||||
while (token != JsonTokenType.RBRACE)
|
||||
{
|
||||
if (token != JsonTokenType.STRING) return UNEXPECTED_CHARACTER?;
|
||||
if (token != JsonTokenType.STRING) return UNEXPECTED_CHARACTER~;
|
||||
DString string = context.last_string;
|
||||
// Copy the key to our temp holder, since our
|
||||
// last_string may be used in parse_any
|
||||
@@ -182,7 +182,7 @@ fn Object*? parse_map(JsonContext* context) @local
|
||||
token = advance(context)!;
|
||||
continue;
|
||||
}
|
||||
if (token != JsonTokenType.RBRACE) return UNEXPECTED_CHARACTER?;
|
||||
if (token != JsonTokenType.RBRACE) return UNEXPECTED_CHARACTER~;
|
||||
}
|
||||
return map;
|
||||
};
|
||||
@@ -193,7 +193,7 @@ fn Object*? parse_array(JsonContext* context) @local
|
||||
Object* list = object::new_obj(context.allocator);
|
||||
defer catch list.free();
|
||||
defer context.depth--;
|
||||
if (++context.depth >= max_depth) return json::MAX_DEPTH_REACHED?;
|
||||
if (++context.depth >= max_depth) return json::MAX_DEPTH_REACHED~;
|
||||
JsonTokenType token = advance(context)!;
|
||||
while (token != JsonTokenType.RBRACKET)
|
||||
{
|
||||
@@ -205,7 +205,7 @@ fn Object*? parse_array(JsonContext* context) @local
|
||||
token = advance(context)!;
|
||||
continue;
|
||||
}
|
||||
if (token != JsonTokenType.RBRACKET) return UNEXPECTED_CHARACTER?;
|
||||
if (token != JsonTokenType.RBRACKET) return UNEXPECTED_CHARACTER~;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ fn char? read_next(JsonContext* context) @local
|
||||
context.reached_end = true;
|
||||
return '\0';
|
||||
}
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
if (c == 0)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ fn JsonTokenType? advance(JsonContext* context) @local
|
||||
{
|
||||
char c;
|
||||
// Skip whitespace
|
||||
while WS: (c = read_next(context)!)
|
||||
while WS: ((c = read_next(context)!))
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -272,12 +272,12 @@ fn JsonTokenType? advance(JsonContext* context) @local
|
||||
while COMMENT: (true)
|
||||
{
|
||||
// Skip to */
|
||||
while (c = read_next(context)!)
|
||||
while ((c = read_next(context)!))
|
||||
{
|
||||
if (c == '\n') context.line++;
|
||||
if (c != '*') continue;
|
||||
// Skip through all the '*'
|
||||
while (c = read_next(context)!)
|
||||
while ((c = read_next(context)!))
|
||||
{
|
||||
if (c == '\n') context.line++;
|
||||
if (c != '*') break;
|
||||
@@ -293,7 +293,7 @@ fn JsonTokenType? advance(JsonContext* context) @local
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return io::EOF?;
|
||||
return io::EOF~;
|
||||
case '{':
|
||||
return LBRACE;
|
||||
case '}':
|
||||
@@ -321,7 +321,7 @@ fn JsonTokenType? advance(JsonContext* context) @local
|
||||
match(context, "ull")!;
|
||||
return NULL;
|
||||
default:
|
||||
return UNEXPECTED_CHARACTER?;
|
||||
return UNEXPECTED_CHARACTER~;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,13 +330,13 @@ fn void? match(JsonContext* context, String str) @local
|
||||
foreach (c : str)
|
||||
{
|
||||
char l = read_next(context)!;
|
||||
if (l != c) return UNEXPECTED_CHARACTER?;
|
||||
if (l != c) return UNEXPECTED_CHARACTER~;
|
||||
}
|
||||
}
|
||||
|
||||
fn void? parse_expected(JsonContext* context, JsonTokenType token) @local
|
||||
{
|
||||
if (advance(context)! != token) return UNEXPECTED_CHARACTER?;
|
||||
if (advance(context)! != token) return UNEXPECTED_CHARACTER~;
|
||||
}
|
||||
|
||||
fn JsonTokenType? lex_string(JsonContext* context)
|
||||
@@ -348,9 +348,9 @@ fn JsonTokenType? lex_string(JsonContext* context)
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return io::EOF?;
|
||||
return io::EOF~;
|
||||
case 1..31:
|
||||
return UNEXPECTED_CHARACTER?;
|
||||
return UNEXPECTED_CHARACTER~;
|
||||
case '"':
|
||||
break LOOP;
|
||||
case '\\':
|
||||
@@ -363,9 +363,9 @@ fn JsonTokenType? lex_string(JsonContext* context)
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return io::EOF?;
|
||||
return io::EOF~;
|
||||
case 1..31:
|
||||
return UNEXPECTED_CHARACTER?;
|
||||
return UNEXPECTED_CHARACTER~;
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
@@ -385,13 +385,13 @@ fn JsonTokenType? lex_string(JsonContext* context)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
c = read_next(context)!;
|
||||
if (!c.is_xdigit()) return INVALID_ESCAPE_SEQUENCE?;
|
||||
if (!c.is_xdigit()) return INVALID_ESCAPE_SEQUENCE~;
|
||||
val = val << 4 + (c > '9' ? (c | 32) - 'a' + 10 : c - '0');
|
||||
}
|
||||
context.last_string.append_char32(val);
|
||||
continue;
|
||||
default:
|
||||
return INVALID_ESCAPE_SEQUENCE?;
|
||||
return INVALID_ESCAPE_SEQUENCE~;
|
||||
}
|
||||
context.last_string.append(c);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::experimental::scheduler{Event};
|
||||
module std::experimental::scheduler <Event>;
|
||||
import std::collections, std::thread, std::time;
|
||||
|
||||
struct DelayedSchedulerEvent @local
|
||||
@@ -43,7 +43,7 @@ macro void FrameScheduler.@destroy(&self; @destruct(Event e))
|
||||
self.events.free();
|
||||
self.pending_events.free();
|
||||
self.delayed_events.free();
|
||||
(void)self.mtx.destroy();
|
||||
self.mtx.destroy();
|
||||
}
|
||||
|
||||
fn void FrameScheduler.queue_delayed_event(&self, Event event, Duration delay)
|
||||
@@ -76,7 +76,7 @@ fn Event? FrameScheduler.pop_event(&self)
|
||||
while (true)
|
||||
{
|
||||
if (try event = self.events.pop()) return event;
|
||||
if (!@atomic_load(self.pending)) return NO_MORE_ELEMENT?;
|
||||
if (!@atomic_load(self.pending)) return NO_MORE_ELEMENT~;
|
||||
self.mtx.@in_lock()
|
||||
{
|
||||
self.events.add_all(&self.pending_events);
|
||||
@@ -88,7 +88,7 @@ fn Event? FrameScheduler.pop_event(&self)
|
||||
self.events.push(self.delayed_events.pop()!!);
|
||||
}
|
||||
@atomic_store(self.pending, self.delayed_events.len() > 0);
|
||||
if (!self.events.len()) return NO_MORE_ELEMENT?;
|
||||
if (!self.events.len()) return NO_MORE_ELEMENT~;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ fn ulong hash(char[] data, ulong seed = 0)
|
||||
for (; data.len > 16; data = data[16..])
|
||||
{
|
||||
@a5mul(
|
||||
@unaligned_load(((ulong*)data.ptr)[0], 1) ^ seed1,
|
||||
@unaligned_load(((ulong*)data.ptr)[1], 1) ^ seed2,
|
||||
mem::load((ulong*)data.ptr, 1) ^ seed1,
|
||||
mem::load((ulong*)data.ptr + 1, 1) ^ seed2,
|
||||
seed1, seed2
|
||||
);
|
||||
|
||||
@@ -71,16 +71,16 @@ fn ulong hash(char[] data, ulong seed = 0)
|
||||
seed2 += val10;
|
||||
}
|
||||
|
||||
a = @unaligned_load(*(ulong*)(data.ptr + (uptr)data.len - 16), 1);
|
||||
b = @unaligned_load(*(ulong*)(data.ptr + (uptr)data.len - 8), 1);
|
||||
a = mem::load((ulong*)(data.ptr + (uptr)data.len - 16), 1);
|
||||
b = mem::load((ulong*)(data.ptr + (uptr)data.len - 8), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = ((ulong)@unaligned_load(*(uint*)&data[0], 1) << 32)
|
||||
| @unaligned_load(*(uint*)&data[^4], 1);
|
||||
a = ((ulong)mem::load((uint*)&data[0], 1) << 32)
|
||||
| mem::load((uint*)&data[^4], 1);
|
||||
|
||||
b = ((ulong)@unaligned_load(*(uint*)&data[(data.len >> 3) * 4], 1) << 32)
|
||||
| @unaligned_load(*(uint*)(data.ptr + data.len - 4 - (data.len >> 3) * 4), 1);
|
||||
b = ((ulong)mem::load((uint*)&data[(data.len >> 3) * 4], 1) << 32)
|
||||
| mem::load((uint*)(data.ptr + data.len - 4 - (data.len >> 3) * 4), 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
383
lib/std/hash/blake2.c3
Normal file
383
lib/std/hash/blake2.c3
Normal file
@@ -0,0 +1,383 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// This is based on the original BLAKE2 reference implementation, but it's been
|
||||
// significantly changed. You can really see how C3's features shine over the
|
||||
// original C source.
|
||||
//
|
||||
// You'll note that this may have been better done with generic modules. I'm not
|
||||
// an expert, but I'd argue that it's unnecessary for this particular algorithm.
|
||||
// There are only two important versions of the algorithm to implement in a "common"
|
||||
// (generic) way, and the output size of each type is controlled rather naturally.
|
||||
//
|
||||
module std::hash::blake2;
|
||||
|
||||
|
||||
// Common hash output sizes. The library is NOT limited to these six output sizes, but
|
||||
// these instead stand in for what would have been "magic numbers" throughout the code.
|
||||
const SIZE_128 = 16;
|
||||
const SIZE_160 = 20;
|
||||
const SIZE_224 = 28;
|
||||
const SIZE_256 = 32;
|
||||
const SIZE_384 = 48;
|
||||
const SIZE_512 = 64;
|
||||
|
||||
|
||||
macro @g(r, m, $s, i, #a, #b, #c, #d) @local
|
||||
{
|
||||
// I really dislike using these conditional one-liners, but... it's the only difference between 2s and 2b besides buffer sizes (mainly).
|
||||
#a += #b + m[$s[r][2*i+0]];
|
||||
#d = (#d ^ #a).rotr($sizeof(#a) == ulong.sizeof ??? 32 : 16);
|
||||
#c += #d;
|
||||
#b = (#b ^ #c).rotr($sizeof(#a) == ulong.sizeof ??? 24 : 12);
|
||||
#a += #b + m[$s[r][2*i+1]];
|
||||
#d = (#d ^ #a).rotr($sizeof(#a) == ulong.sizeof ??? 16 : 8);
|
||||
#c += #d;
|
||||
#b = (#b ^ #c).rotr($sizeof(#a) == ulong.sizeof ??? 63 : 7);
|
||||
}
|
||||
|
||||
macro @round(r, m, $s, #v) @local
|
||||
{
|
||||
@g(r, m, $s, 0, #v[ 0], #v[ 4], #v[ 8], #v[12]);
|
||||
@g(r, m, $s, 1, #v[ 1], #v[ 5], #v[ 9], #v[13]);
|
||||
@g(r, m, $s, 2, #v[ 2], #v[ 6], #v[10], #v[14]);
|
||||
@g(r, m, $s, 3, #v[ 3], #v[ 7], #v[11], #v[15]);
|
||||
@g(r, m, $s, 4, #v[ 0], #v[ 5], #v[10], #v[15]);
|
||||
@g(r, m, $s, 5, #v[ 1], #v[ 6], #v[11], #v[12]);
|
||||
@g(r, m, $s, 6, #v[ 2], #v[ 7], #v[ 8], #v[13]);
|
||||
@g(r, m, $s, 7, #v[ 3], #v[ 4], #v[ 9], #v[14]);
|
||||
}
|
||||
|
||||
macro @common_compress(#instance, $rounds, $iv, $sigma, block) @local
|
||||
{
|
||||
$typeof(#instance.h[0])[16] m, v;
|
||||
|
||||
((char*)&m)[:$sizeof(block)] = block[..];
|
||||
|
||||
v[:8] = #instance.h[..];
|
||||
v[ 8] = $iv[0];
|
||||
v[ 9] = $iv[1];
|
||||
v[10] = $iv[2];
|
||||
v[11] = $iv[3];
|
||||
v[12] = $iv[4] ^ #instance.t[0];
|
||||
v[13] = $iv[5] ^ #instance.t[1];
|
||||
v[14] = $iv[6] ^ #instance.f[0];
|
||||
v[15] = $iv[7] ^ #instance.f[1];
|
||||
|
||||
$for usz $i = 0; $i < $rounds; $i++:
|
||||
@round($i, m, $sigma, v);
|
||||
$endfor
|
||||
|
||||
$for usz $i = 0; $i < 8; $i++:
|
||||
#instance.h[$i] ^= v[$i] ^ v[$i + 8];
|
||||
$endfor
|
||||
}
|
||||
|
||||
macro @add_ctr(#instance, usz amount) @local
|
||||
{
|
||||
#instance.t[0] += ($typeof(#instance.t[0]))amount;
|
||||
#instance.t[1] += ($typeof(#instance.t[0]))(#instance.t[0] < amount); // adds 1 on overflow of [0]
|
||||
}
|
||||
|
||||
macro @common_init(#instance, $ParamType, $iv, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {}) @local
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*#instance)); // explicitly because habits around hash init usually involve @noinit
|
||||
|
||||
#instance.h[..] = $iv[..];
|
||||
#instance.outlen = out_len;
|
||||
|
||||
$ParamType p = {
|
||||
.digest_length = (char)out_len,
|
||||
.key_length = (char)key.len,
|
||||
.fanout = 1,
|
||||
.depth = 1,
|
||||
};
|
||||
if (salt.len) p.salt[:salt.len] = salt[..];
|
||||
if (personal.len) p.personal[:personal.len] = personal[..];
|
||||
|
||||
array::@zip_into(((char*)&#instance.h)[:$sizeof(p)], ((char*)&p)[:$sizeof(p)], fn (a, b) => a ^ b); // bytes(self.h) ^= bytes(p)
|
||||
|
||||
if (key.len)
|
||||
{
|
||||
char[$sizeof($iv[0])*16] dummy = {};
|
||||
dummy[:key.len] = key[..];
|
||||
#instance.update(dummy[..]); // consume a FULL block
|
||||
mem::zero_volatile(dummy[..]); // do not optimize clearing this from the stack
|
||||
}
|
||||
}
|
||||
|
||||
macro @common_update(#instance, $block_size, char[] data) @local
|
||||
{
|
||||
if (@unlikely(!data.len)) return;
|
||||
|
||||
usz fill = $block_size - #instance.buflen;
|
||||
if (data.len > fill)
|
||||
{
|
||||
#instance.buf[#instance.buflen:fill] = data[:fill];
|
||||
#instance.buflen = 0;
|
||||
|
||||
@add_ctr(#instance, $block_size);
|
||||
#instance.compress(#instance.buf);
|
||||
|
||||
data = data[fill..];
|
||||
|
||||
for (; data.len > $block_size; data = data[$block_size..])
|
||||
{
|
||||
@add_ctr(#instance, $block_size);
|
||||
#instance.compress(data[:$block_size]);
|
||||
}
|
||||
}
|
||||
#instance.buf[#instance.buflen:data.len] = data[..];
|
||||
#instance.buflen += data.len;
|
||||
}
|
||||
|
||||
macro @common_final(#instance, $output_length) @local
|
||||
{
|
||||
char[$output_length] result = {};
|
||||
if ($output_length != #instance.outlen) return result;
|
||||
|
||||
@add_ctr(#instance, #instance.buflen);
|
||||
if (#instance.f[0]) return result; // technically an error return
|
||||
|
||||
if (#instance.last_node) #instance.f[1] = $typeof(#instance.h[0]).max;
|
||||
#instance.f[0] = $typeof(#instance.h[0]).max;
|
||||
|
||||
mem::zero_volatile(#instance.buf[#instance.buflen..]); // pad buffer with zeroes
|
||||
#instance.compress(#instance.buf);
|
||||
|
||||
defer mem::zero_volatile(@as_char_view(*#instance)); // destroy the current context implicitly
|
||||
|
||||
result[:#instance.outlen] = @as_char_view(#instance.h)[:#instance.outlen];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ======================================================================================
|
||||
// BEGIN Blake2b contents. Do not separate this from Blake2s: there's not really a point.
|
||||
//
|
||||
const BLAKE2B_BLOCKBYTES @local = 128;
|
||||
const BLAKE2B_OUTBYTES @local = 64;
|
||||
const BLAKE2B_KEYBYTES @local = 64;
|
||||
const BLAKE2B_SALTBYTES @local = 16;
|
||||
const BLAKE2B_PERSONALBYTES @local = 16;
|
||||
const ulong[8] BLAKE2B_IV @local = {
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
|
||||
};
|
||||
const char[16][12] BLAKE2B_SIGMA @local = {
|
||||
x'000102030405060708090a0b0c0d0e0f',
|
||||
x'0e0a0408090f0d06010c00020b070503',
|
||||
x'0b080c0005020f0d0a0e030607010904',
|
||||
x'070903010d0c0b0e0206050a04000f08',
|
||||
x'0900050702040a0f0e010b0c0608030d',
|
||||
x'020c060a000b0803040d07050f0e0109',
|
||||
x'0c05010f0e0d040a000706030902080b',
|
||||
x'0d0b070e0c01030905000f040806020a',
|
||||
x'060f0e090b0300080c020d0701040a05',
|
||||
x'0a020804070601050f0b090e030c0d00',
|
||||
x'000102030405060708090a0b0c0d0e0f',
|
||||
x'0e0a0408090f0d06010c00020b070503',
|
||||
};
|
||||
|
||||
struct Blake2b
|
||||
{
|
||||
ulong[8] h;
|
||||
ulong[2] t;
|
||||
ulong[2] f;
|
||||
char[BLAKE2B_BLOCKBYTES] buf;
|
||||
usz buflen;
|
||||
usz outlen;
|
||||
char last_node;
|
||||
}
|
||||
|
||||
struct Blake2bParam @packed @local
|
||||
{
|
||||
char digest_length; /* 1 */
|
||||
char key_length; /* 2 */
|
||||
char fanout; /* 3 */
|
||||
char depth; /* 4 */
|
||||
uint leaf_length; /* 8 */
|
||||
uint node_offset; /* 12 */
|
||||
uint xof_length; /* 16 */
|
||||
char node_depth; /* 17 */
|
||||
char inner_length; /* 18 */
|
||||
char[14] reserved; /* 32 */
|
||||
char[BLAKE2B_SALTBYTES] salt; /* 48 */
|
||||
char[BLAKE2B_PERSONALBYTES] personal; /* 64 */
|
||||
}
|
||||
|
||||
<*
|
||||
@require $defined(data[0]) &&& $typeof(data[0]) == char : "Input data must be a char slice, char array, or string value."
|
||||
*>
|
||||
macro blake2b_hash($out_len, data, char[] key = {}, char[] salt = {})
|
||||
{
|
||||
Blake2b b @noinit;
|
||||
b.init($out_len, key, salt);
|
||||
b.update(data[..]);
|
||||
return b.final($out_len);
|
||||
}
|
||||
alias b = blake2b_hash;
|
||||
|
||||
// See RFC 7693, Section 4 for common parameter sets.
|
||||
macro blake2b_224(data, char[] key = {}, char[] salt = {}) => blake2b_hash(SIZE_224, data, key, salt);
|
||||
macro blake2b_256(data, char[] key = {}, char[] salt = {}) => blake2b_hash(SIZE_256, data, key, salt);
|
||||
macro blake2b_384(data, char[] key = {}, char[] salt = {}) => blake2b_hash(SIZE_384, data, key, salt);
|
||||
macro blake2b_512(data, char[] key = {}, char[] salt = {}) => blake2b_hash(SIZE_512, data, key, salt);
|
||||
|
||||
alias b_224 = blake2b_224;
|
||||
alias b_256 = blake2b_256;
|
||||
alias b_384 = blake2b_384;
|
||||
alias b_512 = blake2b_512;
|
||||
|
||||
<*
|
||||
Blake2b initialization method. Presents various options
|
||||
|
||||
@param out_len : "The desired output length from the hash function."
|
||||
@param[in] key : "An optional key value to use (keys the entire hash value to give HMAC-like functionality)."
|
||||
@param[in] salt : "An optional salt value to use when generating the hash."
|
||||
@param[in] personal : "An optional personalization value to use when generating the hash."
|
||||
|
||||
@require out_len > 0 && out_len <= BLAKE2B_OUTBYTES : "Blake2 output length must be within the proper range."
|
||||
@require !key.ptr || (key.len > 0 && key.len <= BLAKE2B_KEYBYTES) : "A specified key's length must be within the proper range."
|
||||
@require !salt.ptr || (salt.len > 0 && salt.len <= BLAKE2B_SALTBYTES) : "A specified salt's length must be within the proper range."
|
||||
@require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range."
|
||||
*>
|
||||
fn void Blake2b.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {})
|
||||
=> @common_init(self, Blake2bParam, BLAKE2B_IV, out_len, key, salt, personal);
|
||||
|
||||
<*
|
||||
Core compression inline function for Blake2b.
|
||||
*>
|
||||
fn void Blake2b.compress(&self, char[BLAKE2B_BLOCKBYTES] block) @local @inline
|
||||
=> @common_compress(self, 12, BLAKE2B_IV, BLAKE2B_SIGMA, block);
|
||||
|
||||
<*
|
||||
Add more data to the hash context or stream.
|
||||
|
||||
@param[in] data : "The data to ingest into the hash context."
|
||||
*>
|
||||
fn void Blake2b.update(&self, char[] data)
|
||||
=> @common_update(self, BLAKE2B_BLOCKBYTES, data);
|
||||
|
||||
<*
|
||||
Finalize the hash context and return the hash result at the given size.
|
||||
|
||||
@param $output_length : "The length of the output array which is returned by value, instead of as a slice."
|
||||
|
||||
@require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size."
|
||||
*>
|
||||
macro char[*] Blake2b.final(&self, $output_length)
|
||||
=> @common_final(self, $output_length);
|
||||
|
||||
|
||||
// ======================================================================================
|
||||
// BEGIN Blake2s contents. Do not separate this from Blake2b: there's not really a point.
|
||||
//
|
||||
const BLAKE2S_BLOCKBYTES @local = BLAKE2B_BLOCKBYTES / 2;
|
||||
const BLAKE2S_OUTBYTES @local = BLAKE2B_OUTBYTES / 2;
|
||||
const BLAKE2S_KEYBYTES @local = BLAKE2B_KEYBYTES / 2;
|
||||
const BLAKE2S_SALTBYTES @local = BLAKE2B_SALTBYTES / 2;
|
||||
const BLAKE2S_PERSONALBYTES @local = BLAKE2B_PERSONALBYTES / 2;
|
||||
const uint[8] BLAKE2S_IV @local = { 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 };
|
||||
const char[16][10] BLAKE2S_SIGMA @local = {
|
||||
x'000102030405060708090a0b0c0d0e0f',
|
||||
x'0e0a0408090f0d06010c00020b070503',
|
||||
x'0b080c0005020f0d0a0e030607010904',
|
||||
x'070903010d0c0b0e0206050a04000f08',
|
||||
x'0900050702040a0f0e010b0c0608030d',
|
||||
x'020c060a000b0803040d07050f0e0109',
|
||||
x'0c05010f0e0d040a000706030902080b',
|
||||
x'0d0b070e0c01030905000f040806020a',
|
||||
x'060f0e090b0300080c020d0701040a05',
|
||||
x'0a020804070601050f0b090e030c0d00',
|
||||
};
|
||||
|
||||
struct Blake2s
|
||||
{
|
||||
uint[8] h;
|
||||
uint[2] t;
|
||||
uint[2] f;
|
||||
char[BLAKE2S_BLOCKBYTES] buf;
|
||||
usz buflen;
|
||||
usz outlen;
|
||||
char last_node;
|
||||
}
|
||||
|
||||
struct Blake2sParam @packed @local
|
||||
{
|
||||
char digest_length; /* 1 */
|
||||
char key_length; /* 2 */
|
||||
char fanout; /* 3 */
|
||||
char depth; /* 4 */
|
||||
uint leaf_length; /* 8 */
|
||||
uint node_offset; /* 12 */
|
||||
ushort xof_length; /* 14 */
|
||||
char node_depth; /* 15 */
|
||||
char inner_length; /* 16 */
|
||||
char[BLAKE2S_SALTBYTES] salt; /* 24 */
|
||||
char[BLAKE2S_PERSONALBYTES] personal; /* 32 */
|
||||
}
|
||||
|
||||
<*
|
||||
@require $defined(data[0]) &&& $typeof(data[0]) == char : "Input data must be a char slice, char array, or string value."
|
||||
*>
|
||||
macro blake2s_hash($out_len, data, char[] key = {}, char[] salt = {})
|
||||
{
|
||||
Blake2s b @noinit;
|
||||
b.init($out_len, key, salt);
|
||||
b.update(data[..]);
|
||||
return b.final($out_len);
|
||||
}
|
||||
alias s = blake2s_hash;
|
||||
|
||||
// See RFC 7693, Section 4 for common parameter sets.
|
||||
macro blake2s_128(data, char[] key = {}, char[] salt = {}) => blake2s_hash(SIZE_128, data, key, salt);
|
||||
macro blake2s_160(data, char[] key = {}, char[] salt = {}) => blake2s_hash(SIZE_160, data, key, salt);
|
||||
macro blake2s_224(data, char[] key = {}, char[] salt = {}) => blake2s_hash(SIZE_224, data, key, salt);
|
||||
macro blake2s_256(data, char[] key = {}, char[] salt = {}) => blake2s_hash(SIZE_256, data, key, salt);
|
||||
|
||||
alias s_128 = blake2s_128;
|
||||
alias s_160 = blake2s_160;
|
||||
alias s_224 = blake2s_224;
|
||||
alias s_256 = blake2s_256;
|
||||
|
||||
<*
|
||||
Blake2s initialization method. Presents various options
|
||||
|
||||
@param out_len : "The desired output length from the hash function."
|
||||
@param[in] key : "An optional key value to use (keys the entire hash value to give HMAC-like functionality)."
|
||||
@param[in] salt : "An optional salt value to use when generating the hash."
|
||||
@param[in] personal : "An optional personalization value to use when generating the hash."
|
||||
|
||||
@require out_len > 0 && out_len <= BLAKE2S_OUTBYTES : "Blake2 output length must be within the proper range."
|
||||
@require !key.ptr || (key.len > 0 && key.len <= BLAKE2S_KEYBYTES) : "A specified key's length must be within the proper range."
|
||||
@require !salt.ptr || (salt.len > 0 && salt.len <= BLAKE2S_SALTBYTES) : "A specified salt's length must be within the proper range."
|
||||
@require !personal.ptr || (personal.len > 0 && personal.len <= BLAKE2B_PERSONALBYTES) : "A specified personalization's length must be within the proper range."
|
||||
*>
|
||||
fn void Blake2s.init(&self, usz out_len, char[] key = {}, char[] salt = {}, char[] personal = {})
|
||||
=> @common_init(self, Blake2sParam, BLAKE2S_IV, out_len, key, salt, personal);
|
||||
|
||||
<*
|
||||
Core compression inline function for Blake2s.
|
||||
*>
|
||||
fn void Blake2s.compress(&self, char[BLAKE2S_BLOCKBYTES] block) @local @inline
|
||||
=> @common_compress(self, 10, BLAKE2S_IV, BLAKE2S_SIGMA, block);
|
||||
|
||||
<*
|
||||
Add more data to the hash context or stream.
|
||||
|
||||
@param[in] data : "The data to ingest into the hash context."
|
||||
*>
|
||||
fn void Blake2s.update(&self, char[] data)
|
||||
=> @common_update(self, BLAKE2S_BLOCKBYTES, data);
|
||||
|
||||
<*
|
||||
Finalize the hash context and return the hash result at the given size.
|
||||
|
||||
@param $output_length : "The length of the output array which is returned by value, instead of as a slice."
|
||||
|
||||
@require $output_length == self.outlen : "The specified compile-time output size MUST be equal to the initialized output size."
|
||||
*>
|
||||
macro char[*] Blake2s.final(&self, $output_length)
|
||||
=> @common_final(self, $output_length);
|
||||
747
lib/std/hash/blake3.c3
Normal file
747
lib/std/hash/blake3.c3
Normal file
@@ -0,0 +1,747 @@
|
||||
// Copyright (c) 2025-2026 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// This is based on the original BLAKE3 reference implementation:
|
||||
// https://github.com/BLAKE3-team/BLAKE3/blob/master
|
||||
//
|
||||
module std::hash::blake3;
|
||||
|
||||
|
||||
const BLOCK_SIZE = 64;
|
||||
const CHUNK_SIZE = 1024;
|
||||
const KEY_SIZE = 32;
|
||||
const KEY_SIZE_WORDS = KEY_SIZE / uint.sizeof;
|
||||
const OUT_SIZE = 32;
|
||||
const MAX_DEPTH = 54;
|
||||
|
||||
const uint[8] IV = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
const char[16][7] MESSAGE_SCHEDULE = {
|
||||
x'000102030405060708090a0b0c0d0e0f',
|
||||
x'0206030a0700040d010b0c05090e0f08',
|
||||
x'03040a0c0d02070e060509000b0f0801',
|
||||
x'0a070c090e030d0f04000b0205080106',
|
||||
x'0c0d090b0f0a0e080702050300010604',
|
||||
x'090e0b05080c0f010d03000a02060407',
|
||||
x'0b0f0500010908060e0a020c0304070d',
|
||||
};
|
||||
|
||||
|
||||
// Get feature-based optimization options.
|
||||
// For now, none of these are used until there's a chance to explore BLAKE3's (necessary) vectorization optimizations.
|
||||
//
|
||||
<* When true, force the use of slow-but-portable BLAKE3 functions. Do not vectorize the hash function. *>
|
||||
const FORCE_PORTABLE = true; //$feature(BLAKE3_FORCE_PORTABLE); // this is statically set to TRUE for now
|
||||
<* AARCH64: When not big-endian, use Neon. *>
|
||||
const USE_NEON = !FORCE_PORTABLE &&& (env::AARCH64 &&& !env::BIG_ENDIAN);
|
||||
<* Bundling some architecture booleans into one. *>
|
||||
const IS_X86 = !FORCE_PORTABLE &&& (env::X86_64 ||| env::X86);
|
||||
<*
|
||||
The maximum possible degree of parallelization based on the current architecture.
|
||||
This doesn't represent the ACTUAL degree available.
|
||||
*>
|
||||
const MAX_SIMD_DEGREE = IS_X86 ??? 16 : (USE_NEON ??? 4 : 1);
|
||||
<* There are cases in BLAKE3 where, at compile-time, it's necessary to easily get the max degree, or a minimum of 2. *>
|
||||
const MAX_SIMD_DEGREE_OR_2 = @max(MAX_SIMD_DEGREE, 2);
|
||||
|
||||
|
||||
<* Always set to true once BLAKE3 caches some initial CPU details. *>
|
||||
bool cpuinfo_initd @local = false;
|
||||
|
||||
<*
|
||||
Cache some information at runtime about the current processor and platform, as needed for optimizations.
|
||||
*>
|
||||
fn void init_blake3() @local @init
|
||||
{
|
||||
$if IS_X86:
|
||||
cpudetect::x86_initialize_cpu_features(); // query all x86 feature flags, one time
|
||||
$endif
|
||||
cpuinfo_initd = true;
|
||||
}
|
||||
|
||||
<* Check whether a given CPU flag is set (x86/x86_64 only). *>
|
||||
macro bool @check_cpu_flag(X86Feature f) @local @if(IS_X86)
|
||||
=> !!(cpudetect::x86_features & f.ordinal);
|
||||
|
||||
<*
|
||||
Return the actual SIMD degree of the processor at runtime.
|
||||
*>
|
||||
macro @simd_degree() @local
|
||||
{
|
||||
if (!cpuinfo_initd) init_blake3();
|
||||
assert(cpuinfo_initd == true, "Failed to run required BLAKE3 initializations.");
|
||||
|
||||
$switch:
|
||||
$case IS_X86:
|
||||
if (@check_cpu_flag(AVX512F) && @check_cpu_flag(AVX512VL)) return 16;
|
||||
if (@check_cpu_flag(AVX2)) return 8;
|
||||
if (@check_cpu_flag(SSE4_1) || @check_cpu_flag(SSE2)) return 4;
|
||||
$case USE_NEON:
|
||||
return 4;
|
||||
$endswitch
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
<* Flags used during hash computation based on its state. *>
|
||||
enum Blake3Flags : const inline char
|
||||
{
|
||||
CHUNK_START = 1 << 0,
|
||||
CHUNK_END = 1 << 1,
|
||||
PARENT = 1 << 2,
|
||||
ROOT = 1 << 3,
|
||||
KEYED_HASH = 1 << 4,
|
||||
DERIVE_KEY_CONTEXT = 1 << 5,
|
||||
DERIVE_KEY_MATERIAL = 1 << 6,
|
||||
}
|
||||
|
||||
struct Blake3ChunkState @local
|
||||
{
|
||||
uint[8] cv;
|
||||
ulong chunk_counter;
|
||||
char[BLOCK_SIZE] buf;
|
||||
char buf_len;
|
||||
char blocks_compressed;
|
||||
char flags;
|
||||
}
|
||||
|
||||
struct Blake3Output @local
|
||||
{
|
||||
uint[KEY_SIZE_WORDS] input_cv;
|
||||
ulong counter;
|
||||
char[BLOCK_SIZE] block;
|
||||
char block_len;
|
||||
char flags;
|
||||
}
|
||||
|
||||
struct Blake3
|
||||
{
|
||||
uint[KEY_SIZE_WORDS] key;
|
||||
Blake3ChunkState chunk;
|
||||
char cv_stack_len;
|
||||
char[(MAX_DEPTH + 1) * OUT_SIZE] cv_stack;
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Generate an XOF hash based on the given inputs.
|
||||
|
||||
Consider the output hash w/ `seek = 0` and `$out_size = 41`:
|
||||
```
|
||||
2cc39783c223154fea8dfb7c1b1660f2ac2dcbd1c1de8277b0b0dd39b7e50d7d905630c8be290dfcf3
|
||||
```
|
||||
|
||||
Computing with the same input `key` and input `data`, but with a `seek = 3` and `$out_size = 8` yields:
|
||||
```
|
||||
83c223154fea8dfb
|
||||
|
||||
which is a slice cut out from the above hash:
|
||||
2cc397 [83c223154fea8dfb] 7c1b1660f2ac2dcbd1c1de8277b0b0dd39b7e50d7d905630c8be290dfcf3
|
||||
```
|
||||
|
||||
In this way, the XOF primitive that BLAKE3 is built from allows the hash output to be a potentially
|
||||
limitless result that one may slice to their liking using the right parameters.
|
||||
|
||||
@param [in] data : "The data to hash."
|
||||
@param [in] key : "An optional 32-byte key to turn the result into a keyed hash."
|
||||
@param seek : "An optional value specifying the offset into the XOF's yield where the resultant hash should begin."
|
||||
@param $out_size : "An optional value specifying the desired length to slice from the XOF's yield."
|
||||
|
||||
@return "The hash as a character array of `$out_size` bytes."
|
||||
|
||||
@require !key.len || key.len == KEY_SIZE : "Key value must be empty or exactly 32 bytes."
|
||||
@require $out_size > 0 : "You cannot use a zero $out_size."
|
||||
*>
|
||||
macro char[*] hash(char[] data, char[] key = {}, usz seek = 0, usz $out_size = 32)
|
||||
{
|
||||
char[$out_size] result;
|
||||
Blake3 b @noinit;
|
||||
defer b.destroy();
|
||||
b.init(key);
|
||||
b.update(data);
|
||||
b.final(result[..], $out_size, seek);
|
||||
return result;
|
||||
}
|
||||
|
||||
<*
|
||||
Generate a hash from a context string. This call allows one to use the "context" to
|
||||
auto-generate keying material for the resultant hash value. Effectively, this allows for
|
||||
hashes made from data with completely variable-length keys, rather than having a key fixed
|
||||
to 32 bytes. The 'context' nomenclature is from BLAKE3 itself, not my naming.
|
||||
|
||||
@param [in] data : "The data to hash."
|
||||
@param [in] context : "An optional key to turn the result into a keyed hash."
|
||||
@param seek : "An optional value specifying the offset into the XOF's yield where the resultant hash should begin."
|
||||
@param $out_size : "An optional value specifying the desired length to slice from the XOF's yield."
|
||||
|
||||
@return "The context-based hash as a character array of `$out_size` bytes."
|
||||
|
||||
@require $out_size > 0 : "You cannot use a zero $out_size."
|
||||
*>
|
||||
macro char[*] ctx_hash(char[] data, char[] context, usz seek = 0, usz $out_size = 32)
|
||||
{
|
||||
char[$out_size] result;
|
||||
Blake3 b = new_from_context(context);
|
||||
defer b.destroy();
|
||||
b.update(data);
|
||||
b.final(result[..], $out_size, seek);
|
||||
return result;
|
||||
}
|
||||
|
||||
<*
|
||||
Generate a new Blake3 hashing structure from the given context string. The context string
|
||||
acts as a variable-length key to seed the new hash structure, and makes it ready to ingest
|
||||
incoming data with `update`.
|
||||
|
||||
@param [in] context : "The context byte array used to seed the returned Blake3 context."
|
||||
*>
|
||||
macro Blake3 new_from_context(char[] context)
|
||||
{
|
||||
char[KEY_SIZE] context_based_key;
|
||||
defer mem::zero_volatile(context_based_key[..]);
|
||||
|
||||
Blake3 key_from_ctx @noinit;
|
||||
defer key_from_ctx.destroy();
|
||||
key_from_ctx.init(explicit_flags: Blake3Flags.DERIVE_KEY_CONTEXT);
|
||||
key_from_ctx.update(context);
|
||||
key_from_ctx.final(context_based_key[..], KEY_SIZE);
|
||||
|
||||
Blake3 b @noinit;
|
||||
b.init(key: context_based_key[..], explicit_flags: Blake3Flags.DERIVE_KEY_MATERIAL);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Initialize a BLAKE3 context.
|
||||
|
||||
@param [in] key : "An optional key initializer to use."
|
||||
|
||||
@require !key.len || key.len == KEY_SIZE : "An explicit initialization key must be of KEY_SIZE (32 bytes)."
|
||||
*>
|
||||
fn void Blake3.init(&self, char[] key = {}, char explicit_flags = 0)
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*self));
|
||||
|
||||
if (key.len)
|
||||
{
|
||||
foreach (i, &w : self.key) *w = mem::load((uint*)&key[i * $sizeof(self.key[0])], 1);
|
||||
if (!explicit_flags) explicit_flags = Blake3Flags.KEYED_HASH;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.key[..] = IV[..];
|
||||
}
|
||||
|
||||
self.chunk.init(self.key[..], explicit_flags);
|
||||
}
|
||||
|
||||
<*
|
||||
Reset the state of the hashing context, in case it should be reused without reloading the key value.
|
||||
*>
|
||||
fn void Blake3.reset(&self) @local @inline
|
||||
{
|
||||
self.chunk.reset(self.key[..], 0);
|
||||
self.cv_stack_len = 0;
|
||||
}
|
||||
|
||||
<*
|
||||
Private function to merge tree results.
|
||||
*>
|
||||
fn void Blake3.merge_cv_stack(&self, ulong total_len) @local @inline
|
||||
{
|
||||
usz post_merge_stack_len = (usz)@popcnt(total_len);
|
||||
for (; self.cv_stack_len > post_merge_stack_len; self.cv_stack_len--)
|
||||
{
|
||||
char* parent_node = &self.cv_stack[(self.cv_stack_len - 2) * OUT_SIZE];
|
||||
Blake3Output o = parent_output(parent_node, self.key[..], self.chunk.flags);
|
||||
o.chaining_value(parent_node);
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
Private function to add a new tree onto the stack.
|
||||
*>
|
||||
fn void Blake3.push_cv(&self, char* new_cv, ulong chunk_counter) @local @inline
|
||||
{
|
||||
self.merge_cv_stack(chunk_counter);
|
||||
self.cv_stack[self.cv_stack_len * OUT_SIZE : OUT_SIZE] = new_cv[:OUT_SIZE];
|
||||
self.cv_stack_len++;
|
||||
}
|
||||
|
||||
<*
|
||||
Update the hash context by consuming incoming data.
|
||||
|
||||
@param [in] input : "The slice of new data to digest."
|
||||
@param use_tbb : "Should remain `false` until other BLAKE3 optimizations are set up."
|
||||
*>
|
||||
fn void Blake3.update(&self, char[] input, bool use_tbb = false)
|
||||
{
|
||||
if (!input.len) return;
|
||||
|
||||
if (self.chunk.len() > 0)
|
||||
{
|
||||
usz take = min(CHUNK_SIZE - self.chunk.len(), input.len);
|
||||
self.chunk.update(input[:take]);
|
||||
input = input[take..];
|
||||
|
||||
if (!input.len) return;
|
||||
|
||||
char[KEY_SIZE] chunk_cv;
|
||||
Blake3Output o = self.chunk.output();
|
||||
o.chaining_value(&chunk_cv);
|
||||
self.push_cv(&chunk_cv, self.chunk.chunk_counter);
|
||||
self.chunk.reset(self.key[..], self.chunk.chunk_counter + 1);
|
||||
}
|
||||
|
||||
while (input.len > CHUNK_SIZE)
|
||||
{
|
||||
usz subtree_len = @round_down_to_power_of_2(input.len);
|
||||
ulong count_so_far = self.chunk.chunk_counter * CHUNK_SIZE;
|
||||
|
||||
while ((((ulong)(subtree_len - 1)) & count_so_far) != 0) subtree_len /= 2;
|
||||
|
||||
ulong subtree_chunks = subtree_len / CHUNK_SIZE;
|
||||
if (subtree_len <= CHUNK_SIZE)
|
||||
{
|
||||
Blake3ChunkState chunk_state;
|
||||
chunk_state.init(self.key[..], self.chunk.flags);
|
||||
chunk_state.chunk_counter = self.chunk.chunk_counter;
|
||||
chunk_state.update(input[:subtree_len]);
|
||||
char[OUT_SIZE] cv;
|
||||
Blake3Output o = chunk_state.output();
|
||||
o.chaining_value(&cv);
|
||||
self.push_cv(&cv, chunk_state.chunk_counter);
|
||||
}
|
||||
else
|
||||
{
|
||||
char[2 * OUT_SIZE] cv_pair;
|
||||
compress_subtree_to_parent_node(input[:subtree_len], self.key[..], self.chunk.chunk_counter, self.chunk.flags, cv_pair[..], use_tbb);
|
||||
self.push_cv(&cv_pair[0], self.chunk.chunk_counter);
|
||||
self.push_cv(&cv_pair[OUT_SIZE], self.chunk.chunk_counter + (subtree_chunks / 2));
|
||||
}
|
||||
self.chunk.chunk_counter += subtree_chunks;
|
||||
input = input[subtree_len..];
|
||||
}
|
||||
|
||||
if (input.len > 0)
|
||||
{
|
||||
self.chunk.update(input);
|
||||
self.merge_cv_stack(self.chunk.chunk_counter);
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
Yield the results of the hash into a specified output buffer, at the specified length.
|
||||
Note that the `into` slice does not need to be properly cut to receive hash results; it
|
||||
just needs to be wide enough to accommodate `into_len` yielded bytes from the XOF.
|
||||
|
||||
@param [in] into : "The storage buffer for the output hash value. Must be >= `into_len` bytes."
|
||||
@param into_len : "How many bytes to receive from the XOF/hash output."
|
||||
@param seek : "How far into the XOF's yield to begin the stored byte sequence."
|
||||
|
||||
@require into.len >= into_len : "The requested output size must be equal to or less than the size of the output slice."
|
||||
*>
|
||||
fn void Blake3.final(&self, char[] into, usz into_len, usz seek = 0)
|
||||
{
|
||||
if (!into_len) return;
|
||||
|
||||
if (!self.cv_stack_len)
|
||||
{
|
||||
Blake3Output o = self.chunk.output();
|
||||
o.root_bytes(seek, into[:into_len]);
|
||||
return;
|
||||
}
|
||||
|
||||
Blake3Output o @noinit;
|
||||
usz cvs_remaining;
|
||||
if (self.chunk.len() > 0)
|
||||
{
|
||||
cvs_remaining = self.cv_stack_len;
|
||||
o = self.chunk.output();
|
||||
}
|
||||
else
|
||||
{
|
||||
cvs_remaining = (usz)self.cv_stack_len - 2;
|
||||
o = parent_output(&self.cv_stack[cvs_remaining * KEY_SIZE], self.key[..], self.chunk.flags);
|
||||
}
|
||||
|
||||
while (cvs_remaining > 0)
|
||||
{
|
||||
char[BLOCK_SIZE] parent_block;
|
||||
cvs_remaining--;
|
||||
parent_block[:32] = self.cv_stack[cvs_remaining * 32 : 32];
|
||||
o.chaining_value(&parent_block[32]);
|
||||
o = parent_output(&parent_block, self.key[..], self.chunk.flags);
|
||||
}
|
||||
|
||||
o.root_bytes(seek, into[:into_len]);
|
||||
}
|
||||
|
||||
<*
|
||||
Destroy a BLAKE3 hashing context.
|
||||
*>
|
||||
fn void Blake3.destroy(&self) @inline
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*self));
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Initialize a BLAKE3 chunk state.
|
||||
|
||||
@param [in] key
|
||||
@param flags
|
||||
*>
|
||||
fn void Blake3ChunkState.init(&self, uint[] key, char flags) @local @inline
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*self));
|
||||
self.cv[..] = key[..];
|
||||
self.flags = flags;
|
||||
}
|
||||
|
||||
<*
|
||||
Reset a BLAKE3 chunk state.
|
||||
|
||||
@param [in] key
|
||||
@param chunk_counter
|
||||
*>
|
||||
fn void Blake3ChunkState.reset(&self, uint[] key, ulong chunk_counter) @local @inline
|
||||
{
|
||||
self.init(key, self.flags); // maintain its own flags
|
||||
self.chunk_counter = chunk_counter; // update chunk counter
|
||||
}
|
||||
|
||||
<*
|
||||
Get bytes length of consumed data.
|
||||
*>
|
||||
fn usz Blake3ChunkState.len(&self) @operator(len) @local @inline
|
||||
=> (BLOCK_SIZE * (usz)self.blocks_compressed) + (usz)self.buf_len;
|
||||
|
||||
<*
|
||||
Ingest an amount of bytes into the chunk's buffer. NOTE: Doesn't check for underflow.
|
||||
|
||||
@param [in] data : "Data to ingest."
|
||||
*>
|
||||
fn usz Blake3ChunkState.fill_buf(&self, char[] data) @local @inline
|
||||
{
|
||||
usz take = min(BLOCK_SIZE - (usz)self.buf_len, data.len);
|
||||
self.buf[self.buf_len:take] = data[:take];
|
||||
self.buf_len += (char)take;
|
||||
return take;
|
||||
}
|
||||
|
||||
<*
|
||||
Determine whether to set the CHUNK_START flag.
|
||||
*>
|
||||
fn char Blake3ChunkState.maybe_start_flag(&self) @local @inline
|
||||
=> !self.blocks_compressed ? Blake3Flags.CHUNK_START : 0;
|
||||
|
||||
<*
|
||||
Update the chunk with the provided input bytes.
|
||||
|
||||
@param [in] input : "Incoming bytes to update with."
|
||||
*>
|
||||
fn void Blake3ChunkState.update(&self, char[] input) @local
|
||||
{
|
||||
if (self.buf_len)
|
||||
{
|
||||
usz take = self.fill_buf(input);
|
||||
input = input[take..];
|
||||
if (input.len)
|
||||
{
|
||||
compress_in_place(self.cv[..], self.buf[..], BLOCK_SIZE, self.chunk_counter, self.flags | self.maybe_start_flag());
|
||||
self.blocks_compressed++;
|
||||
self.buf_len = 0;
|
||||
self.buf[..] = {};
|
||||
}
|
||||
}
|
||||
for (; input.len > BLOCK_SIZE; self.blocks_compressed++, input = input[BLOCK_SIZE..])
|
||||
{
|
||||
compress_in_place(self.cv[..], input[:BLOCK_SIZE], BLOCK_SIZE, self.chunk_counter, self.flags | self.maybe_start_flag());
|
||||
}
|
||||
self.fill_buf(input);
|
||||
}
|
||||
|
||||
<*
|
||||
Convert the chunk state to an "output" type with the right flags.
|
||||
*>
|
||||
fn Blake3Output Blake3ChunkState.output(&self) @local @inline
|
||||
=> make_output(self.cv[..], &self.buf, self.buf_len, self.chunk_counter, self.flags | self.maybe_start_flag() | Blake3Flags.CHUNK_END);
|
||||
|
||||
<*
|
||||
Generate and initialize an output structure with the provided parameters.
|
||||
|
||||
@param [in] key
|
||||
@param [&in] in_block
|
||||
@param block_len
|
||||
@param counter
|
||||
@param flags
|
||||
*>
|
||||
fn Blake3Output make_output(uint[] key, char* in_block, usz block_len, ulong counter, char flags) @local @noinline
|
||||
{
|
||||
Blake3Output o;
|
||||
o.input_cv[..] = key[..];
|
||||
o.block[..] = in_block[:BLOCK_SIZE];
|
||||
o.block_len = (char)block_len;
|
||||
o.counter = counter;
|
||||
o.flags = flags;
|
||||
return o;
|
||||
}
|
||||
|
||||
<*
|
||||
Auto-generate a parent output structure, pre-initialized with some constant identifiers.
|
||||
|
||||
@param [&in] block
|
||||
@param [in] key
|
||||
@param flags
|
||||
*>
|
||||
macro Blake3Output parent_output(char* block, uint[] key, char flags) @local
|
||||
=> make_output(key, block, BLOCK_SIZE, 0, flags | Blake3Flags.PARENT);
|
||||
|
||||
<*
|
||||
Compress then store the chaining value of the output structure.
|
||||
|
||||
@param [&inout] cv
|
||||
*>
|
||||
macro void Blake3Output.chaining_value(&self, char* cv) @local
|
||||
{
|
||||
uint[KEY_SIZE_WORDS] cv_words;
|
||||
cv_words[..] = self.input_cv[..];
|
||||
compress_in_place(cv_words[..], self.block, self.block_len, self.counter, self.flags);
|
||||
cv[:KEY_SIZE] = @as_char_view(cv_words)[:KEY_SIZE];
|
||||
}
|
||||
|
||||
<*
|
||||
Store the result of the output into the designated slice.
|
||||
|
||||
@param seek
|
||||
@param [inout] into
|
||||
*>
|
||||
fn void Blake3Output.root_bytes(&self, usz seek, char[] into) @local
|
||||
{
|
||||
if (!into.len) return;
|
||||
|
||||
ulong output_block_counter = seek / BLOCK_SIZE;
|
||||
usz offset_within_block = seek % BLOCK_SIZE;
|
||||
char[BLOCK_SIZE] wide_buf;
|
||||
|
||||
if (offset_within_block)
|
||||
{
|
||||
compress_xof(self.input_cv[..], self.block, self.block_len, output_block_counter, self.flags | Blake3Flags.ROOT, wide_buf[..]);
|
||||
usz avail = BLOCK_SIZE - offset_within_block;
|
||||
usz bytes = min(into.len, avail);
|
||||
into[:bytes] = wide_buf[offset_within_block:bytes];
|
||||
into = into[bytes..];
|
||||
output_block_counter++;
|
||||
}
|
||||
if (into.len / BLOCK_SIZE)
|
||||
{
|
||||
@xof_many(self.input_cv[..], self.block, self.block_len, output_block_counter, self.flags | Blake3Flags.ROOT, into, into.len / BLOCK_SIZE);
|
||||
}
|
||||
output_block_counter += into.len / 64;
|
||||
into = into[(usz)(into.len & -64ll) ..];
|
||||
if (into.len)
|
||||
{
|
||||
compress_xof(self.input_cv[..], self.block, self.block_len, output_block_counter, self.flags | Blake3Flags.ROOT, wide_buf[..]);
|
||||
into[..] = wide_buf[:into.len];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =================================================================================================
|
||||
// =================================================================================================
|
||||
// =================================================================================================
|
||||
// WELCOME TO THE COMPUTATION GARDEN...
|
||||
//
|
||||
// You wanna understand BLAKE3? You gotta get through us.
|
||||
// ______________________________
|
||||
// ༼ ºل͟º ༼ ºل͟º ༼ ºل͟º ༽ ºل͟º ༽ ºل͟º ༽
|
||||
//
|
||||
//
|
||||
macro uint @popcnt(#x) @local => (uint)#x.popcount();
|
||||
macro uint @highest_one(#x) @local => 63 ^ (uint)#x.clz();
|
||||
macro usz @round_down_to_power_of_2(#x) @local => (usz)1 << @highest_one(#x | 1);
|
||||
|
||||
macro left_subtree_len(usz input_len) @local
|
||||
=> @round_down_to_power_of_2((input_len - 1) / CHUNK_SIZE) * CHUNK_SIZE;
|
||||
|
||||
|
||||
macro @g(#state, a, b, c, d, x, y) @local
|
||||
{
|
||||
#state[a] += #state[b] + x;
|
||||
#state[d] = (#state[d] ^ #state[a]).rotr(16);
|
||||
#state[c] += #state[d];
|
||||
#state[b] = (#state[b] ^ #state[c]).rotr(12);
|
||||
#state[a] += #state[b] + y;
|
||||
#state[d] = (#state[d] ^ #state[a]).rotr(8);
|
||||
#state[c] += #state[d];
|
||||
#state[b] = (#state[b] ^ #state[c]).rotr(7);
|
||||
}
|
||||
|
||||
macro @round(uint[] state, uint* msg, usz round) @local
|
||||
{
|
||||
char* schedule = &MESSAGE_SCHEDULE[round];
|
||||
@g(state, 0, 4, 8, 12, msg[schedule[0] ], msg[schedule[1] ]);
|
||||
@g(state, 1, 5, 9, 13, msg[schedule[2] ], msg[schedule[3] ]);
|
||||
@g(state, 2, 6, 10, 14, msg[schedule[4] ], msg[schedule[5] ]);
|
||||
@g(state, 3, 7, 11, 15, msg[schedule[6] ], msg[schedule[7] ]);
|
||||
@g(state, 0, 5, 10, 15, msg[schedule[8] ], msg[schedule[9] ]);
|
||||
@g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]);
|
||||
@g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]);
|
||||
@g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]);
|
||||
}
|
||||
|
||||
fn void compress_pre(uint[] state, uint[] cv, char[BLOCK_SIZE] block, usz block_len, ulong counter, char flags) @local @noinline
|
||||
{
|
||||
uint[16] block_words @noinit;
|
||||
foreach (i, &b : block_words) *b = mem::load((uint*)&block[i * 4], 1);
|
||||
state[0:8] = cv[0:8];
|
||||
state[8:4] = IV[0:4];
|
||||
state[12] = (uint)counter;
|
||||
state[13] = (uint)(counter >> 32);
|
||||
state[14] = (uint)block_len;
|
||||
state[15] = (uint)flags;
|
||||
@round(state, &block_words[0], 0);
|
||||
@round(state, &block_words[0], 1);
|
||||
@round(state, &block_words[0], 2);
|
||||
@round(state, &block_words[0], 3);
|
||||
@round(state, &block_words[0], 4);
|
||||
@round(state, &block_words[0], 5);
|
||||
@round(state, &block_words[0], 6);
|
||||
}
|
||||
|
||||
macro compress_in_place(uint[] cv, char[BLOCK_SIZE] block, usz block_len, ulong counter, char flags) @local
|
||||
{
|
||||
uint[16] state @noinit;
|
||||
compress_pre(state[..], cv, block, block_len, counter, flags);
|
||||
for (usz i = 0; i < 8; i++) cv[i] = state[i] ^ state[i + 8];
|
||||
}
|
||||
|
||||
macro compress_xof(uint[] cv, char[BLOCK_SIZE] block, usz block_len, ulong counter, char flags, char[] out) @local
|
||||
{
|
||||
uint[16] state @noinit;
|
||||
compress_pre(state[..], cv, block, block_len, counter, flags);
|
||||
$for usz $i = 0; $i < 8; $i++: mem::store((uint*)&out[4 * $i], state[$i] ^ state[$i + 8], 1); $endfor
|
||||
$for usz $i = 0; $i < 8; $i++: mem::store((uint*)&out[4 * (8 + $i)], state[$i + 8] ^ cv[$i], 1); $endfor
|
||||
}
|
||||
|
||||
macro @xof_many(uint[] cv, char[BLOCK_SIZE] block, usz block_len, ulong counter, char flags, char[] out, usz out_blocks) @local
|
||||
{
|
||||
for (usz i = 0; i < out_blocks; i++, out = out[BLOCK_SIZE..]) compress_xof(cv, block, block_len, counter + i, flags, out);
|
||||
}
|
||||
|
||||
macro hash_one(char* input, usz blocks, uint[] key, ulong counter, char flags, char flags_start, char flags_end, char[] out) @local
|
||||
{
|
||||
uint[8] cv;
|
||||
cv[..] = key[..];
|
||||
char block_flags = flags | flags_start;
|
||||
for (; blocks > 0; input += BLOCK_SIZE, blocks--, block_flags = flags)
|
||||
{
|
||||
if (blocks == 1) block_flags |= flags_end;
|
||||
compress_in_place(cv[..], input[:BLOCK_SIZE], BLOCK_SIZE, counter, block_flags);
|
||||
}
|
||||
foreach (i, c : cv) mem::store((uint*)&out[i * 4], c, 1);
|
||||
}
|
||||
|
||||
macro hash_many(char*[] inputs, usz num_inputs, usz blocks, uint[] key, ulong counter, bool $increment_counter, char flags, char flags_start, char flags_end, char* out) @local
|
||||
{
|
||||
for (; num_inputs > 0; num_inputs--, inputs = inputs[1..], out += OUT_SIZE)
|
||||
{
|
||||
hash_one(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out[:OUT_SIZE]);
|
||||
$if $increment_counter: counter++; $endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn void compress_subtree_to_parent_node(char[] input, uint[] key, ulong chunk_counter, char flags, char[] out, bool use_tbb) @local @noinline
|
||||
{
|
||||
char[MAX_SIMD_DEGREE_OR_2 * OUT_SIZE] cv_array;
|
||||
|
||||
usz num_cvs = compress_subtree_wide(input, key, chunk_counter, flags, cv_array[..], use_tbb);
|
||||
assert(num_cvs <= 2);
|
||||
|
||||
$if MAX_SIMD_DEGREE_OR_2 > 2:
|
||||
char[MAX_SIMD_DEGREE_OR_2 * OUT_SIZE / 2] out_array;
|
||||
while (num_cvs > 2) num_cvs = compress_parents_parallel(cv_array[..], num_cvs, key, flags, &out_array);
|
||||
$endif
|
||||
|
||||
out[..] = cv_array[:2 * OUT_SIZE];
|
||||
}
|
||||
|
||||
fn usz compress_subtree_wide(char[] input, uint[] key, ulong chunk_counter, char flags, char* out, bool use_tbb) @local @noinline
|
||||
{
|
||||
if (input.len <= @simd_degree() * CHUNK_SIZE) return compress_chunks_parallel(input, key, chunk_counter, flags, out);
|
||||
|
||||
usz left_input_len = left_subtree_len(input.len);
|
||||
usz right_input_len = input.len - left_input_len;
|
||||
char* right_input = &input[left_input_len];
|
||||
ulong right_chunk_counter = chunk_counter + (ulong)(left_input_len / CHUNK_SIZE);
|
||||
|
||||
char[2 * MAX_SIMD_DEGREE_OR_2 * OUT_SIZE] cv_array;
|
||||
usz degree = @simd_degree();
|
||||
if (left_input_len > CHUNK_SIZE && degree == 1) degree = 2;
|
||||
char* right_cvs = &cv_array[degree * OUT_SIZE];
|
||||
|
||||
usz left_n = compress_subtree_wide(input[:left_input_len], key, chunk_counter, flags, &cv_array, use_tbb);
|
||||
usz right_n = compress_subtree_wide(right_input[:right_input_len], key, right_chunk_counter, flags, right_cvs, use_tbb);
|
||||
|
||||
if (left_n == 1)
|
||||
{
|
||||
out[:2 * OUT_SIZE] = cv_array[:2 * OUT_SIZE];
|
||||
return 2;
|
||||
}
|
||||
|
||||
return compress_parents_parallel(cv_array[..], left_n + right_n, key, flags, out);
|
||||
}
|
||||
|
||||
fn usz compress_parents_parallel(char[] child_chaining_values, usz num_chaining_values, uint[] key, char flags, char* out) @local @noinline
|
||||
{
|
||||
char*[MAX_SIMD_DEGREE_OR_2] parents_array;
|
||||
usz parents_array_len = 0;
|
||||
|
||||
while (num_chaining_values - (2 * parents_array_len) >= 2)
|
||||
{
|
||||
parents_array[parents_array_len++] = &child_chaining_values[2 * parents_array_len * OUT_SIZE];
|
||||
}
|
||||
|
||||
hash_many(parents_array[:parents_array_len], parents_array_len, 1, key, 0, false, flags | Blake3Flags.PARENT, 0, 0, out);
|
||||
|
||||
if (num_chaining_values > 2 * parents_array_len)
|
||||
{
|
||||
out[parents_array_len * OUT_SIZE : OUT_SIZE] = child_chaining_values[2 * parents_array_len * OUT_SIZE : OUT_SIZE];
|
||||
return parents_array_len + 1;
|
||||
}
|
||||
|
||||
return parents_array_len;
|
||||
}
|
||||
|
||||
fn usz compress_chunks_parallel(char[] input, uint[] key, ulong chunk_counter, char flags, char* out) @local @noinline
|
||||
{
|
||||
char*[MAX_SIMD_DEGREE] chunks_array;
|
||||
usz input_position = 0;
|
||||
usz chunks_array_len = 0;
|
||||
|
||||
for (; input.len - input_position >= CHUNK_SIZE; input_position += CHUNK_SIZE)
|
||||
{
|
||||
chunks_array[chunks_array_len++] = &input[input_position];
|
||||
}
|
||||
|
||||
hash_many(chunks_array[:chunks_array_len], chunks_array_len, CHUNK_SIZE / BLOCK_SIZE, key, chunk_counter, true, flags, Blake3Flags.CHUNK_START, Blake3Flags.CHUNK_END, out);
|
||||
|
||||
if (input.len <= input_position) return chunks_array_len;
|
||||
|
||||
ulong counter = chunk_counter + (ulong)chunks_array_len;
|
||||
Blake3ChunkState chunk_state;
|
||||
chunk_state.init(key, flags);
|
||||
chunk_state.chunk_counter = counter;
|
||||
chunk_state.update(input[input_position : input.len - input_position]);
|
||||
Blake3Output o = chunk_state.output();
|
||||
o.chaining_value(&out[chunks_array_len * OUT_SIZE]);
|
||||
|
||||
return chunks_array_len + 1;
|
||||
}
|
||||
169
lib/std/hash/gost/streebog.c3
Normal file
169
lib/std/hash/gost/streebog.c3
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// An implementation of Streebog-256 and Streebog-512, defined in the
|
||||
// Russian standard GOST R 34.11-2012. Also known as "GOST-12".
|
||||
//
|
||||
module std::hash::streebog;
|
||||
|
||||
|
||||
enum StreebogLength : const inline uint
|
||||
{
|
||||
SIZE_256 = 32,
|
||||
SIZE_512 = 64,
|
||||
}
|
||||
|
||||
struct Streebog
|
||||
{
|
||||
ulong[8] h;
|
||||
ulong[8] n;
|
||||
ulong[8] s;
|
||||
ulong[8] message;
|
||||
usz index;
|
||||
usz hash_size;
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
@require $defined(data[0]) &&& $typeof(data[0]) == char : "Input data must be a char slice, char array, or string value."
|
||||
*>
|
||||
macro char[*] hash(StreebogLength $hash_size, data)
|
||||
{
|
||||
// TODO: The speed of this hash hinges on use of >>> SIMD instructions <<<. It would be nice to have some added.
|
||||
Streebog s @noinit;
|
||||
s.init($hash_size);
|
||||
s.update(data);
|
||||
return s.final($hash_size);
|
||||
}
|
||||
|
||||
macro char[*] hash_256(char[] data) => hash(SIZE_256, data);
|
||||
macro char[*] hash_512(char[] data) => hash(SIZE_512, data);
|
||||
|
||||
|
||||
macro @xor_512(#x, #y, #z) @local
|
||||
{
|
||||
$for var $i = 0; $i < 8; $i++:
|
||||
#z[$i] = #x[$i] ^ #y[$i];
|
||||
$endfor
|
||||
}
|
||||
|
||||
macro @add_512(#sum, #x) @local
|
||||
{
|
||||
ulong carry = 0;
|
||||
$for usz $i = 0; $i < 8; $i++:
|
||||
#sum[$i] += #x[$i] + carry;
|
||||
carry = #sum[$i] < #x[$i] ? 1 : (#sum[$i] == #x[$i] ? carry : 0);
|
||||
$endfor
|
||||
}
|
||||
|
||||
macro @lpsx(#a, #b, #result) @local
|
||||
{
|
||||
ulong[8] z @noinit;
|
||||
@xor_512(#a, #b, z);
|
||||
// Do not unroll these loops - produces far too much code at compile-time.
|
||||
for (usz i = 0; i < 8; i++)
|
||||
{
|
||||
#result[i] = TR[0][(z[0] >> (i << 3)) & 0xff];
|
||||
for (usz j = 1; j < 8; j++) #result[i] ^= TR[j][(z[j] >> (i << 3)) & 0xff];
|
||||
}
|
||||
}
|
||||
|
||||
macro @g_n(#n, #h, #m) @local
|
||||
{
|
||||
ulong[8] k_i;
|
||||
ulong[8] state;
|
||||
|
||||
@lpsx(#h, #n, k_i);
|
||||
@lpsx(k_i, #m, state);
|
||||
// Do not unroll this loop - produces far too much code at compile-time.
|
||||
for (usz i = 0; i < 11; i++)
|
||||
{
|
||||
@lpsx(k_i, ITERATION_CONSTANTS[i], k_i);
|
||||
@lpsx(k_i, state, state);
|
||||
}
|
||||
@lpsx(k_i, ITERATION_CONSTANTS[11], k_i);
|
||||
@xor_512(k_i, state, state);
|
||||
@xor_512(state, #h, state);
|
||||
@xor_512(state, #m, #h);
|
||||
}
|
||||
|
||||
|
||||
macro Streebog.@stage2(&self, #m) @local
|
||||
{
|
||||
@g_n(self.n, self.h, #m);
|
||||
@add_512(self.n, STAGE2_512);
|
||||
@add_512(self.s, #m);
|
||||
}
|
||||
|
||||
macro void Streebog.init(&self, StreebogLength $hash_size)
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*self)); // explicitly initialize the entire state to 0
|
||||
self.hash_size = $hash_size;
|
||||
$if $hash_size != SIZE_512:
|
||||
@as_char_view(self.h)[..] = (char[*]){ [0..63] = 0x01 }[..];
|
||||
$endif
|
||||
}
|
||||
|
||||
fn void Streebog.update(&self, char[] data)
|
||||
{
|
||||
if (self.index)
|
||||
{
|
||||
usz rest = BLOCK_SIZE - self.index;
|
||||
usz size = data.len;
|
||||
usz len = size < rest ? size : rest;
|
||||
|
||||
@as_char_view(self.message)[self.index:len] = data[:len];
|
||||
self.index += size;
|
||||
if (size < rest) return;
|
||||
|
||||
self.@stage2(self.message);
|
||||
data = data[rest..];
|
||||
self.index = 0;
|
||||
}
|
||||
bool aligned = 0 == (usz)data.ptr % ulong.sizeof;
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..])
|
||||
{
|
||||
if (aligned)
|
||||
{
|
||||
self.@stage2((ulong*)data.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@as_char_view(self.message)[:BLOCK_SIZE] = data[:BLOCK_SIZE];
|
||||
self.@stage2(self.message);
|
||||
}
|
||||
}
|
||||
if (data.len)
|
||||
{
|
||||
self.index = data.len;
|
||||
@as_char_view(self.message)[:data.len] = data[..];
|
||||
}
|
||||
}
|
||||
|
||||
<*
|
||||
@require $hash_size == self.hash_size : "You must use the same output hash size as was initialized with the context."
|
||||
*>
|
||||
macro char[*] Streebog.final(&self, StreebogLength $hash_size)
|
||||
{
|
||||
char[$hash_size] result;
|
||||
ulong[8] unprocessed_bits_count;
|
||||
usz index = self.index >> 3;
|
||||
usz shift = (self.index & 0b111) * 8;
|
||||
|
||||
unprocessed_bits_count[0] = self.index * 8;
|
||||
self.message[index] &= ~(ulong.max << shift);
|
||||
self.message[index++] ^= 1ul << shift;
|
||||
if (index < 8) self.message[index..] = {};
|
||||
|
||||
@g_n(self.n, self.h, self.message);
|
||||
@add_512(self.n, unprocessed_bits_count);
|
||||
@add_512(self.s, self.message);
|
||||
@g_n(ZERO_512, self.h, self.n);
|
||||
@g_n(ZERO_512, self.h, self.s);
|
||||
|
||||
defer mem::zero_volatile(@as_char_view(*self)); // implicitly clear the structure when finalized
|
||||
|
||||
result[..] = @as_char_view(self.h)[(BLOCK_SIZE - $hash_size)..];
|
||||
return result;
|
||||
}
|
||||
305
lib/std/hash/gost/streebog_internal.c3
Normal file
305
lib/std/hash/gost/streebog_internal.c3
Normal file
@@ -0,0 +1,305 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// An implementation of Streebog-256 and Streebog-512, defined in the
|
||||
// Russian standard GOST R 34.11-2012. Also known as "GOST-12".
|
||||
//
|
||||
module std::hash::streebog @private;
|
||||
|
||||
|
||||
const usz BLOCK_SIZE = 64;
|
||||
|
||||
const ulong[8] ZERO_512 @align(ulong.sizeof) = {};
|
||||
|
||||
const ulong[8] STAGE2_512 @align(ulong.sizeof) = { [0] = 512ul, [1..7] = 0 };
|
||||
|
||||
const ulong[8][12] ITERATION_CONSTANTS @align(ulong.sizeof) = {
|
||||
{ 0xdd806559f2a64507, 0x05767436cc744d23, 0xa2422a08a460d315, 0x4b7ce09192676901, 0x714eb88d7585c4fc, 0x2f6a76432e45d016, 0xebcb2f81c0657c1f, 0xb1085bda1ecadae9 },
|
||||
{ 0xe679047021b19bb7, 0x55dda21bd7cbcd56, 0x5cb561c2db0aa7ca, 0x9ab5176b12d69958, 0x61d55e0f16b50131, 0xf3feea720a232b98, 0x4fe39d460f70b5d7, 0x6fa3b58aa99d2f1a },
|
||||
{ 0x991e96f50aba0ab2, 0xc2b6f443867adb31, 0xc1c93a376062db09, 0xd3e20fe490359eb1, 0xf2ea7514b1297b7b, 0x06f15e5f529c1f8b, 0x0a39fc286a3d8435, 0xf574dcac2bce2fc7 },
|
||||
{ 0x220cbebc84e3d12e, 0x3453eaa193e837f1, 0xd8b71333935203be, 0xa9d72c82ed03d675, 0x9d721cad685e353f, 0x488e857e335c3c7d, 0xf948e1a05d71e4dd, 0xef1fdfb3e81566d2 },
|
||||
{ 0x601758fd7c6cfe57, 0x7a56a27ea9ea63f5, 0xdfff00b723271a16, 0xbfcd1747253af5a3, 0x359e35d7800fffbd, 0x7f151c1f1686104a, 0x9a3f410c6ca92363, 0x4bea6bacad474799 },
|
||||
{ 0xfa68407a46647d6e, 0xbf71c57236904f35, 0x0af21f66c2bec6b6, 0xcffaa6b71c9ab7b4, 0x187f9ab49af08ec6, 0x2d66c4f95142a46c, 0x6fa4c33b7a3039c0, 0xae4faeae1d3ad3d9 },
|
||||
{ 0x8886564d3a14d493, 0x3517454ca23c4af3, 0x06476983284a0504, 0x0992abc52d822c37, 0xd3473e33197a93c9, 0x399ec6c7e6bf87c9, 0x51ac86febf240954, 0xf4c70e16eeaac5ec },
|
||||
{ 0xa47f0dd4bf02e71e, 0x36acc2355951a8d9, 0x69d18d2bd1a5c42f, 0xf4892bcb929b0690, 0x89b4443b4ddbc49a, 0x4eb7f8719c36de1e, 0x03e7aa020c6e4141, 0x9b1f5b424d93c9a7 },
|
||||
{ 0x7261445183235adb, 0x0e38dc92cb1f2a60, 0x7b2b8a9aa6079c54, 0x800a440bdbb2ceb1, 0x3cd955b7e00d0984, 0x3a7d3a1b25894224, 0x944c9ad8ec165fde, 0x378f5a541631229b },
|
||||
{ 0x74b4c7fb98459ced, 0x3698fad1153bb6c3, 0x7a1e6c303b7652f4, 0x9fe76702af69334b, 0x1fffe18a1b336103, 0x8941e71cff8a78db, 0x382ae548b2e4f3f3, 0xabbedea680056f52 },
|
||||
{ 0x6bcaa4cd81f32d1b, 0xdea2594ac06fd85d, 0xefbacd1d7d476e98, 0x8a1d71efea48b9ca, 0x2001802114846679, 0xd8fa6bbbebab0761, 0x3002c6cd635afe94, 0x7bcd9ed0efc889fb },
|
||||
{ 0x48bc924af11bd720, 0xfaf417d5d9b21b99, 0xe71da4aa88e12852, 0x5d80ef9d1891cc86, 0xf82012d430219f9b, 0xcda43c32bcdf1d77, 0xd21380b00449b17a, 0x378ee767f11631ba }
|
||||
};
|
||||
|
||||
const ulong[256][8] TR @align(ulong.sizeof) = {
|
||||
{
|
||||
0xd01f715b5c7ef8e6, 0x16fa240980778325, 0xa8a42e857ee049c8, 0x6ac1068fa186465b, 0x6e417bd7a2e9320b, 0x665c8167a437daab, 0x7666681aa89617f6, 0x4b959163700bdcf5,
|
||||
0xf14be6b78df36248, 0xc585bd689a625cff, 0x9557d7fca67d82cb, 0x89f0b969af6dd366, 0xb0833d48749f6c35, 0xa1998c23b1ecbc7c, 0x8d70c431ac02a736, 0xd6dfbc2fd0a8b69e,
|
||||
0x37aeb3e551fa198b, 0x0b7d128a40b5cf9c, 0x5a8f2008b5780cbc, 0xedec882284e333e5, 0xd25fc177d3c7c2ce, 0x5e0f5d50b61778ec, 0x1d873683c0c24cb9, 0xad040bcbb45d208c,
|
||||
0x2f89a0285b853c76, 0x5732fff6791b8d58, 0x3e9311439ef6ec3f, 0xc9183a809fd3c00f, 0x83adf3f5260a01ee, 0xa6791941f4e8ef10, 0x103ae97d0ca1cd5d, 0x2ce948121dee1b4a,
|
||||
0x39738421dbf2bf53, 0x093da2a6cf0cf5b4, 0xcd9847d89cbcb45f, 0xf9561c078b2d8ae8, 0x9c6a755a6971777f, 0xbc1ebaa0712ef0c5, 0x72e61542abf963a6, 0x78bb5fde229eb12e,
|
||||
0x14ba94250fceb90d, 0x844d6697630e5282, 0x98ea08026a1e032f, 0xf06bbea144217f5c, 0xdb6263d11ccb377a, 0x641c314b2b8ee083, 0x320e96ab9b4770cf, 0x1ee7deb986a96b85,
|
||||
0xe96cf57a878c47b5, 0xfdd6615f8842feb8, 0xc83862965601dd1b, 0x2ea9f83e92572162, 0xf876441142ff97fc, 0xeb2c455608357d9d, 0x5612a7e0b0c9904c, 0x6c01cbfb2d500823,
|
||||
0x4548a6a7fa037a2d, 0xabc4c6bf388b6ef4, 0xbade77d4fdf8bebd, 0x799b07c8eb4cac3a, 0x0c9d87e805b19cf0, 0xcb588aac106afa27, 0xea0c1d40c1e76089, 0x2869354a1e816f1a,
|
||||
0xff96d17307fbc490, 0x9f0a9d602f1a5043, 0x96373fc6e016a5f7, 0x5292dab8b3a6e41c, 0x9b8ae0382c752413, 0x4f15ec3b7364a8a5, 0x3fb349555724f12b, 0xc7c50d4415db66d7,
|
||||
0x92b7429ee379d1a7, 0xd37f99611a15dfda, 0x231427c05e34a086, 0xa439a96d7b51d538, 0xb403401077f01865, 0xdda2aea5901d7902, 0x0a5d4a9c8967d288, 0xc265280adf660f93,
|
||||
0x8bb0094520d4e94e, 0x2a29856691385532, 0x42a833c5bf072941, 0x73c64d54622b7eb2, 0x07e095624504536c, 0x8a905153e906f45a, 0x6f6123c16b3b2f1f, 0xc6e55552dc097bc3,
|
||||
0x4468feb133d16739, 0xe211e7f0c7398829, 0xa2f96419f7879b40, 0x19074bdbc3ad38e9, 0xf4ebc3f9474e0b0c, 0x43886bd376d53455, 0xd8028beb5aa01046, 0x51f23282f5cdc320,
|
||||
0xe7b1c2be0d84e16d, 0x081dfab006dee8a0, 0x3b33340d544b857b, 0x7f5bcabc679ae242, 0x0edd37c48a08a6d8, 0x81ed43d9a9b33bc6, 0xb1a3655ebd4d7121, 0x69a1eeb5e7ed6167,
|
||||
0xf6ab73d5c8f73124, 0x1a67a3e185c61fd5, 0x2dc91004d43c065e, 0x0240b02c8fb93a28, 0x90f7f2b26cc0eb8f, 0x3cd3a16f114fd617, 0xaae49ea9f15973e0, 0x06c0cd748cd64e78,
|
||||
0xda423bc7d5192a6e, 0xc345701c16b41287, 0x6d2193ede4821537, 0xfcf639494190e3ac, 0x7c3b228621f1c57e, 0xfb16ac2b0494b0c0, 0xbf7e529a3745d7f9, 0x6881b6a32e3f7c73,
|
||||
0xca78d2bad9b8e733, 0xbbfe2fc2342aa3a9, 0x0dbddffecc6381e4, 0x70a6a56e2440598e, 0xe4d12a844befc651, 0x8c509c2765d0ba22, 0xee8c6018c28814d9, 0x17da7c1f49a59e31,
|
||||
0x609c4c1328e194d3, 0xb3e3d57232f44b09, 0x91d7aaa4a512f69b, 0x0ffd6fd243dabbcc, 0x50d26a943c1fde34, 0x6be15e9968545b4f, 0x94778fea6faf9fdf, 0x2b09dd7058ea4826,
|
||||
0x677cd9716de5c7bf, 0x49d5214fffb2e6dd, 0x0360e83a466b273c, 0x1fc786af4f7b7691, 0xa0b9d435783ea168, 0xd49f0c035f118cb6, 0x01205816c9d21d14, 0xac2453dd7d8f3d98,
|
||||
0x545217cc3f70aa64, 0x26b4028e9489c9c2, 0xdec2469fd6765e3e, 0x04807d58036f7450, 0xe5f17292823ddb45, 0xf30b569b024a5860, 0x62dcfc3fa758aefb, 0xe84cad6c4e5e5aa1,
|
||||
0xccb81fce556ea94b, 0x53b282ae7a74f908, 0x1b47fbf74c1402c1, 0x368eebf39828049f, 0x7afbeff2ad278b06, 0xbe5e0a8cfe97caed, 0xcfd8f7f413058e77, 0xf78b2bc301252c30,
|
||||
0x4d555c17fcdd928d, 0x5f2f05467fc565f8, 0x24f4b2a21b30f3ea, 0x860dd6bbecb768aa, 0x4c750401350f8f99, 0x0000000000000000, 0xecccd0344d312ef1, 0xb5231806be220571,
|
||||
0xc105c030990d28af, 0x653c695de25cfd97, 0x159acc33c61ca419, 0xb89ec7f872418495, 0xa9847693b73254dc, 0x58cf90243ac13694, 0x59efc832f3132b80, 0x5c4fed7c39ae42c4,
|
||||
0x828dabe3efd81cfa, 0xd13f294d95ace5f2, 0x7d1b7a90e823d86a, 0xb643f03cf849224d, 0x3df3f979d89dcb03, 0x7426d836272f2dde, 0xdfe21e891fa4432a, 0x3a136c1b9d99986f,
|
||||
0xfa36f43dcd46add4, 0xc025982650df35bb, 0x856d3e81aadc4f96, 0xc4a5e57e53b041eb, 0x4708168b75ba4005, 0xaf44bbe73be41aa4, 0x971767d029c4b8e3, 0xb9be9feebb939981,
|
||||
0x215497ecd18d9aae, 0x316e7e91dd2c57f3, 0xcef8afe2dad79363, 0x3853dc371220a247, 0x35ee03c9de4323a3, 0xe6919aa8c456fc79, 0xe05157dc4880b201, 0x7bdbb7e464f59612,
|
||||
0x127a59518318f775, 0x332ecebd52956ddb, 0x8f30741d23bb9d1e, 0xd922d3fd93720d52, 0x7746300c61440ae2, 0x25d4eab4d2e2eefe, 0x75068020eefd30ca, 0x135a01474acaea61,
|
||||
0x304e268714fe4ae7, 0xa519f17bb283c82c, 0xdc82f6b359cf6416, 0x5baf781e7caa11a8, 0xb2c38d64fb26561d, 0x34ce5bdf17913eb7, 0x5d6fb56af07c5fd0, 0x182713cd0a7f25fd,
|
||||
0x9e2ac576e6c84d57, 0x9aaab82ee5a73907, 0xa3d93c0f3e558654, 0x7e7b92aaae48ff56, 0x872d8ead256575be, 0x41c8dbfff96c0e7d, 0x99ca5014a3cc1e3b, 0x40e883e930be1369,
|
||||
0x1ca76e95091051ad, 0x4e35b42dbab6b5b1, 0x05a0254ecabd6944, 0xe1710fca8152af15, 0xf22b0e8dcb984574, 0xb763a82a319b3f59, 0x63fca4296e8ab3ef, 0x9d4a2d4ca0a36a6b,
|
||||
0xe331bfe60eeb953d, 0xd5bf541596c391a2, 0xf5cb9bef8e9c1618, 0x46284e9dbc685d11, 0x2074cffa185f87ba, 0xbd3ee2b6b8fcedd1, 0xae64e3f1f23607b0, 0xfeb68965ce29d984,
|
||||
0x55724fdaf6a2b770, 0x29496d5cd753720e, 0xa75941573d3af204, 0x8e102c0bea69800a, 0x111ab16bc573d049, 0xd7ffe439197aab8a, 0xefac380e0b5a09cd, 0x48f579593660fbc9,
|
||||
0x22347fd697e6bd92, 0x61bc1405e13389c7, 0x4ab5c975b9d9c1e1, 0x80cd1bcf606126d2, 0x7186fd78ed92449a, 0x93971a882aabccb3, 0x88d0e17f66bfce72, 0x27945a985d5bd4d6
|
||||
},
|
||||
{
|
||||
0xde553f8c05a811c8, 0x1906b59631b4f565, 0x436e70d6b1964ff7, 0x36d343cb8b1e9d85, 0x843dfacc858aab5a, 0xfdfc95c299bfc7f9, 0x0f634bdea1d51fa2, 0x6d458b3b76efb3cd,
|
||||
0x85c3f77cf8593f80, 0x3c91315fbe737cb2, 0x2148b03366ace398, 0x18f8b8264c6761bf, 0xc830c1c495c9fb0f, 0x981a76102086a0aa, 0xaa16012142f35760, 0x35cc54060c763cf6,
|
||||
0x42907d66cc45db2d, 0x8203d44b965af4bc, 0x3d6f3cefc3a0e868, 0xbc73ff69d292bda7, 0x8722ed0102e20a29, 0x8f8185e8cd34deb7, 0x9b0561dda7ee01d9, 0x5335a0193227fad6,
|
||||
0xc9cecc74e81a6fd5, 0x54f5832e5c2431ea, 0x99e47ba05d553470, 0xf7bee756acd226ce, 0x384e05a5571816fd, 0xd1367452a47d0e6a, 0xf29fde1c386ad85b, 0x320c77316275f7ca,
|
||||
0xd0c879e2d9ae9ab0, 0xdb7406c69110ef5d, 0x45505e51a2461011, 0xfc029872e46c5323, 0xfa3cb6f5f7bc0cc5, 0x031f17cd8768a173, 0xbd8df2d9af41297d, 0x9d3b4f5ab43e5e3f,
|
||||
0x4071671b36feee84, 0x716207e7d3e3b83d, 0x48d20ff2f9283a1a, 0x27769eb4757cbc7e, 0x5c56ebc793f2e574, 0xa48b474f9ef5dc18, 0x52cbada94ff46e0c, 0x60c7da982d8199c6,
|
||||
0x0e9d466edc068b78, 0x4eec2175eaf865fc, 0x550b8e9e21f7a530, 0x6b7ba5bc653fec2b, 0x5eb7f1ba6949d0dd, 0x57ea94e3db4c9099, 0xf640eae6d101b214, 0xdd4a284182c0b0bb,
|
||||
0xff1d8fbf6304f250, 0xb8accb933bf9d7e8, 0xe8867c478eb68c4d, 0x3f8e2692391bddc1, 0xcb2fd60912a15a7c, 0xaec935dbab983d2f, 0xf55ffd2b56691367, 0x80e2ce366ce1c115,
|
||||
0x179bf3f8edb27e1d, 0x01fe0db07dd394da, 0xda8a0b76ecc37b87, 0x44ae53e1df9584cb, 0xb310b4b77347a205, 0xdfab323c787b8512, 0x3b511268d070b78e, 0x65e6e3d2b9396753,
|
||||
0x6864b271e2574d58, 0x259784c98fc789d7, 0x02e11a7dfabb35a9, 0x8841a6dfa337158b, 0x7ade78c39b5dcdd0, 0xb7cf804d9a2cc84a, 0x20b6bd831b7f7742, 0x75bd331d3a88d272,
|
||||
0x418f6aab4b2d7a5e, 0xd9951cbb6babdaf4, 0xb6318dfde7ff5c90, 0x1f389b112264aa83, 0x492c024284fbaec0, 0xe33a0363c608f9a0, 0x2688930408af28a4, 0xc7538a1a341ce4ad,
|
||||
0x5da8e677ee2171ae, 0x8c9e92254a5c7fc4, 0x63d8cd55aae938b5, 0x29ebd8daa97a3706, 0x959827b37be88aa1, 0x1484e4356adadf6e, 0xa7945082199d7d6b, 0xbf6ce8a455fa1cd4,
|
||||
0x9cc542eac9edcae5, 0x79c16f0e1c356ca3, 0x89bfab6fdee48151, 0xd4174d1830c5f0ff, 0x9258048415eb419d, 0x6139d72850520d1c, 0x6a85a80c18ec78f1, 0xcd11f88e0171059a,
|
||||
0xcceff53e7ca29140, 0xd229639f2315af19, 0x90b91ef9ef507434, 0x5977d28d074a1be1, 0x311360fce51d56b9, 0xc093a92d5a1f2f91, 0x1a19a25bb6dc5416, 0xeb996b8a09de2d3e,
|
||||
0xfee3820f1ed7668a, 0xd7085ad5b7ad518c, 0x7fff41890fe53345, 0xec5948bd67dde602, 0x2fd5f65dbaaa68e0, 0xa5754affe32648c2, 0xf8ddac880d07396c, 0x6fa491468c548664,
|
||||
0x0c7c5c1326bdbed1, 0x4a33158f03930fb3, 0x699abfc19f84d982, 0xe4fa2054a80b329c, 0x6707f9af438252fa, 0x08a368e9cfd6d49e, 0x47b1442c58fd25b8, 0xbbb3dc5ebc91769b,
|
||||
0x1665fe489061eac7, 0x33f27a811fa66310, 0x93a609346838d547, 0x30ed6d4c98cec263, 0x1dd9816cd8df9f2a, 0x94662a03063b1e7b, 0x83fdd9fbeb896066, 0x7b207573e68e590a,
|
||||
0x5f49fc0a149a4407, 0x343259b671a5a82c, 0xfbc2bb458a6f981f, 0xc272b350a0a41a38, 0x3aaf1fd8ada32354, 0x6cbb868b0b3c2717, 0xa2b569c88d2583fe, 0xf180c9d1bf027928,
|
||||
0xaf37386bd64ba9f5, 0x12bacab2790a8088, 0x4c0d3b0810435055, 0xb2eeb9070e9436df, 0xc5b29067cea7d104, 0xdcb425f1ff132461, 0x4f122cc5972bf126, 0xac282fa651230886,
|
||||
0xe7e537992f6393ef, 0xe61b3a2952b00735, 0x709c0a57ae302ce7, 0xe02514ae416058d3, 0xc44c9dd7b37445de, 0x5a68c5408022ba92, 0x1c278cdca50c0bf0, 0x6e5a9cf6f18712be,
|
||||
0x86dce0b17f319ef3, 0x2d34ec2040115d49, 0x4bcd183f7e409b69, 0x2815d56ad4a9a3dc, 0x24698979f2141d0d, 0x0000000000000000, 0x1ec696a15fb73e59, 0xd86b110b16784e2e,
|
||||
0x8e7f8858b0e74a6d, 0x063e2e8713d05fe6, 0xe2c40ed3bbdb6d7a, 0xb1f1aeca89fc97ac, 0xe1db191e3cb3cc09, 0x6418ee62c4eaf389, 0xc6ad87aa49cf7077, 0xd6f65765ca7ec556,
|
||||
0x9afb6c6dda3d9503, 0x7ce05644888d9236, 0x8d609f95378feb1e, 0x23a9aa4e9c17d631, 0x6226c0e5d73aac6f, 0x56149953a69f0443, 0xeeb852c09d66d3ab, 0x2b0ac2a753c102af,
|
||||
0x07c023376e03cb3c, 0x2ccae1903dc2c993, 0xd3d76e2f5ec63bc3, 0x9e2458973356ff4c, 0xa66a5d32644ee9b1, 0x0a427294356de137, 0x783f62be61e6f879, 0x1344c70204d91452,
|
||||
0x5b96c8f0fdf12e48, 0xa90916ecc59bf613, 0xbe92e5142829880e, 0x727d102a548b194e, 0x1be7afebcb0fc0cc, 0x3e702b2244c8491b, 0xd5e940a84d166425, 0x66f9f41f3e51c620,
|
||||
0xabe80c913f20c3ba, 0xf07ec461c2d1edf2, 0xf361d3ac45b94c81, 0x0521394a94b8fe95, 0xadd622162cf09c5c, 0xe97871f7f3651897, 0xf4a1f09b2bba87bd, 0x095d6559b2054044,
|
||||
0x0bbc7f2448be75ed, 0x2af4cf172e129675, 0x157ae98517094bb4, 0x9fda55274e856b96, 0x914713499283e0ee, 0xb952c623462a4332, 0x74433ead475b46a8, 0x8b5eb112245fb4f8,
|
||||
0xa34b6478f0f61724, 0x11a5dd7ffe6221fb, 0xc16da49d27ccbb4b, 0x76a224d0bde07301, 0x8aa0bca2598c2022, 0x4df336b86d90c48f, 0xea67663a740db9e4, 0xef465f70e0b54771,
|
||||
0x39b008152acb8227, 0x7d1e5bf4f55e06ec, 0x105bd0cf83b1b521, 0x775c2960c033e7db, 0x7e014c397236a79f, 0x811cc386113255cf, 0xeda7450d1a0e72d8, 0x5889df3d7a998f3b,
|
||||
0x2e2bfbedc779fc3a, 0xce0eef438619a4e9, 0x372d4e7bf6cd095f, 0x04df34fae96b6a4f, 0xf923a13870d4adb6, 0xa1aa7e050a4d228d, 0xa8f71b5cb84862c9, 0xb52e9a306097fde3,
|
||||
0x0d8251a35b6e2a0b, 0x2257a7fee1c442eb, 0x73831d9a29588d94, 0x51d4ba64c89ccf7f, 0x502ab7d4b54f5ba5, 0x97793dce8153bf08, 0xe5042de4d5d8a646, 0x9687307efc802bd2,
|
||||
0xa05473b5779eb657, 0xb4d097801d446939, 0xcff0e2f3fbca3033, 0xc38cbee0dd778ee2, 0x464f499c252eb162, 0xcad1dbb96f72cea6, 0xba4dd1eec142e241, 0xb00fa37af42f0376
|
||||
},
|
||||
{
|
||||
0xcce4cd3aa968b245, 0x089d5484e80b7faf, 0x638246c1b3548304, 0xd2fe0ec8c2355492, 0xa7fbdf7ff2374eee, 0x4df1600c92337a16, 0x84e503ea523b12fb, 0x0790bbfd53ab0c4a,
|
||||
0x198a780f38f6ea9d, 0x2ab30c8f55ec48cb, 0xe0f7fed6b2c49db5, 0xb6ecf3f422cadbdc, 0x409c9a541358df11, 0xd3ce8a56dfde3fe3, 0xc3e9224312c8c1a0, 0x0d6dfa58816ba507,
|
||||
0xddf3e1b179952777, 0x04c02a42748bb1d9, 0x94c2abff9f2decb8, 0x4f91752da8f8acf4, 0x78682befb169bf7b, 0xe1c77a48af2ff6c4, 0x0c5d7ec69c80ce76, 0x4cc1e4928fd81167,
|
||||
0xfeed3d24d9997b62, 0x518bb6dfc3a54a23, 0x6dbf2d26151f9b90, 0xb5bc624b05ea664f, 0xe86aaa525acfe21a, 0x4801ced0fb53a0be, 0xc91463e6c00868ed, 0x1027a815cd16fe43,
|
||||
0xf67069a0319204cd, 0xb04ccc976c8abce7, 0xc0b9b3fc35e87c33, 0xf380c77c58f2de65, 0x50bb3241de4e2152, 0xdf93f490435ef195, 0xf1e0d25d62390887, 0xaf668bfb1a3c3141,
|
||||
0xbc11b251f00a7291, 0x73a5eed47e427d47, 0x25bee3f6ee4c3b2e, 0x43cc0beb34786282, 0xc824e778dde3039c, 0xf97d86d98a327728, 0xf2b043e24519b514, 0xe297ebf7880f4b57,
|
||||
0x3a94a49a98fab688, 0x868516cb68f0c419, 0xeffa11af0964ee50, 0xa4ab4ec0d517f37d, 0xa9c6b498547c567a, 0x8e18424f80fbbbb6, 0x0bcdc53bcf2bc23c, 0x137739aaea3643d0,
|
||||
0x2c1333ec1bac2ff0, 0x8d48d3f0a7db0625, 0x1e1ac3f26b5de6d7, 0xf520f81f16b2b95e, 0x9f0f6ec450062e84, 0x0130849e1deb6b71, 0xd45e31ab8c7533a9, 0x652279a2fd14e43f,
|
||||
0x3209f01e70f1c927, 0xbe71a770cac1a473, 0x0e3d6be7a64b1894, 0x7ec8148cff29d840, 0xcb7476c7fac3be0f, 0x72956a4a63a91636, 0x37f95ec21991138f, 0x9e3fea5a4ded45f5,
|
||||
0x7b38ba50964902e8, 0x222e580bbde73764, 0x61e253e0899f55e6, 0xfc8d2805e352ad80, 0x35994be3235ac56d, 0x09add01af5e014de, 0x5e8659a6780539c6, 0xb17c48097161d796,
|
||||
0x026015213acbd6e2, 0xd1ae9f77e515e901, 0xb7dc776a3f21b0ad, 0xaba6a1b96eb78098, 0x9bcf4486248d9f5d, 0x582666c536455efd, 0xfdbdac9bfeb9c6f1, 0xc47999be4163cdea,
|
||||
0x765540081722a7ef, 0x3e548ed8ec710751, 0x3d041f67cb51bac2, 0x7958af71ac82d40a, 0x36c9da5c047a78fe, 0xed9a048e33af38b2, 0x26ee7249c96c86bd, 0x900281bdeba65d61,
|
||||
0x11172c8bd0fd9532, 0xea0abf73600434f8, 0x42fc8f75299309f3, 0x34a9cf7d3eb1ae1c, 0x2b838811480723ba, 0x5ce64c8742ceef24, 0x1adae9b01fd6570e, 0x3c349bf9d6bad1b3,
|
||||
0x82453c891c7b75c0, 0x97923a40b80d512b, 0x4a61dbf1c198765c, 0xb48ce6d518010d3e, 0xcfb45c858e480fd6, 0xd933cbf30d1e96ae, 0xd70ea014ab558e3a, 0xc189376228031742,
|
||||
0x9262949cd16d8b83, 0xeb3a3bed7def5f89, 0x49314a4ee6b8cbcf, 0xdcc3652f647e4c06, 0xda635a4c2a3e2b3d, 0x470c21a940f3d35b, 0x315961a157d174b4, 0x6672e81dda3459ac,
|
||||
0x5b76f77a1165e36e, 0x445cb01667d36ec8, 0xc5491d205c88a69b, 0x456c34887a3805b9, 0xffddb9bac4721013, 0x99af51a71e4649bf, 0xa15be01cbc7729d5, 0x52db2760e485f7b0,
|
||||
0x8c78576eba306d54, 0xae560f6507d75a30, 0x95f22f6182c687c9, 0x71c5fbf54489aba5, 0xca44f259e728d57e, 0x88b87d2ccebbdc8d, 0xbab18d32be4a15aa, 0x8be8ec93e99b611e,
|
||||
0x17b713e89ebdf209, 0xb31c5d284baa0174, 0xeeca9531148f8521, 0xb8d198138481c348, 0x8988f9b2d350b7fc, 0xb9e11c8d996aa839, 0x5a4673e40c8e881f, 0x1687977683569978,
|
||||
0xbf4123eed72acf02, 0x4ea1f1b3b513c785, 0xe767452be16f91ff, 0x7505d1b730021a7c, 0xa59bca5ec8fc980c, 0xad069eda20f7e7a3, 0x38f4b1bba231606a, 0x60d2d77e94743e97,
|
||||
0x9affc0183966f42c, 0x248e6768f3a7505f, 0xcdd449a4b483d934, 0x87b59255751baf68, 0x1bea6d2e023d3c7f, 0x6b1f12455b5ffcab, 0x743555292de9710d, 0xd8034f6d10f5fddf,
|
||||
0xc6198c9f7ba81b08, 0xbb8109aca3a17edb, 0xfa2d1766ad12cabb, 0xc729080166437079, 0x9c5fff7b77269317, 0x0000000000000000, 0x15d706c9a47624eb, 0x6fdf38072fd44d72,
|
||||
0x5fb6dd3865ee52b7, 0xa33bf53d86bcff37, 0xe657c1b5fc84fa8e, 0xaa962527735cebe9, 0x39c43525bfda0b1b, 0x204e4d2a872ce186, 0x7a083ece8ba26999, 0x554b9c9db72efbfa,
|
||||
0xb22cd9b656416a05, 0x96a2bedea5e63a5a, 0x802529a826b0a322, 0x8115ad363b5bc853, 0x8375b81701901eb1, 0x3069e53f4a3a1fc5, 0xbd2136cfede119e0, 0x18bafc91251d81ec,
|
||||
0x1d4a524d4c7d5b44, 0x05f0aedc6960daa8, 0x29e39d3072ccf558, 0x70f57f6b5962c0d4, 0x989fd53903ad22ce, 0xf84d024797d91c59, 0x547b1803aac5908b, 0xf0d056c37fd263f6,
|
||||
0xd56eb535919e58d8, 0x1c7ad6d351963035, 0x2e7326cd2167f912, 0xac361a443d1c8cd2, 0x697f076461942a49, 0x4b515f6fdc731d2d, 0x8ad8680df4700a6f, 0x41ac1eca0eb3b460,
|
||||
0x7d988533d80965d3, 0xa8f6300649973d0b, 0x7765c4960ac9cc9e, 0x7ca801adc5e20ea2, 0xdea3700e5eb59ae4, 0xa06b6482a19c42a4, 0x6a2f96db46b497da, 0x27def6d7d487edcc,
|
||||
0x463ca5375d18b82a, 0xa6cb5be1efdc259f, 0x53eba3fef96e9cc1, 0xce84d81b93a364a7, 0xf4107c810b59d22f, 0x333974806d1aa256, 0x0f0def79bba073e5, 0x231edc95a00c5c15,
|
||||
0xe437d494c64f2c6c, 0x91320523f64d3610, 0x67426c83c7df32dd, 0x6eefbc99323f2603, 0x9d6f7be56acdf866, 0x5916e25b2bae358c, 0x7ff89012e2c2b331, 0x035091bf2720bd93,
|
||||
0x561b0d22900e4669, 0x28d319ae6f279e29, 0x2f43a2533c8c9263, 0xd09e1be9f8fe8270, 0xf740ed3e2c796fbc, 0xdb53ded237d5404c, 0x62b2c25faebfe875, 0x0afd41a5d2c0a94d,
|
||||
0x6412fd3ce0ff8f4e, 0xe3a76f6995e42026, 0x6c8fa9b808f4f0e1, 0xc2d9a6dd0f23aad1, 0x8f28c6d19d10d0c7, 0x85d587744fd0798a, 0xa20b71a39b579446, 0x684f83fa7c7f4138,
|
||||
0xe507500adba4471d, 0x3f640a46f19a6c20, 0x1247bd34f7dd28a1, 0x2d23b77206474481, 0x93521002cc86e0f2, 0x572b89bc8de52d18, 0xfb1d93f8b0f9a1ca, 0xe95a2ecc4724896b,
|
||||
0x3ba420048511ddf9, 0xd63e248ab6bee54b, 0x5dd6c8195f258455, 0x06a03f634e40673b, 0x1f2a476c76b68da6, 0x217ec9b49ac78af7, 0xecaa80102e4453c3, 0x14e78257b99d4f9a
|
||||
},
|
||||
{
|
||||
0x20329b2cc87bba05, 0x4f5eb6f86546a531, 0xd4f44775f751b6b1, 0x8266a47b850dfa8b, 0xbb986aa15a6ca985, 0xc979eb08f9ae0f99, 0x2da6f447a2375ea1, 0x1e74275dcd7d8576,
|
||||
0xbc20180a800bc5f8, 0xb4a2f701b2dc65be, 0xe726946f981b6d66, 0x48e6c453bf21c94c, 0x42cad9930f0a4195, 0xefa47b64aacccd20, 0x71180a8960409a42, 0x8bb3329bf6a44e0c,
|
||||
0xd34c35de2d36dacc, 0xa92f5b7cbc23dc96, 0xb31a85aa68bb09c3, 0x13e04836a73161d2, 0xb24dfc4129c51d02, 0x8ae44b70b7da5acd, 0xe671ed84d96579a7, 0xa4bb3417d66f3832,
|
||||
0x4572ab38d56d2de8, 0xb1b47761ea47215c, 0xe81c09cf70aba15d, 0xffbdb872ce7f90ac, 0xa8782297fd5dc857, 0x0d946f6b6a4ce4a4, 0xe4df1f4f5b995138, 0x9ebc71edca8c5762,
|
||||
0x0a2c1dc0b02b88d9, 0x3b503c115d9d7b91, 0xc64376a8111ec3a2, 0xcec199a323c963e4, 0xdc76a87ec58616f7, 0x09d596e073a9b487, 0x14583a9d7d560daf, 0xf4c6dc593f2a0cb4,
|
||||
0xdd21d19584f80236, 0x4a4836983ddde1d3, 0xe58866a41ae745f9, 0xf591a5b27e541875, 0x891dc05074586693, 0x5b068c651810a89e, 0xa30346bc0c08544f, 0x3dbf3751c684032d,
|
||||
0x2a1e86ec785032dc, 0xf73f5779fca830ea, 0xb60c05ca30204d21, 0x0cc316802b32f065, 0x8770241bdd96be69, 0xb861e18199ee95db, 0xf805cad91418fcd1, 0x29e70dccbbd20e82,
|
||||
0xc7140f435060d763, 0x0f3a9da0e8b0cc3b, 0xa2543f574d76408e, 0xbd7761e1c175d139, 0x4b1f4f737ca3f512, 0x6dc2df1f2fc137ab, 0xf1d05c3967b14856, 0xa742bf3715ed046c,
|
||||
0x654030141d1697ed, 0x07b872abda676c7d, 0x3ce84eba87fa17ec, 0xc1fb0403cb79afdf, 0x3e46bc7105063f73, 0x278ae987121cd678, 0xa1adb4778ef47cd0, 0x26dd906c5362c2b9,
|
||||
0x05168060589b44e2, 0xfbfc41f9d79ac08f, 0x0e6de44ba9ced8fa, 0x9feb08068bf243a3, 0x7b341749d06b129b, 0x229c69e74a87929a, 0xe09ee6c4427c011b, 0x5692e30e725c4c3a,
|
||||
0xda99a33e5e9f6e4b, 0x353dd85af453a36b, 0x25241b4c90e0fee7, 0x5de987258309d022, 0xe230140fc0802984, 0x93281e86a0c0b3c6, 0xf229d719a4337408, 0x6f6c2dd4ad3d1f34,
|
||||
0x8ea5b2fbae3f0aee, 0x8331dd90c473ee4a, 0x346aa1b1b52db7aa, 0xdf8f235e06042aa9, 0xcc6f6b68a1354b7b, 0x6c95a6f46ebf236a, 0x52d31a856bb91c19, 0x1a35ded6d498d555,
|
||||
0xf37eaef2e54d60c9, 0x72e181a9a3c2a61c, 0x98537aad51952fde, 0x16f6c856ffaa2530, 0xd960281e9d1d5215, 0x3a0745fa1ce36f50, 0x0b7b642bf1559c18, 0x59a87eae9aec8001,
|
||||
0x5e100c05408bec7c, 0x0441f98b19e55023, 0xd70dcc5534d38aef, 0x927f676de1bea707, 0x9769e70db925e3e5, 0x7a636ea29115065a, 0x468b201816ef11b6, 0xab81a9b73edff409,
|
||||
0xc0ac7de88a07bb1e, 0x1f235eb68c0391b7, 0x6056b074458dd30f, 0xbe8eeac102f7ed67, 0xcd381283e04b5fba, 0x5cbefecec277c4e3, 0xd21b4c356c48ce0d, 0x1019c31664b35d8c,
|
||||
0x247362a7d19eea26, 0xebe582efb3299d03, 0x02aef2cb82fc289f, 0x86275df09ce8aaa8, 0x28b07427faac1a43, 0x38a9b7319e1f47cf, 0xc82e92e3b8d01b58, 0x06ef0b409b1978bc,
|
||||
0x62f842bfc771fb90, 0x9904034610eb3b1f, 0xded85ab5477a3e68, 0x90d195a663428f98, 0x5384636e2ac708d8, 0xcbd719c37b522706, 0xae9729d76644b0eb, 0x7c8c65e20a0c7ee6,
|
||||
0x80c856b007f1d214, 0x8c0b40302cc32271, 0xdbcedad51fe17a8a, 0x740e8ae938dbdea0, 0xa615c6dc549310ad, 0x19cc55f6171ae90b, 0x49b1bdb8fe5fdd8d, 0xed0a89af2830e5bf,
|
||||
0x6a7aadb4f5a65bd6, 0x7e22972988f05679, 0xf952b3325566e810, 0x39fecedadf61530e, 0x6101c99f04f3c7ce, 0x2e5f7f6761b562ff, 0xf08725d226cf5c97, 0x63af3b54860fef51,
|
||||
0x8ff2cb10ef411e2f, 0x884ab9bb35267252, 0x4df04433e7ba8dae, 0x9afd8866d3690741, 0x66b9bb34de94abb3, 0x9baaf18d92171380, 0x543c11c5f0a064a5, 0x17a1b1bdbed431f1,
|
||||
0xb5f58eeaf3a2717f, 0xc355f6c849858740, 0xec5df044694ef17e, 0xd83751f5dc6346d4, 0xfc4433520dfdacf2, 0x0000000000000000, 0x5a51f58e596ebc5f, 0x3285aaf12e34cf16,
|
||||
0x8d5c39db6dbd36b0, 0x12b731dde64f7513, 0x94906c2d7aa7dfbb, 0x302b583aacc8e789, 0x9d45facd090e6b3c, 0x2165e2c78905aec4, 0x68d45f7f775a7349, 0x189b2c1d5664fdca,
|
||||
0xe1c99f2f030215da, 0x6983269436246788, 0x8489af3b1e148237, 0xe94b702431d5b59c, 0x33d2d31a6f4adbd7, 0xbfd9932a4389f9a6, 0xb0e30e8aab39359d, 0xd1e2c715afcaf253,
|
||||
0x150f43763c28196e, 0xc4ed846393e2eb3d, 0x03f98b20c3823c5e, 0xfd134ab94c83b833, 0x556b682eb1de7064, 0x36c4537a37d19f35, 0x7559f30279a5ca61, 0x799ae58252973a04,
|
||||
0x9c12832648707ffd, 0x78cd9c6913e92ec5, 0x1d8dac7d0effb928, 0x439da0784e745554, 0x413352b3cc887dcb, 0xbacf134a1b12bd44, 0x114ebafd25cd494d, 0x2f08068c20cb763e,
|
||||
0x76a07822ba27f63f, 0xeab2fb04f25789c2, 0xe3676de481fe3d45, 0x1b62a73d95e6c194, 0x641749ff5c68832c, 0xa5ec4dfc97112cf3, 0xf6682e92bdd6242b, 0x3f11c59a44782bb2,
|
||||
0x317c21d1edb6f348, 0xd65ab5be75ad9e2e, 0x6b2dd45fb4d84f17, 0xfaab381296e4d44e, 0xd0b5befeeeb4e692, 0x0882ef0b32d7a046, 0x512a91a5a83b2047, 0x963e9ee6f85bf724,
|
||||
0x4e09cf132438b1f0, 0x77f701c9fb59e2fe, 0x7ddb1c094b726a27, 0x5f4775ee01f5f8bd, 0x9186ec4d223c9b59, 0xfeeac1998f01846d, 0xac39db1ce4b89874, 0xb75b7c21715e59e0,
|
||||
0xafc0503c273aa42a, 0x6e3b543fec430bf5, 0x704f7362213e8e83, 0x58ff0745db9294c0, 0x67eec2df9feabf72, 0xa0facd9ccf8a6811, 0xb936986ad890811a, 0x95c715c63bd9cb7a,
|
||||
0xca8060283a2c33c7, 0x507de84ee9453486, 0x85ded6d05f6a96f6, 0x1cdad5964f81ade9, 0xd5a33e9eb62fa270, 0x40642b588df6690a, 0x7f75eec2c98e42b8, 0x2cf18dace3494a60,
|
||||
0x23cb100c0bf9865b, 0xeef3028febb2d9e1, 0x4425d2d394133929, 0xaad6d05c7fa1e0c8, 0xad6ea2f7a5c68cb5, 0xc2028f2308fb9381, 0x819f2f5b468fc6d5, 0xc5bafd88d29cfffc,
|
||||
0x47dc59f357910577, 0x2b49ff07392e261d, 0x57c59ae5332258fb, 0x73b6f842e2bcb2dd, 0xcf96e04862b77725, 0x4ca73dd8a6c4996f, 0x015779eb417e14c1, 0x37932a9176af8bf4
|
||||
},
|
||||
{
|
||||
0x190a2c9b249df23e, 0x2f62f8b62263e1e9, 0x7a7f754740993655, 0x330b7ba4d5564d9f, 0x4c17a16a46672582, 0xb22f08eb7d05f5b8, 0x535f47f40bc148cc, 0x3aec5d27d4883037,
|
||||
0x10ed0a1825438f96, 0x516101f72c233d17, 0x13cc6f949fd04eae, 0x739853c441474bfd, 0x653793d90d3f5b1b, 0x5240647b96b0fc2f, 0x0c84890ad27623e0, 0xd7189b32703aaea3,
|
||||
0x2685de3523bd9c41, 0x99317c5b11bffefa, 0x0d9baa854f079703, 0x70b93648fbd48ac5, 0xa80441fce30bc6be, 0x7287704bdc36ff1e, 0xb65384ed33dc1f13, 0xd36417343ee34408,
|
||||
0x39cd38ab6e1bf10f, 0x5ab861770a1f3564, 0x0ebacf09f594563b, 0xd04572b884708530, 0x3cae9722bdb3af47, 0x4a556b6f2f5cbaf2, 0xe1704f1f76c4bd74, 0x5ec4ed7144c6dfcf,
|
||||
0x16afc01d4c7810e6, 0x283f113cd629ca7a, 0xaf59a8761741ed2d, 0xeed5a3991e215fac, 0x3bf37ea849f984d4, 0xe413e096a56ce33c, 0x2c439d3a98f020d1, 0x637559dc6404c46b,
|
||||
0x9e6c95d1e5f5d569, 0x24bb9836045fe99a, 0x44efa466dac8ecc9, 0xc6eab2a5c80895d6, 0x803b50c035220cc4, 0x0321658cba93c138, 0x8f9ebc465dc7ee1c, 0xd15a5137190131d3,
|
||||
0x0fa5ec8668e5e2d8, 0x91c979578d1037b1, 0x0642ca05693b9f70, 0xefca80168350eb4f, 0x38d21b24f36a45ec, 0xbeab81e1af73d658, 0x8cbfd9cae7542f24, 0xfd19cc0d81f11102,
|
||||
0x0ac6430fbb4dbc90, 0x1d76a09d6a441895, 0x2a01573ff1cbbfa1, 0xb572e161894fde2b, 0x8124734fa853b827, 0x614b1fdf43e6b1b0, 0x68ac395c4238cc18, 0x21d837bfd7f7b7d2,
|
||||
0x20c714304a860331, 0x5cfaab726324aa14, 0x74c5ba4eb50d606e, 0xf3a3030474654739, 0x23e671bcf015c209, 0x45f087e947b9582a, 0xd8bd77b418df4c7b, 0xe06f6c90ebb50997,
|
||||
0x0bd96080263c0873, 0x7e03f9410e40dcfe, 0xb8e94be4c6484928, 0xfb5b0608e8ca8e72, 0x1a2b49179e0e3306, 0x4e29e76961855059, 0x4f36c4e6fcf4e4ba, 0x49740ee395cf7bca,
|
||||
0xc2963ea386d17f7d, 0x90d65ad810618352, 0x12d34c1b02a1fa4d, 0xfa44258775bb3a91, 0x18150f14b9ec46dd, 0x1491861e6b9a653d, 0x9a1019d7ab2c3fc2, 0x3668d42d06fe13d7,
|
||||
0xdcc1fbb25606a6d0, 0x969490dd795a1c22, 0x3549b1a1bc6dd2ef, 0xc94f5e23a0ed770e, 0xb9f6686b5b39fdcb, 0xc4d4f4a6efeae00d, 0xe732851a1fff2204, 0x94aad6de5eb869f9,
|
||||
0x3f8ff2ae07206e7f, 0xfe38a9813b62d03a, 0xa7a1ad7a8bee2466, 0x7b6056c8dde882b6, 0x302a1e286fc58ca7, 0x8da0fa457a259bc7, 0xb3302b64e074415b, 0x5402ae7eff8b635f,
|
||||
0x08f8050c9cafc94b, 0xae468bf98a3059ce, 0x88c355cca98dc58f, 0xb10e6d67c7963480, 0xbad70de7e1aa3cf3, 0xbfb4a26e320262bb, 0xcb711820870f02d5, 0xce12b7a954a75c9d,
|
||||
0x563ce87dd8691684, 0x9f73b65e7884618a, 0x2b1e74b06cba0b42, 0x47cec1ea605b2df1, 0x1c698312f735ac76, 0x5fdbcefed9b76b2c, 0x831a354c8fb1cdfc, 0x820516c312c0791f,
|
||||
0xb74ca762aeadabf0, 0xfc06ef821c80a5e1, 0x5723cbf24518a267, 0x9d4df05d5f661451, 0x588627742dfd40bf, 0xda8331b73f3d39a0, 0x17b0e392d109a405, 0xf965400bcf28fba9,
|
||||
0x7c3dbf4229a2a925, 0x023e460327e275db, 0x6cd0b55a0ce126b3, 0xe62da695828e96e7, 0x42ad6e63b3f373b9, 0xe50cc319381d57df, 0xc5cbd729729b54ee, 0x46d1e265fd2a9912,
|
||||
0x6428b056904eeff8, 0x8be23040131e04b7, 0x6709d5da2add2ec0, 0x075de98af44a2b93, 0x8447dcc67bfbe66f, 0x6616f655b7ac9a23, 0xd607b8bded4b1a40, 0x0563af89d3a85e48,
|
||||
0x3db1b4ad20c21ba4, 0x11f22997b8323b75, 0x292032b34b587e99, 0x7f1cdace9331681d, 0x8e819fc9c0b65aff, 0xa1e3677fe2d5bb16, 0xcd33d225ee349da5, 0xd9a2543b85aef898,
|
||||
0x795e10cbfa0af76d, 0x25a4bbb9992e5d79, 0x78413344677b438e, 0xf0826688cef68601, 0xd27b34bba392f0eb, 0x551d8df162fad7bc, 0x1e57c511d0d7d9ad, 0xdeffbdb171e4d30b,
|
||||
0xf4feea8e802f6caa, 0xa480c8f6317de55e, 0xa0fc44f07fa40ff5, 0x95b5f551c3c9dd1a, 0x22f952336d6476ea, 0x0000000000000000, 0xa6be8ef5169f9085, 0xcc2cf1aa73452946,
|
||||
0x2e7ddb39bf12550a, 0xd526dd3157d8db78, 0x486b2d6c08becf29, 0x9b0f3a58365d8b21, 0xac78cdfaadd22c15, 0xbc95c7e28891a383, 0x6a927f5f65dab9c3, 0xc3891d2c1ba0cb9e,
|
||||
0xeaa92f9f50f8b507, 0xcf0d9426c9d6e87e, 0xca6e3baf1a7eb636, 0xab25247059980786, 0x69b31ad3df4978fb, 0xe2512a93cc577c4c, 0xff278a0ea61364d9, 0x71a615c766a53e26,
|
||||
0x89dc764334fc716c, 0xf87a638452594f4a, 0xf2bc208be914f3da, 0x8766b94ac1682757, 0xbbc82e687cdb8810, 0x626a7a53f9757088, 0xa2c202f358467a2e, 0x4d0882e5db169161,
|
||||
0x09e7268301de7da8, 0xe897699c771ac0dc, 0xc8507dac3d9cc3ed, 0xc0a878a0a1330aa6, 0x978bb352e42ba8c1, 0xe9884a13ea6b743f, 0x279afdbabecc28a2, 0x047c8c064ed9eaab,
|
||||
0x507e2278b15289f4, 0x599904fbb08cf45c, 0xbd8ae46d15e01760, 0x31353da7f2b43844, 0x8558ff49e68a528c, 0x76fbfc4d92ef15b5, 0x3456922e211c660c, 0x86799ac55c1993b4,
|
||||
0x3e90d1219a51da9c, 0x2d5cbeb505819432, 0x982e5fd48cce4a19, 0xdb9c1238a24c8d43, 0xd439febecaa96f9b, 0x418c0bef0960b281, 0x158ea591f6ebd1de, 0x1f48e69e4da66d4e,
|
||||
0x8afd13cf8e6fb054, 0xf5e1c9011d5ed849, 0xe34e091c5126c8af, 0xad67ee7530a398f6, 0x43b24dec2e82c75a, 0x75da99c1287cd48d, 0x92e81cdb3783f689, 0xa3dd217cc537cecd,
|
||||
0x60543c50de970553, 0x93f73f54aaf2426a, 0xa91b62737e7a725d, 0xf19d4507538732e2, 0x77e4dfc20f9ea156, 0x7d229ccdb4d31dc6, 0x1b346a98037f87e5, 0xedf4c615a4b29e94,
|
||||
0x4093286094110662, 0xb0114ee85ae78063, 0x6ff1d0d6b672e78b, 0x6dcf96d591909250, 0xdfe09e3eec9567e8, 0x3214582b4827f97c, 0xb46dc2ee143e6ac8, 0xf6c0ac8da7cd1971,
|
||||
0xebb60c10cd8901e4, 0xf7df8f023abcad92, 0x9c52d3d2c217a0b2, 0x6b8d5cd0f8ab0d20, 0x3777f7a29b8fa734, 0x011f238f9d71b4e3, 0xc1b75b2f3c42be45, 0x5de588fdfe551ef7,
|
||||
0x6eeef3592b035368, 0xaa3a07ffc4e9b365, 0xecebe59a39c32a77, 0x5ba742f8976e8187, 0x4b4a48e0b22d0e11, 0xddded83dcb771233, 0xa59feb79ac0c51bd, 0xc7f5912a55792135
|
||||
},
|
||||
{
|
||||
0x6d6ae04668a9b08a, 0x3ab3f04b0be8c743, 0xe51e166b54b3c908, 0xbe90a9eb35c2f139, 0xb2c7066637f2bec1, 0xaa6945613392202c, 0x9a28c36f3b5201eb, 0xddce5a93ab536994,
|
||||
0x0e34133ef6382827, 0x52a02ba1ec55048b, 0xa2f88f97c4b2a177, 0x8640e513ca2251a5, 0xcdf1d36258137622, 0xfe6cb708dedf8ddb, 0x8a174a9ec8121e5d, 0x679896036b81560e,
|
||||
0x59ed033395795fee, 0x1dd778ab8b74edaf, 0xee533ef92d9f926d, 0x2a8c79baf8a8d8f5, 0x6bcf398e69b119f6, 0xe20491742fafdd95, 0x276488e0809c2aec, 0xea955b82d88f5cce,
|
||||
0x7102c63a99d9e0c4, 0xf9763017a5c39946, 0x429fa2501f151b3d, 0x4659c72bea05d59e, 0x984b7fdccf5a6634, 0xf742232953fbb161, 0x3041860e08c021c7, 0x747bfd9616cd9386,
|
||||
0x4bb1367192312787, 0x1b72a1638a6c44d3, 0x4a0e68a6e8359a66, 0x169a5039f258b6ca, 0xb98a2ef44edee5a4, 0xd9083fe85e43a737, 0x967f6ce239624e13, 0x8874f62d3c1a7982,
|
||||
0x3c1629830af06e3f, 0x9165ebfd427e5a8e, 0xb5dd81794ceeaa5c, 0x0de8f15a7834f219, 0x70bd98ede3dd5d25, 0xaccc9ca9328a8950, 0x56664eda1945ca28, 0x221db34c0f8859ae,
|
||||
0x26dbd637fa98970d, 0x1acdffb4f068f932, 0x4585254f64090fa0, 0x72de245e17d53afa, 0x1546b25d7c546cf4, 0x207e0ffffb803e71, 0xfaaad2732bcf4378, 0xb462dfae36ea17bd,
|
||||
0xcf926fd1ac1b11fd, 0xe0672dc7dba7ba4a, 0xd3fa49ad5d6b41b3, 0x8ba81449b216a3bc, 0x14f9ec8a0650d115, 0x40fc1ee3eb1d7ce2, 0x23a2ed9b758ce44f, 0x782c521b14fddc7e,
|
||||
0x1c68267cf170504e, 0xbcf31558c1ca96e6, 0xa781b43b4ba6d235, 0xf6fd7dfe29ff0c80, 0xb0a4bad5c3fad91e, 0xd199f51ea963266c, 0x414340349119c103, 0x5405f269ed4dadf7,
|
||||
0xabd61bb649969dcd, 0x6813dbeae7bdc3c8, 0x65fb2ab09f8931d1, 0xf1e7fae152e3181d, 0xc1a67cef5a2339da, 0x7a4feea8e0f5bba1, 0x1e0b9acf05783791, 0x5b8ebf8061713831,
|
||||
0x80e53cdbcb3af8d9, 0x7e898bd315e57502, 0xc6bcfbf0213f2d47, 0x95a38e86b76e942d, 0x092e94218d243cba, 0x8339debf453622e7, 0xb11be402b9fe64ff, 0x57d9100d634177c9,
|
||||
0xcc4e8db52217cbc3, 0x3b0cae9c71ec7aa2, 0xfb158ca451cbfe99, 0x2b33276d82ac6514, 0x01bf5ed77a04bde1, 0xc5601994af33f779, 0x75c4a3416cc92e67, 0xf3844652a6eb7fc2,
|
||||
0x3487e375fdd0ef64, 0x18ae430704609eed, 0x4d14efb993298efb, 0x815a620cb13e4538, 0x125c354207487869, 0x9eeea614ce42cf48, 0xce2d3106d61fac1c, 0xbbe99247bad6827b,
|
||||
0x071a871f7b1c149d, 0x2e4a1cc10db81656, 0x77a71ff298c149b8, 0x06a5d9c80118a97c, 0xad73c27e488e34b1, 0x443a7b981e0db241, 0xe3bbcfa355ab6074, 0x0af276450328e684,
|
||||
0x73617a896dd1871b, 0x58525de4ef7de20f, 0xb7be3dcab8e6cd83, 0x19111dd07e64230c, 0x842359a03e2a367a, 0x103f89f1f3401fb6, 0xdc710444d157d475, 0xb835702334da5845,
|
||||
0x4320fc876511a6dc, 0xd026abc9d3679b8d, 0x17250eee885c0b2b, 0x90dab52a387ae76f, 0x31fed8d972c49c26, 0x89cba8fa461ec463, 0x2ff5421677bcabb7, 0x396f122f85e41d7d,
|
||||
0xa09b332430bac6a8, 0xc888e8ced7070560, 0xaeaf201ac682ee8f, 0x1180d7268944a257, 0xf058a43628e7a5fc, 0xbd4c4b8fbbce2b07, 0xa1246df34abe7b49, 0x7d5569b79be9af3c,
|
||||
0xa9b5a705bd9efa12, 0xdb6b835baa4bc0e8, 0x05793bac8f147342, 0x21c1512881848390, 0xfdb0556c50d357e5, 0x613d4fcb6a99ff72, 0x03dce2648e0cda3e, 0xe949b9e6568386f0,
|
||||
0xfc0f0bbb2ad7ea04, 0x6a70675913b5a417, 0x7f36d5046fe1c8e3, 0x0c57af8d02304ff8, 0x32223abdfcc84618, 0x0891caf6f720815b, 0xa63eeaec31a26fd4, 0x2507345374944d33,
|
||||
0x49d28ac266394058, 0xf5219f9aa7f3d6be, 0x2d96fea583b4cc68, 0x5a31e1571b7585d0, 0x8ed12fe53d02d0fe, 0xdfade6205f5b0e4b, 0x4cabb16ee92d331a, 0x04c6657bf510cea3,
|
||||
0xd73c2cd6a87b8f10, 0xe1d87310a1a307ab, 0x6cd5be9112ad0d6b, 0x97c032354366f3f2, 0xd4e0ceb22677552e, 0x0000000000000000, 0x29509bde76a402cb, 0xc27a9e8bd42fe3e4,
|
||||
0x5ef7842cee654b73, 0xaf107ecdbc86536e, 0x3fcacbe784fcb401, 0xd55f90655c73e8cf, 0xe6c2f40fdabf1336, 0xe8f6e7312c873b11, 0xeb2a0555a28be12f, 0xe4a148bc2eb774e9,
|
||||
0x9b979db84156bc0a, 0x6eb60222e6a56ab4, 0x87ffbbc4b026ec44, 0xc703a5275b3b90a6, 0x47e699fc9001687f, 0x9c8d1aa73a4aa897, 0x7cea3760e1ed12dd, 0x4ec80ddd1d2554c5,
|
||||
0x13e36b957d4cc588, 0x5d2b66486069914d, 0x92b90999cc7280b0, 0x517cc9c56259deb5, 0xc937b619ad03b881, 0xec30824ad997f5b2, 0xa45d565fc5aa080b, 0xd6837201d27f32f1,
|
||||
0x635ef3789e9198ad, 0x531f75769651b96a, 0x4f77530a6721e924, 0x486dd4151c3dfdb9, 0x5f48dafb9461f692, 0x375b011173dc355a, 0x3da9775470f4d3de, 0x8d0dcd81b30e0ac0,
|
||||
0x36e45fc609d888bb, 0x55baacbe97491016, 0x8cb29356c90ab721, 0x76184125e2c5f459, 0x99f4210bb55edbd5, 0x6f095cf59ca1d755, 0x9f51f8c3b44672a9, 0x3538bda287d45285,
|
||||
0x50c39712185d6354, 0xf23b1885dcefc223, 0x79930ccc6ef9619f, 0xed8fdc9da3934853, 0xcb540aaa590bdf5e, 0x5c94389f1a6d2cac, 0xe77daad8a0bbaed7, 0x28efc5090ca0bf2a,
|
||||
0xbf2ff73c4fc64cd8, 0xb37858b14df60320, 0xf8c96ec0dfc724a7, 0x828680683f329f06, 0x941cd051cd6a29cc, 0xc3c5c05cae2b5e05, 0xb601631dc2e27062, 0xc01922382027843b,
|
||||
0x24b86a840e90f0d2, 0xd245177a276ffc52, 0x0f8b4de98c3c95c6, 0x3e759530fef809e0, 0x0b4d2892792c5b65, 0xc4df4743d5374a98, 0xa5e20888bfaeb5ea, 0xba56cc90c0d23f9a,
|
||||
0x38d04cf8ffe0a09c, 0x62e1adafe495254c, 0x0263bcb3f40867df, 0xcaeb547d230f62bf, 0x6082111c109d4293, 0xdad4dd8cd04f7d09, 0xefec602e579b2f8c, 0x1fb4c4187f7c8a70,
|
||||
0xffd3e9dfa4db303a, 0x7bf0b07f9af10640, 0xf49ec14dddf76b5f, 0x8f6e713247066d1f, 0x339d646a86ccfbf9, 0x64447467e58d8c30, 0x2c29a072f9b07189, 0xd8b7613f24471ad6,
|
||||
0x6627c8d41185ebef, 0xa347d140beb61c96, 0xde12b8f7255fb3aa, 0x9d324470404e1576, 0x9306574eb6763d51, 0xa80af9d2c79a47f3, 0x859c0777442e8b9b, 0x69ac853d9db97e29
|
||||
},
|
||||
{
|
||||
0xc3407dfc2de6377e, 0x5b9e93eea4256f77, 0xadb58fdd50c845e0, 0x5219ff11a75bed86, 0x356b61cfd90b1de9, 0xfb8f406e25abe037, 0x7a5a0231c0f60796, 0x9d3cd216e1f5020b,
|
||||
0x0c6550fb6b48d8f3, 0xf57508c427ff1c62, 0x4ad35ffa71cb407d, 0x6290a2da1666aa6d, 0xe284ec2349355f9f, 0xb3c307c53d7c84ec, 0x05e23c0468365a02, 0x190bac4d6c9ebfa8,
|
||||
0x94bbbee9e28b80fa, 0xa34fc777529cb9b5, 0xcc7b39f095bcd978, 0x2426addb0ce532e3, 0x7e79329312ce4fc7, 0xab09a72eebec2917, 0xf8d15499f6b9d6c2, 0x1a55b8babf8c895d,
|
||||
0xdb8add17fb769a85, 0xb57f2f368658e81b, 0x8acd36f18f3f41f6, 0x5ce3b7bba50f11d3, 0x114dcc14d5ee2f0a, 0xb91a7fcded1030e8, 0x81d5425fe55de7a1, 0xb6213bc1554adeee,
|
||||
0x80144ef95f53f5f2, 0x1e7688186db4c10c, 0x3b912965db5fe1bc, 0xc281715a97e8252d, 0x54a5d7e21c7f8171, 0x4b12535ccbc5522e, 0x1d289cefbea6f7f9, 0x6ef5f2217d2e729e,
|
||||
0xe6a7dc819b0d17ce, 0x1b94b41c05829b0e, 0x33d7493c622f711e, 0xdcf7f942fa5ce421, 0x600fba8b7f7a8ecb, 0x46b60f011a83988e, 0x235b898e0dcf4c47, 0x957ab24f588592a9,
|
||||
0x4354330572b5c28c, 0xa5f3ef84e9b8d542, 0x8c711e02341b2d01, 0x0b1874ae6a62a657, 0x1213d8e306fc19ff, 0xfe6d7c6a4d9dba35, 0x65ed868f174cd4c9, 0x88522ea0e6236550,
|
||||
0x899322065c2d7703, 0xc01e690bfef4018b, 0x915982ed8abddaf8, 0xbe675b98ec3a4e4c, 0xa996bf7f82f00db1, 0xe1daf8d49a27696a, 0x2effd5d3dc8986e7, 0xd153a51f2b1a2e81,
|
||||
0x18caa0ebd690adfb, 0x390e3134b243c51a, 0x2778b92cdff70416, 0x029f1851691c24a6, 0x5e7cafeacc133575, 0xfa4e4cc89fa5f264, 0x5a5f9f481e2b7d24, 0x484c47ab18d764db,
|
||||
0x400a27f2a1a7f479, 0xaeeb9b2a83da7315, 0x721c626879869734, 0x042330a2d2384851, 0x85f672fd3765aff0, 0xba446b3a3e02061d, 0x73dd6ecec3888567, 0xffac70ccf793a866,
|
||||
0xdfa9edb5294ed2d4, 0x6c6aea7014325638, 0x834a5a0e8c41c307, 0xcdba35562fb2cb2b, 0x0ad97808d06cb404, 0x0f3b440cb85aee06, 0xe5f9c876481f213b, 0x98deee1289c35809,
|
||||
0x59018bbfcd394bd1, 0xe01bf47220297b39, 0xde68e1139340c087, 0x9fa3ca4788e926ad, 0xbb85679c840c144e, 0x53d8f3b71d55ffd5, 0x0da45c5dd146caa0, 0x6f34fe87c72060cd,
|
||||
0x57fbc315cf6db784, 0xcee421a1fca0fdde, 0x3d2d0196607b8d4b, 0x642c8a29ad42c69a, 0x14aff010bdd87508, 0xac74837beac657b3, 0x3216459ad821634d, 0x3fb219c70967a9ed,
|
||||
0x06bc28f3bb246cf7, 0xf2082c9126d562c6, 0x66b39278c45ee23c, 0xbd394f6f3f2878b9, 0xfd33689d9e8f8cc0, 0x37f4799eb017394f, 0x108cc0b26fe03d59, 0xda4bd1b1417888d6,
|
||||
0xb09d1332ee6eb219, 0x2f3ed975668794b4, 0x58c0871977375982, 0x7561463d78ace990, 0x09876cff037e82f1, 0x7fb83e35a8c05d94, 0x26b9b58a65f91645, 0xef20b07e9873953f,
|
||||
0x3148516d0b3355b8, 0x41cb2b541ba9e62a, 0x790416c613e43163, 0xa011d380818e8f40, 0x3a5025c36151f3ef, 0xd57095bdf92266d0, 0x498d4b0da2d97688, 0x8b0c3a57353153a5,
|
||||
0x21c491df64d368e1, 0x8f2f0af5e7091bf4, 0x2da1c1240f9bb012, 0xc43d59a92ccc49da, 0xbfa6573e56345c1f, 0x828b56a8364fd154, 0x9a41f643e0df7caf, 0xbcf843c985266aea,
|
||||
0x2b1de9d7b4bfdce5, 0x20059d79dedd7ab2, 0x6dabe6d6ae3c446b, 0x45e81bf6c991ae7b, 0x6351ae7cac68b83e, 0xa432e32253b6c711, 0xd092a9b991143cd2, 0xcac711032e98b58f,
|
||||
0xd8d4c9e02864ac70, 0xc5fc550f96c25b89, 0xd7ef8dec903e4276, 0x67729ede7e50f06f, 0xeac28c7af045cf3d, 0xb15c1f945460a04a, 0x9cfddeb05bfb1058, 0x93c69abce3a1fe5e,
|
||||
0xeb0380dc4a4bdd6e, 0xd20db1e8f8081874, 0x229a8528b7c15e14, 0x44291750739fbc28, 0xd3ccbd4e42060a27, 0xf62b1c33f4ed2a97, 0x86a8660ae4779905, 0xd62e814a2a305025,
|
||||
0x477703a7a08d8add, 0x7b9b0e977af815c5, 0x78c51a60a9ea2330, 0xa6adfb733aaae3b7, 0x97e5aa1e3199b60f, 0x0000000000000000, 0xf4b404629df10e31, 0x5564db44a6719322,
|
||||
0x9207961a59afec0d, 0x9624a6b88b97a45c, 0x363575380a192b1c, 0x2c60cd82b595a241, 0x7d272664c1dc7932, 0x7142769faa94a1c1, 0xa1d0df263b809d13, 0x1630e841d4c451ae,
|
||||
0xc1df65ad44fa13d8, 0x13d2d445bcf20bac, 0xd915c546926abe23, 0x38cf3d92084dd749, 0xe766d0272103059d, 0xc7634d5effde7f2f, 0x077d2455012a7ea4, 0xedbfa82ff16fb199,
|
||||
0xaf2a978c39d46146, 0x42953fa3c8bbd0df, 0xcb061da59496a7dc, 0x25e7a17db6eb20b0, 0x34aa6d6963050fba, 0xa76cf7d580a4f1e4, 0xf7ea10954ee338c4, 0xfcf2643b24819e93,
|
||||
0xcf252d0746aeef8d, 0x4ef06f58a3f3082c, 0x563acfb37563a5d7, 0x5086e740ce47c920, 0x2982f186dda3f843, 0x87696aac5e798b56, 0x5d22bb1d1f010380, 0x035e14f7d31236f5,
|
||||
0x3cec0d30da759f18, 0xf3c920379cdb7095, 0xb8db736b571e22bb, 0xdd36f5e44052f672, 0xaac8ab8851e23b44, 0xa857b3d938fe1fe2, 0x17f1e4e76eca43fd, 0xec7ea4894b61a3ca,
|
||||
0x9e62c6e132e734fe, 0xd4b1991b432c7483, 0x6ad6c283af163acf, 0x1ce9904904a8e5aa, 0x5fbda34c761d2726, 0xf910583f4cb7c491, 0xc6a241f845d06d7c, 0x4f3163fe19fd1a7f,
|
||||
0xe99c988d2357f9c8, 0x8eee06535d0709a7, 0x0efa48aa0254fc55, 0xb4be23903c56fa48, 0x763f52caabbedf65, 0xeee1bcd8227d876c, 0xe345e085f33b4dcc, 0x3e731561b369bbbe,
|
||||
0x2843fd2067adea10, 0x2adce5710eb1ceb6, 0xb7e03767ef44ccbd, 0x8db012a48e153f52, 0x61ceb62dc5749c98, 0xe85d942b9959eb9b, 0x4c6f7709caef2c8a, 0x84377e5b8d6bbda3,
|
||||
0x30895dcbb13d47eb, 0x74a04a9bc2a2fbc3, 0x6b17ce251518289c, 0xe438c4d0f2113368, 0x1fb784bed7bad35f, 0x9b80fae55ad16efc, 0x77fe5e6c11b0cd36, 0xc858095247849129,
|
||||
0x08466059b97090a2, 0x01c10ca6ba0e1253, 0x6988d6747c040c3a, 0x6849dad2c60a1e69, 0x5147ebe67449db73, 0xc99905f4fd8a837a, 0x991fe2b433cd4a5a, 0xf09734c04fc94660,
|
||||
0xa28ecbd1e892abe6, 0xf1563866f5c75433, 0x4dae7baf70e13ed9, 0x7ce62ac27bd26b61, 0x70837a39109ab392, 0x90988e4b30b3c8ab, 0xb2020b63877296bf, 0x156efcb607d6675b
|
||||
},
|
||||
{
|
||||
0xe63f55ce97c331d0, 0x25b506b0015bba16, 0xc8706e29e6ad9ba8, 0x5b43d3775d521f6a, 0x0bfa3d577035106e, 0xab95fc172afb0e66, 0xf64b63979e7a3276, 0xf58b4562649dad4b,
|
||||
0x48f7c3dbae0c83f1, 0xff31916642f5c8c5, 0xcbb048dc1c4a0495, 0x66b8f83cdf622989, 0x35c130e908e2b9b0, 0x7c761a61f0b34fa1, 0x3601161cf205268d, 0x9e54ccfe2219b7d6,
|
||||
0x8b7d90a538940837, 0x9cd403588ea35d0b, 0xbc3c6fea9ccc5b5a, 0xe5ff733b6d24aeed, 0xceed22de0f7eb8d2, 0xec8581cab1ab545e, 0xb96105e88ff8e71d, 0x8ca03501871a5ead,
|
||||
0x76ccce65d6db2a2f, 0x5883f582a7b58057, 0x3f7be4ed2e8adc3e, 0x0fe7be06355cd9c9, 0xee054e6c1d11be83, 0x1074365909b903a6, 0x5dde9f80b4813c10, 0x4a770c7d02b6692c,
|
||||
0x5379c8d5d7809039, 0xb4067448161ed409, 0x5f5e5026183bd6cd, 0xe898029bf4c29df9, 0x7fb63c940a54d09c, 0xc5171f897f4ba8bc, 0xa6f28db7b31d3d72, 0x2e4f3be7716eaa78,
|
||||
0x0d6771a099e63314, 0x82076254e41bf284, 0x2f0fd2b42733df98, 0x5c9e76d3e2dc49f0, 0x7aeb569619606cdb, 0x83478b07b2468764, 0xcfadcb8d5923cd32, 0x85dac7f05b95a41e,
|
||||
0xb5469d1b4043a1e9, 0xb821ecbbd9a592fd, 0x1b8e0b0e798c13c8, 0x62a57b6d9a0be02e, 0xfcf1b793b81257f8, 0x9d94ea0bd8fe28eb, 0x4cea408aeb654a56, 0x23284a47e888996c,
|
||||
0x2d8f1d128b893545, 0xf4cbac3132c0d8ab, 0xbd7c86b9ca912eba, 0x3a268eef3dbe6079, 0xf0d62f6077a9110c, 0x2735c916ade150cb, 0x89fd5f03942ee2ea, 0x1acee25d2fd16628,
|
||||
0x90f39bab41181bff, 0x430dfe8cde39939f, 0xf70b8ac4c8274796, 0x1c53aeaac6024552, 0x13b410acf35e9c9b, 0xa532ab4249faa24f, 0x2b1251e5625a163f, 0xd7e3e676da4841c7,
|
||||
0xa7b264e4e5404892, 0xda8497d643ae72d3, 0x861ae105a1723b23, 0x38a6414991048aa4, 0x6578dec92585b6b4, 0x0280cfa6acbaeadd, 0x88bdb650c273970a, 0x9333bd5ebbff84c2,
|
||||
0x4e6a8f2c47dfa08b, 0x321c954db76cef2a, 0x418d312a72837942, 0xb29b38bfffcdf773, 0x6c022c38f90a4c07, 0x5a033a240b0f6a8a, 0x1f93885f3ce5da6f, 0xc38a537e96988bc6,
|
||||
0x39e6a81ac759ff44, 0x29929e43cee0fce2, 0x40cdd87924de0ca2, 0xe9d8ebc8a29fe819, 0x0c2798f3cfbb46f4, 0x55e484223e53b343, 0x4650948ecd0d2fd8, 0x20e86cb2126f0651,
|
||||
0x6d42c56baf5739e7, 0xa06fc1405ace1e08, 0x7babbfc54f3d193b, 0x424d17df8864e67f, 0xd8045870ef14980e, 0xc6d7397c85ac3781, 0x21a885e1443273b1, 0x67f8116f893f5c69,
|
||||
0x24f5efe35706cff6, 0xd56329d076f2ab1a, 0x5e1eb9754e66a32d, 0x28d2771098bd8902, 0x8f6013f47dfdc190, 0x17a993fdb637553c, 0xe0a219397e1012aa, 0x786b9930b5da8606,
|
||||
0x6e82e39e55b0a6da, 0x875a0856f72f4ec3, 0x3741ff4fa458536d, 0xac4859b3957558fc, 0x7ef6d5c75c09a57c, 0xc04a758b6c7f14fb, 0xf9acdd91ab26ebbf, 0x7391a467c5ef9668,
|
||||
0x335c7c1ee1319aca, 0xa91533b18641e4bb, 0xe4bf9a683b79db0d, 0x8e20faa72ba0b470, 0x51f907737b3a7ae4, 0x2268a314bed5ec8c, 0xd944b123b949edee, 0x31dcb3b84d8b7017,
|
||||
0xd3fe65279f218860, 0x097af2f1dc8ffab3, 0x9b09a6fc312d0b91, 0xcc6ded78a3c4520f, 0x3481d9ba5ebfcc50, 0x4f2a667f1182d56b, 0xdfd9fdd4509ace94, 0x26752045fbbc252b,
|
||||
0xbffc491f662bc467, 0xdd593272fc202449, 0x3cbbc218d46d4303, 0x91b372f817456e1f, 0x681faf69bc6385a0, 0xb686bbeebaa43ed4, 0x1469b5084cd0ca01, 0x98c98009cbca94ac,
|
||||
0x6438379a73d8c354, 0xc2caba2dc0c5fe26, 0x3e3b0dbe78d7a9de, 0x50b9ee202d670f04, 0x4590b27b37eab0e5, 0x6025b4cb36b10af3, 0xfb2c1237079c0162, 0xa12f28130c936be8,
|
||||
0x4b37e52e54eb1ccc, 0x083a1ba28ad28f53, 0xc10a9cd83a22611b, 0x9f1425ad7444c236, 0x069d4cf7e9d3237a, 0xedc56899e7f621be, 0x778c273680865fcf, 0x309c5aeb1bd605f7,
|
||||
0x8de0dc52d1472b4d, 0xf8ec34c2fd7b9e5f, 0xea18cd3d58787724, 0xaad515447ca67b86, 0x9989695a9d97e14c, 0x0000000000000000, 0xf196c63321f464ec, 0x71116bc169557cb5,
|
||||
0xaf887f466f92c7c1, 0x972e3e0ffe964d65, 0x190ec4a8d536f915, 0x95aef1a9522ca7b8, 0xdc19db21aa7d51a9, 0x94ee18fa0471d258, 0x8087adf248a11859, 0xc457f6da2916dd5c,
|
||||
0xfa6cfb6451c17482, 0xf256e0c6db13fbd1, 0x6a9f60cf10d96f7d, 0x4daaa9d9bd383fb6, 0x03c026f5fae79f3d, 0xde99148706c7bb74, 0x2a52b8b6340763df, 0x6fc20acd03edd33a,
|
||||
0xd423c08320afdefa, 0xbbe1ca4e23420dc0, 0x966ed75ca8cb3885, 0xeb58246e0e2502c4, 0x055d6a021334bc47, 0xa47242111fa7d7af, 0xe3623fcc84f78d97, 0x81c744a11efc6db9,
|
||||
0xaec8961539cfb221, 0xf31609958d4e8e31, 0x63e5923ecc5695ce, 0x47107ddd9b505a38, 0xa3afe7b5a0298135, 0x792b7063e387f3e6, 0x0140e953565d75e0, 0x12f4f9ffa503e97b,
|
||||
0x750ce8902c3cb512, 0xdbc47e8515f30733, 0x1ed3610c6ab8af8f, 0x5239218681dde5d9, 0xe222d69fd2aaf877, 0xfe71783514a8bd25, 0xcaf0a18f4a177175, 0x61655d9860ec7f13,
|
||||
0xe77fbc9dc19e4430, 0x2ccff441ddd440a5, 0x16e97aaee06a20dc, 0xa855dae2d01c915b, 0x1d1347f9905f30b2, 0xb7c652bdecf94b34, 0xd03e43d265c6175d, 0xfdb15ec0ee4f2218,
|
||||
0x57644b8492e9599e, 0x07dda5a4bf8e569a, 0x54a46d71680ec6a3, 0x5624a2d7c4b42c7e, 0xbebca04c3076b187, 0x7d36f332a6ee3a41, 0x3b6667bc6be31599, 0x695f463aea3ef040,
|
||||
0xad08b0e0c3282d1c, 0xb15b1e4a052a684e, 0x44d05b2861b7c505, 0x15295c5b1a8dbfe1, 0x744c01c37a61c0f2, 0x59c31cd1f1e8f5b7, 0xef45a73f4b4ccb63, 0x6bdf899c46841a9d,
|
||||
0x3dfb2b4b823036e3, 0xa2ef0ee6f674f4d5, 0x184e2dfb836b8cf5, 0x1134df0a5fe47646, 0xbaa1231d751f7820, 0xd17eaa81339b62bd, 0xb01bf71953771dae, 0x849a2ea30dc8d1fe,
|
||||
0x705182923f080955, 0x0ea757556301ac29, 0x041d83514569c9a7, 0x0abad4042668658e, 0x49b72a88f851f611, 0x8a3d79f66ec97dd7, 0xcd2d042bf59927ef, 0xc930877ab0f0ee48,
|
||||
0x9273540deda2f122, 0xc797d02fd3f14261, 0xe1e2f06a284d674a, 0xd2be8c74c97cfd80, 0x9a494faf67707e71, 0xb3dbd1eca9908293, 0x72d14d3493b2e388, 0xd6a30f258c153427
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::hash::hmac{HashAlg, HASH_BYTES, BLOCK_BYTES};
|
||||
module std::hash::hmac <HashAlg, HASH_BYTES, BLOCK_BYTES>;
|
||||
import std::crypto;
|
||||
|
||||
struct Hmac
|
||||
|
||||
@@ -58,38 +58,38 @@ fn ulong hash(char[] data, ulong seed = 0)
|
||||
|
||||
if (@likely(data.len >= 8))
|
||||
{
|
||||
r1h ^= @unaligned_load(*(ulong*)data.ptr, 1);
|
||||
r1h ^= mem::load((ulong*)data.ptr, 1);
|
||||
|
||||
r2h ^= (data.len < 12)
|
||||
? ((data[data.len - 3] | ((ulong)data[data.len - 2] << 8) | ((ulong)data[data.len - 1] << 16) | ((ulong)1 << 24)) >> ((data.len * 8) ^ 88))
|
||||
: (((@unaligned_load(*(uint*)&data[^4], 1) | ((ulong)1 << 32)) >> (128 - data.len * 8)) << 32 | @unaligned_load(*(uint*)&data[8], 1));
|
||||
: (((mem::load((uint*)&data[^4], 1) | ((ulong)1 << 32)) >> (128 - data.len * 8)) << 32 | mem::load((uint*)&data[8], 1));
|
||||
}
|
||||
else if (data.len != 0)
|
||||
{
|
||||
r1h ^= (data.len < 4)
|
||||
? (((ulong)1 << (data.len * 8)) ^ data[0] ^ (data.len > 1 ? (ulong)data[1] << 8 : 0) ^ (data.len > 2 ? (ulong)data[2] << 16 : 0))
|
||||
: (((@unaligned_load(*(uint*)&data[^4], 1) | ((ulong)1 << 32)) >> (64 - data.len * 8)) << 32 | @unaligned_load(*(uint*)&data[0], 1));
|
||||
: (((mem::load((uint*)&data[^4], 1) | ((ulong)1 << 32)) >> (64 - data.len * 8)) << 32 | mem::load((uint*)&data[0], 1));
|
||||
}
|
||||
}
|
||||
else if (data.len < 32)
|
||||
{
|
||||
// HASH16
|
||||
@komimul(
|
||||
@unaligned_load(*(ulong*)&data[0], 1) ^ seed1,
|
||||
@unaligned_load(*(ulong*)&data[8], 1) ^ seed5,
|
||||
mem::load((ulong*)&data[0], 1) ^ seed1,
|
||||
mem::load((ulong*)&data[8], 1) ^ seed5,
|
||||
seed1, seed5
|
||||
);
|
||||
seed1 ^= seed5;
|
||||
|
||||
if (data.len < 24)
|
||||
{
|
||||
r1h = (((@unaligned_load(*(ulong*)&data[^8], 1) >> 8) | ((ulong)1 << 56)) >> (((int)(data.len * 8) ^ 184))) ^ seed1;
|
||||
r1h = (((mem::load((ulong*)&data[^8], 1) >> 8) | ((ulong)1 << 56)) >> (((int)(data.len * 8) ^ 184))) ^ seed1;
|
||||
r2h = seed5;
|
||||
}
|
||||
else
|
||||
{
|
||||
r1h = @unaligned_load(*(ulong*)&data[16], 1) ^ seed1;
|
||||
r2h = (((@unaligned_load(*(ulong*)&data[^8], 1) >> 8) | ((ulong)1 << 56)) >> (((int)(data.len * 8) ^ 248))) ^ seed5;
|
||||
r1h = mem::load((ulong*)&data[16], 1) ^ seed1;
|
||||
r2h = (((mem::load((ulong*)&data[^8], 1) >> 8) | ((ulong)1 << 56)) >> (((int)(data.len * 8) ^ 248))) ^ seed5;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -106,8 +106,8 @@ fn ulong hash(char[] data, ulong seed = 0)
|
||||
{
|
||||
$for var $x = 0; $x < 4; ++$x :
|
||||
@komimul(
|
||||
@unaligned_load(*(ulong*)&data[0 + ($x * 8)], 1) ^ seeds[$x],
|
||||
@unaligned_load(*(ulong*)&data[32 + ($x * 8)], 1) ^ seeds[4 + $x],
|
||||
mem::load((ulong*)&data[0 + ($x * 8)], 1) ^ seeds[$x],
|
||||
mem::load((ulong*)&data[32 + ($x * 8)], 1) ^ seeds[4 + $x],
|
||||
seeds[$x], seeds[4 + $x]
|
||||
);
|
||||
$endfor
|
||||
@@ -125,8 +125,8 @@ fn ulong hash(char[] data, ulong seed = 0)
|
||||
for (; data.len >= 16; data = data[16:^16])
|
||||
{
|
||||
@komimul(
|
||||
@unaligned_load(*(ulong*)&data[0], 1) ^ seed1,
|
||||
@unaligned_load(*(ulong*)&data[8], 1) ^ seed5,
|
||||
mem::load((ulong*)&data[0], 1) ^ seed1,
|
||||
mem::load((ulong*)&data[8], 1) ^ seed5,
|
||||
seed1, seed5
|
||||
);
|
||||
seed1 ^= seed5;
|
||||
@@ -137,13 +137,13 @@ fn ulong hash(char[] data, ulong seed = 0)
|
||||
// NOTE: This is translated from the original code. It grabs the last ulong off the buffer even though the
|
||||
// data slice is less than 8 bytes. This is possible because this branch only occurs in a loop where
|
||||
// the original data slice length is >= 32.
|
||||
r1h = (((@unaligned_load(*(ulong*)(data.ptr + data.len - 8), 1) >> 8) | ((ulong)1 << 56)) >> ((data.len * 8) ^ 0x38)) ^ seed1;
|
||||
r1h = (((mem::load((ulong*)(data.ptr + data.len - 8), 1) >> 8) | ((ulong)1 << 56)) >> ((data.len * 8) ^ 0x38)) ^ seed1;
|
||||
r2h = seed5;
|
||||
}
|
||||
else
|
||||
{
|
||||
r1h = @unaligned_load(*(ulong*)data.ptr, 1) ^ seed1;
|
||||
r2h = (((@unaligned_load(*(ulong*)&data[^8], 1) >> 8) | ((ulong)1 << 56)) >> ((data.len * 8) ^ 0x78)) ^ seed5;
|
||||
r1h = mem::load((ulong*)data.ptr, 1) ^ seed1;
|
||||
r2h = (((mem::load((ulong*)&data[^8], 1) >> 8) | ((ulong)1 << 56)) >> ((data.len * 8) ^ 0x78)) ^ seed5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ macro @i(x, y, z) => y ^ (x | ~z);
|
||||
|
||||
macro void @step(#f, a, b, c, d, ptr, n, t, s)
|
||||
{
|
||||
*a += #f(b, c, d) + @unaligned_load(*(uint *)&ptr[n * 4], 2) + t;
|
||||
*a += #f(b, c, d) + mem::load((uint *)&ptr[n * 4], 2) + t;
|
||||
*a = (*a << s) | ((*a & 0xffffffff) >> (32 - s));
|
||||
*a += b;
|
||||
}
|
||||
|
||||
171
lib/std/hash/poly1305.c3
Normal file
171
lib/std/hash/poly1305.c3
Normal file
@@ -0,0 +1,171 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// Poly1305 code dedicated from repo: https://github.com/NotsoanoNimus/chacha20_aead.c3l (but massively cleaned)
|
||||
module std::hash::poly1305;
|
||||
|
||||
|
||||
<* The fixed output length of Poly1305 tags (hashes). *>
|
||||
const TAG_SIZE = 16;
|
||||
|
||||
<* Fixed length of a Poly1305 block. *>
|
||||
const BLOCK_SIZE = 16;
|
||||
|
||||
<* Fixed length of the required Poly1305 key, *>
|
||||
const KEY_SIZE = 32;
|
||||
|
||||
|
||||
struct Poly1305
|
||||
{
|
||||
ulong[3] h; // hash internal state
|
||||
uint128 r; // secret portion of key
|
||||
uint128 nonce; // initialization vector, derived from key
|
||||
char[TAG_SIZE] temp; // last partial ingestion state
|
||||
usz num; // index into last partial ingestion
|
||||
// Additional, cached state information:
|
||||
ulong r0;
|
||||
ulong r1;
|
||||
ulong s1;
|
||||
}
|
||||
|
||||
|
||||
<* Constant-time carrying computation for block permutations. *>
|
||||
macro ulong constant_time_carry(ulong a, ulong b) @local
|
||||
{
|
||||
return (a ^ ((a ^ b) | ((a - b) ^ b))) >> (bitsizeof(ulong) - 1);
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Compute a Poly1305 message authentication code for the input with the given key (secret + nonce) value.
|
||||
Note that this construct SHOULD NOT be used with the 'Hmac' module; it is its own MAC package.
|
||||
|
||||
@param[in] input
|
||||
@param key
|
||||
*>
|
||||
fn char[TAG_SIZE] hash(char[] input, char[KEY_SIZE] key)
|
||||
{
|
||||
Poly1305 p @noinit;
|
||||
p.init(key);
|
||||
p.update(input);
|
||||
return p.final();
|
||||
}
|
||||
|
||||
<* Alias for the `hash` function; Message Authentication Code. *>
|
||||
alias mac = hash;
|
||||
|
||||
<* Alias for the `hash` function; "tag" generation. *>
|
||||
alias tag = hash;
|
||||
|
||||
|
||||
fn void Poly1305.init(&self, char[KEY_SIZE] key)
|
||||
{
|
||||
*self = { // implicitly clears state as well
|
||||
.r = mem::load((uint128*)&key[ 0], 1) & 0x0ffffffc_0ffffffc_0ffffffc_0fffffff, // clamped per spec
|
||||
.nonce = mem::load((uint128*)&key[16], 1)
|
||||
};
|
||||
|
||||
self.r0 = @unaligned_load(((ulong*)&self.r)[0], 1);
|
||||
self.r1 = @unaligned_load(((ulong*)&self.r)[1], 1);
|
||||
|
||||
self.s1 = self.r1 + (self.r1 >> 2);
|
||||
}
|
||||
|
||||
|
||||
fn void Poly1305.update(&self, char[] input)
|
||||
{
|
||||
if (self.num) // currently between consuming full blocks?
|
||||
{
|
||||
usz rem = BLOCK_SIZE - self.num;
|
||||
if (input.len < rem)
|
||||
{
|
||||
self.temp[self.num:input.len] = input[..]; // saving another partial block
|
||||
self.num += input.len; // move index forward
|
||||
return;
|
||||
}
|
||||
// ingest up to a block size to finish the partial, then advance the slice ptr
|
||||
self.temp[self.num:rem] = input[:rem];
|
||||
self.blocks(self.temp[..]);
|
||||
input = input[rem..];
|
||||
}
|
||||
|
||||
usz even_length = input.len - (input.len % BLOCK_SIZE);
|
||||
if (even_length >= BLOCK_SIZE)
|
||||
{
|
||||
self.blocks(input[:even_length]); // consume blocks
|
||||
input = input[even_length..]; // scroll to end (remainder)
|
||||
}
|
||||
|
||||
if (input.len) self.temp[:input.len] = input[..]; // keep remainder (uneven block sizes)
|
||||
|
||||
self.num = input.len;
|
||||
}
|
||||
|
||||
|
||||
fn char[TAG_SIZE] Poly1305.final(&self)
|
||||
{
|
||||
if (self.num) // consume any leftovers
|
||||
{
|
||||
self.temp[self.num++] = 1; // partial blocks must end with 0x01
|
||||
self.temp[self.num..] = {}; // explicit zeros on the rest
|
||||
self.blocks(self.temp[..], 0); // chomp
|
||||
}
|
||||
|
||||
uint128 t = (uint128)self.h[0] + 5;
|
||||
ulong g0 = (ulong)t;
|
||||
|
||||
t = (uint128)self.h[1] + (t >> 64);
|
||||
ulong g1 = (ulong)t;
|
||||
|
||||
ulong mask = 0 - ((self.h[2] + (ulong)(t >> 64)) >> 2);
|
||||
self.h[0] = (self.h[0] & ~mask) | (g0 & mask);
|
||||
self.h[1] = (self.h[1] & ~mask) | (g1 & mask);
|
||||
|
||||
t = (uint128)self.h[0] + (ulong)self.nonce;
|
||||
self.h[0] = (ulong)t;
|
||||
|
||||
t = (uint128)self.h[1] + (ulong)(self.nonce >> 64) + (t >> 64);
|
||||
self.h[1] = (ulong)t;
|
||||
|
||||
// Store, clear context, return.
|
||||
uint128 result = ((uint128)self.h[1] << 64) + self.h[0];
|
||||
*self = {};
|
||||
return @as_char_view(result)[:TAG_SIZE];
|
||||
}
|
||||
|
||||
|
||||
fn void Poly1305.blocks(&self, char[] input, ulong pad_bit = 1) @local
|
||||
{
|
||||
for (; input.len >= BLOCK_SIZE; input = input[BLOCK_SIZE..])
|
||||
{
|
||||
ulong i0 = mem::load((ulong*)&input[0], 1);
|
||||
ulong i1 = mem::load((ulong*)&input[8], 1);
|
||||
|
||||
uint128 d0 = (uint128)self.h[0] + i0;
|
||||
self.h[0] = (ulong)d0;
|
||||
|
||||
uint128 d1 = (uint128)self.h[1] + (d0 >> 64) + i1;
|
||||
self.h[1] = (ulong)d1;
|
||||
|
||||
self.h[2] += (ulong)(d1 >> 64) + pad_bit;
|
||||
|
||||
d0 = ((uint128)self.h[0] * self.r0) + ((uint128)self.h[1] * self.s1);
|
||||
d1 = ((uint128)self.h[0] * self.r1) + ((uint128)self.h[1] * self.r0) + ((uint128)self.h[2] * self.s1);
|
||||
self.h[2] = (self.h[2] * self.r0);
|
||||
|
||||
self.h[0] = (ulong)d0;
|
||||
|
||||
d1 = d1 + (d0 >> 64);
|
||||
self.h[1] = (ulong)d1;
|
||||
self.h[2] = self.h[2] + (ulong)(d1 >> 64);
|
||||
|
||||
ulong c = (self.h[2] >> 2) + (self.h[2] & ~(ulong)3);
|
||||
|
||||
self.h[2] &= 3;
|
||||
self.h[0] += c;
|
||||
c = constant_time_carry(self.h[0], c);
|
||||
self.h[1] += c;
|
||||
self.h[2] += constant_time_carry(self.h[1], c);
|
||||
}
|
||||
}
|
||||
577
lib/std/hash/ripemd.c3
Normal file
577
lib/std/hash/ripemd.c3
Normal file
@@ -0,0 +1,577 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
|
||||
module std::hash::ripemd;
|
||||
const usz[4] PERMISSIBLE_SIZES_BITS = { 128, 160, 256, 320 };
|
||||
|
||||
<* Unchanging block size. *>
|
||||
const BLOCK_SIZE = 64;
|
||||
|
||||
|
||||
<* RIPE-MD initial values. *>
|
||||
const uint[10] H = {
|
||||
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0,
|
||||
0x76543210, 0xfedcba98, 0x89abcdef, 0x01234567, 0x3c2d1e0f
|
||||
};
|
||||
|
||||
<* RIPE-MD constant values. *>
|
||||
const uint[9] K = {
|
||||
0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e,
|
||||
0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9
|
||||
};
|
||||
|
||||
<*
|
||||
@require @in(DIGEST_BITS, ...PERMISSIBLE_SIZES_BITS) : "Invalid DIGEST_BITS; must be one of {128, 160, 256, 320}."
|
||||
*>
|
||||
module std::hash::ripemd <DIGEST_BITS>;
|
||||
|
||||
<* Ultimate digest's size in bytes. *>
|
||||
const DIGEST_BYTES = DIGEST_BITS / 8;
|
||||
|
||||
|
||||
struct RipeMd
|
||||
{
|
||||
uint[10] state;
|
||||
uint[16] buffer;
|
||||
ulong byte_count;
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Compute the RIPE-MD hash of the given data.
|
||||
|
||||
@param [in] data : "The data to hash."
|
||||
*>
|
||||
macro char[*] hash(char[] data)
|
||||
{
|
||||
RipeMd r @noinit;
|
||||
r.init();
|
||||
r.update(data);
|
||||
return r.final();
|
||||
}
|
||||
|
||||
<*
|
||||
Initialize the RIPE-MD hash context.
|
||||
*>
|
||||
fn void RipeMd.init(&self)
|
||||
{
|
||||
mem::zero_volatile(@as_char_view(*self));
|
||||
self.state[..] = H[..];
|
||||
// I don't care about the reason, I want to strangle whoever thought this was a good idea.
|
||||
// I get it, you have to set the lane initializers correctly, but damn I want my hours back.
|
||||
$if DIGEST_BITS == 256: self.state[4:4] = self.state[5:4]; $endif
|
||||
}
|
||||
|
||||
<*
|
||||
Update the RIPE-MD hash context with the given data.
|
||||
|
||||
@param [in] data : "The data to digest."
|
||||
*>
|
||||
fn void RipeMd.update(&self, char[] data)
|
||||
{
|
||||
usz $bufsz = $sizeof(self.buffer);
|
||||
uint avail = $bufsz - (uint)(self.byte_count & 0x3f);
|
||||
self.byte_count += data.len;
|
||||
|
||||
if (avail > data.len)
|
||||
{
|
||||
@as_char_view(self.buffer)[($bufsz - avail) : data.len] = data[..];
|
||||
return;
|
||||
}
|
||||
|
||||
@as_char_view(self.buffer)[($bufsz - avail) : avail] = data[:avail];
|
||||
self.transform(self.buffer);
|
||||
data = data[avail..];
|
||||
|
||||
for (bool is_aligned = 0 == (usz)data.ptr % uint.sizeof; data.len >= $bufsz; data = data[$bufsz..])
|
||||
{
|
||||
if (is_aligned) // when aligned, this optimization is a ~10-20% performance boost
|
||||
{
|
||||
self.transform(((uint*)data.ptr)[:$bufsz / uint.sizeof]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@as_char_view(self.buffer)[:$bufsz] = data[:$bufsz];
|
||||
self.transform(self.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@as_char_view(self.buffer)[:data.len] = data[..];
|
||||
}
|
||||
|
||||
<*
|
||||
Finalize the RIPE-MD hash context and return the final hash value.
|
||||
This implicitly destroys the underlying hash structure for the sake of security.
|
||||
*>
|
||||
fn char[DIGEST_BYTES] RipeMd.final(&self)
|
||||
{
|
||||
char[DIGEST_BYTES] result @align(uint.sizeof);
|
||||
static char[64] padding = { [0] = 0x80, [1..63] = 0x00 };
|
||||
|
||||
// Napkin maffs.
|
||||
ulong bits = (ulong)self.byte_count << 3;
|
||||
uint index = (uint)self.byte_count & 0x3f;
|
||||
uint padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
|
||||
|
||||
// Update with padding, then append bit-length of digested message.
|
||||
self.update(padding[:padlen]);
|
||||
self.update(@as_char_view(bits));
|
||||
|
||||
// Clean up implicitly.
|
||||
defer mem::zero_volatile(@as_char_view(*self));
|
||||
|
||||
// Copy and return.
|
||||
((uint*)&result)[:DIGEST_BYTES / uint.sizeof] = self.state[:DIGEST_BYTES / uint.sizeof];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// State-based permutation functions given as a function pointer to each computation lane.
|
||||
fn uint f1(uint x, uint y, uint z) @inline @local => x ^ y ^ z;
|
||||
fn uint f2(uint x, uint y, uint z) @inline @local => z ^ (x & (y ^ z));
|
||||
fn uint f3(uint x, uint y, uint z) @inline @local => (x | ~y) ^ z;
|
||||
fn uint f4(uint x, uint y, uint z) @inline @local => y ^ (z & (x ^ y));
|
||||
fn uint f5(uint x, uint y, uint z) @inline @local => x ^ (y | ~z);
|
||||
|
||||
// The primary workhorse of the digest function. Behavior only changes slightly.
|
||||
// All 128/256 inputs will expand with 'e' as 0 - they don't use it anyway.
|
||||
macro @round(#a, b, #c, d, e, #func, k, x, s) @local
|
||||
{
|
||||
#a += #func(b, #c, d) + x + k;
|
||||
$switch:
|
||||
$case DIGEST_BITS == 128 ||| DIGEST_BITS == 256:
|
||||
#a = #a.rotl(s);
|
||||
$case DIGEST_BITS == 160 ||| DIGEST_BITS == 320:
|
||||
#a = #a.rotl(s) + e;
|
||||
#c = #c.rotl(10);
|
||||
$default:
|
||||
$error "Invalid digest bits";
|
||||
$endswitch
|
||||
}
|
||||
|
||||
<*
|
||||
Apply a transformation to some input data, but DO NOT inline the contents of the macro within the parent call.
|
||||
|
||||
@param in : "Data or message block to process."
|
||||
*>
|
||||
fn void RipeMd.transform(&self, uint[BLOCK_SIZE / uint.sizeof] in) @noinline => self.@transform(in);
|
||||
|
||||
<*
|
||||
@param in : "Data or message block to process."
|
||||
*>
|
||||
macro RipeMd.@transform(&self, uint[BLOCK_SIZE / uint.sizeof] in) @local
|
||||
{
|
||||
uint aa, bb, cc, dd, ee, aaa, bbb, ccc, ddd, eee;
|
||||
uint[] state = self.state[..];
|
||||
|
||||
// Run computations lanes based on the size of the resulting digest.
|
||||
// The behavior is different enough for each that this can simply stay broken out into separate cases.
|
||||
// Otherwise, lacing them all together is just not worth the effort and isn't as clear to other developers.
|
||||
// (No shade, but see 'RustCrypto/hashes' RIPE-MD macros for an example of what I mean...)
|
||||
$switch DIGEST_BITS:
|
||||
$case 128:
|
||||
aa = state[0];
|
||||
bb = state[1];
|
||||
cc = state[2];
|
||||
dd = state[3];
|
||||
aaa = state[0];
|
||||
bbb = state[1];
|
||||
ccc = state[2];
|
||||
ddd = state[3];
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[0], 11); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[5], 8);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[1], 14); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[14], 9);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[2], 15); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[7], 9);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[3], 12); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[0], 11);
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[4], 5); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[9], 13);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[5], 8); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[2], 15);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[6], 7); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[11], 15);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[7], 9); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[4], 5);
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[8], 11); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[13], 7);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[9], 13); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[6], 7);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[10], 14); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[15], 8);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[11], 15); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[8], 11);
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[12], 6); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[1], 14);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[13], 7); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[10], 14);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[14], 9); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[3], 12);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[15], 8); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[12], 6);
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[7], 7); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[6], 9);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[4], 6); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[11], 13);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[13], 8); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[3], 15);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[1], 13); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[7], 7);
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[10], 11); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[0], 12);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[6], 9); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[13], 8);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[15], 7); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[5], 9);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[3], 15); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[10], 11);
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[12], 7); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[14], 7);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[0], 12); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[15], 7);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[9], 15); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[8], 12);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[5], 9); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[12], 7);
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[2], 11); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[4], 6);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[14], 7); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[9], 15);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[11], 13); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[1], 13);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[8], 12); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[2], 11);
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[3], 11); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[15], 9);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[10], 13); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[5], 7);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[14], 6); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[1], 15);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[4], 7); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[3], 11);
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[9], 14); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[7], 8);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[15], 9); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[14], 6);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[8], 13); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[6], 6);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[1], 15); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[9], 14);
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[2], 14); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[11], 12);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[7], 8); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[8], 13);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[0], 13); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[12], 5);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[6], 6); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[2], 14);
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[13], 5); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[10], 13);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[11], 12); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[0], 13);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[5], 7); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[4], 7);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[12], 5); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[13], 5);
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[1], 11); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[8], 15);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[9], 12); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[6], 5);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[11], 14); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[4], 8);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[10], 15); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[1], 11);
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[0], 14); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[3], 14);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[8], 15); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[11], 14);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[12], 9); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[15], 6);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[4], 8); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[0], 14);
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[13], 9); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[5], 6);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[3], 14); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[12], 9);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[7], 5); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[2], 12);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[15], 6); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[13], 9);
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[14], 8); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[9], 12);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[5], 6); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[7], 5);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[6], 5); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[10], 15);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[2], 12); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[14], 8);
|
||||
|
||||
ddd += cc + state[1];
|
||||
state[1] = state[2] + dd + aaa;
|
||||
state[2] = state[3] + aa + bbb;
|
||||
state[3] = state[0] + bb + ccc;
|
||||
state[0] = ddd;
|
||||
|
||||
$case 160:
|
||||
aa = state[0];
|
||||
bb = state[1];
|
||||
cc = state[2];
|
||||
dd = state[3];
|
||||
ee = state[4];
|
||||
aaa = state[0];
|
||||
bbb = state[1];
|
||||
ccc = state[2];
|
||||
ddd = state[3];
|
||||
eee = state[4];
|
||||
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[0], 11); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[5], 8);
|
||||
@round(ee, aa, bb, cc, dd, f1, K[0], in[1], 14); @round(eee, aaa, bbb, ccc, ddd, f5, K[5], in[14], 9);
|
||||
@round(dd, ee, aa, bb, cc, f1, K[0], in[2], 15); @round(ddd, eee, aaa, bbb, ccc, f5, K[5], in[7], 9);
|
||||
@round(cc, dd, ee, aa, bb, f1, K[0], in[3], 12); @round(ccc, ddd, eee, aaa, bbb, f5, K[5], in[0], 11);
|
||||
@round(bb, cc, dd, ee, aa, f1, K[0], in[4], 5); @round(bbb, ccc, ddd, eee, aaa, f5, K[5], in[9], 13);
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[5], 8); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[2], 15);
|
||||
@round(ee, aa, bb, cc, dd, f1, K[0], in[6], 7); @round(eee, aaa, bbb, ccc, ddd, f5, K[5], in[11], 15);
|
||||
@round(dd, ee, aa, bb, cc, f1, K[0], in[7], 9); @round(ddd, eee, aaa, bbb, ccc, f5, K[5], in[4], 5);
|
||||
@round(cc, dd, ee, aa, bb, f1, K[0], in[8], 11); @round(ccc, ddd, eee, aaa, bbb, f5, K[5], in[13], 7);
|
||||
@round(bb, cc, dd, ee, aa, f1, K[0], in[9], 13); @round(bbb, ccc, ddd, eee, aaa, f5, K[5], in[6], 7);
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[10], 14); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[15], 8);
|
||||
@round(ee, aa, bb, cc, dd, f1, K[0], in[11], 15); @round(eee, aaa, bbb, ccc, ddd, f5, K[5], in[8], 11);
|
||||
@round(dd, ee, aa, bb, cc, f1, K[0], in[12], 6); @round(ddd, eee, aaa, bbb, ccc, f5, K[5], in[1], 14);
|
||||
@round(cc, dd, ee, aa, bb, f1, K[0], in[13], 7); @round(ccc, ddd, eee, aaa, bbb, f5, K[5], in[10], 14);
|
||||
@round(bb, cc, dd, ee, aa, f1, K[0], in[14], 9); @round(bbb, ccc, ddd, eee, aaa, f5, K[5], in[3], 12);
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[15], 8); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[12], 6);
|
||||
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[7], 7); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[6], 9);
|
||||
@round(dd, ee, aa, bb, cc, f2, K[1], in[4], 6); @round(ddd, eee, aaa, bbb, ccc, f4, K[6], in[11], 13);
|
||||
@round(cc, dd, ee, aa, bb, f2, K[1], in[13], 8); @round(ccc, ddd, eee, aaa, bbb, f4, K[6], in[3], 15);
|
||||
@round(bb, cc, dd, ee, aa, f2, K[1], in[1], 13); @round(bbb, ccc, ddd, eee, aaa, f4, K[6], in[7], 7);
|
||||
@round(aa, bb, cc, dd, ee, f2, K[1], in[10], 11); @round(aaa, bbb, ccc, ddd, eee, f4, K[6], in[0], 12);
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[6], 9); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[13], 8);
|
||||
@round(dd, ee, aa, bb, cc, f2, K[1], in[15], 7); @round(ddd, eee, aaa, bbb, ccc, f4, K[6], in[5], 9);
|
||||
@round(cc, dd, ee, aa, bb, f2, K[1], in[3], 15); @round(ccc, ddd, eee, aaa, bbb, f4, K[6], in[10], 11);
|
||||
@round(bb, cc, dd, ee, aa, f2, K[1], in[12], 7); @round(bbb, ccc, ddd, eee, aaa, f4, K[6], in[14], 7);
|
||||
@round(aa, bb, cc, dd, ee, f2, K[1], in[0], 12); @round(aaa, bbb, ccc, ddd, eee, f4, K[6], in[15], 7);
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[9], 15); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[8], 12);
|
||||
@round(dd, ee, aa, bb, cc, f2, K[1], in[5], 9); @round(ddd, eee, aaa, bbb, ccc, f4, K[6], in[12], 7);
|
||||
@round(cc, dd, ee, aa, bb, f2, K[1], in[2], 11); @round(ccc, ddd, eee, aaa, bbb, f4, K[6], in[4], 6);
|
||||
@round(bb, cc, dd, ee, aa, f2, K[1], in[14], 7); @round(bbb, ccc, ddd, eee, aaa, f4, K[6], in[9], 15);
|
||||
@round(aa, bb, cc, dd, ee, f2, K[1], in[11], 13); @round(aaa, bbb, ccc, ddd, eee, f4, K[6], in[1], 13);
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[8], 12); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[2], 11);
|
||||
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[3], 11); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[15], 9);
|
||||
@round(cc, dd, ee, aa, bb, f3, K[2], in[10], 13); @round(ccc, ddd, eee, aaa, bbb, f3, K[7], in[5], 7);
|
||||
@round(bb, cc, dd, ee, aa, f3, K[2], in[14], 6); @round(bbb, ccc, ddd, eee, aaa, f3, K[7], in[1], 15);
|
||||
@round(aa, bb, cc, dd, ee, f3, K[2], in[4], 7); @round(aaa, bbb, ccc, ddd, eee, f3, K[7], in[3], 11);
|
||||
@round(ee, aa, bb, cc, dd, f3, K[2], in[9], 14); @round(eee, aaa, bbb, ccc, ddd, f3, K[7], in[7], 8);
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[15], 9); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[14], 6);
|
||||
@round(cc, dd, ee, aa, bb, f3, K[2], in[8], 13); @round(ccc, ddd, eee, aaa, bbb, f3, K[7], in[6], 6);
|
||||
@round(bb, cc, dd, ee, aa, f3, K[2], in[1], 15); @round(bbb, ccc, ddd, eee, aaa, f3, K[7], in[9], 14);
|
||||
@round(aa, bb, cc, dd, ee, f3, K[2], in[2], 14); @round(aaa, bbb, ccc, ddd, eee, f3, K[7], in[11], 12);
|
||||
@round(ee, aa, bb, cc, dd, f3, K[2], in[7], 8); @round(eee, aaa, bbb, ccc, ddd, f3, K[7], in[8], 13);
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[0], 13); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[12], 5);
|
||||
@round(cc, dd, ee, aa, bb, f3, K[2], in[6], 6); @round(ccc, ddd, eee, aaa, bbb, f3, K[7], in[2], 14);
|
||||
@round(bb, cc, dd, ee, aa, f3, K[2], in[13], 5); @round(bbb, ccc, ddd, eee, aaa, f3, K[7], in[10], 13);
|
||||
@round(aa, bb, cc, dd, ee, f3, K[2], in[11], 12); @round(aaa, bbb, ccc, ddd, eee, f3, K[7], in[0], 13);
|
||||
@round(ee, aa, bb, cc, dd, f3, K[2], in[5], 7); @round(eee, aaa, bbb, ccc, ddd, f3, K[7], in[4], 7);
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[12], 5); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[13], 5);
|
||||
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[1], 11); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[8], 15);
|
||||
@round(bb, cc, dd, ee, aa, f4, K[3], in[9], 12); @round(bbb, ccc, ddd, eee, aaa, f2, K[8], in[6], 5);
|
||||
@round(aa, bb, cc, dd, ee, f4, K[3], in[11], 14); @round(aaa, bbb, ccc, ddd, eee, f2, K[8], in[4], 8);
|
||||
@round(ee, aa, bb, cc, dd, f4, K[3], in[10], 15); @round(eee, aaa, bbb, ccc, ddd, f2, K[8], in[1], 11);
|
||||
@round(dd, ee, aa, bb, cc, f4, K[3], in[0], 14); @round(ddd, eee, aaa, bbb, ccc, f2, K[8], in[3], 14);
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[8], 15); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[11], 14);
|
||||
@round(bb, cc, dd, ee, aa, f4, K[3], in[12], 9); @round(bbb, ccc, ddd, eee, aaa, f2, K[8], in[15], 6);
|
||||
@round(aa, bb, cc, dd, ee, f4, K[3], in[4], 8); @round(aaa, bbb, ccc, ddd, eee, f2, K[8], in[0], 14);
|
||||
@round(ee, aa, bb, cc, dd, f4, K[3], in[13], 9); @round(eee, aaa, bbb, ccc, ddd, f2, K[8], in[5], 6);
|
||||
@round(dd, ee, aa, bb, cc, f4, K[3], in[3], 14); @round(ddd, eee, aaa, bbb, ccc, f2, K[8], in[12], 9);
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[7], 5); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[2], 12);
|
||||
@round(bb, cc, dd, ee, aa, f4, K[3], in[15], 6); @round(bbb, ccc, ddd, eee, aaa, f2, K[8], in[13], 9);
|
||||
@round(aa, bb, cc, dd, ee, f4, K[3], in[14], 8); @round(aaa, bbb, ccc, ddd, eee, f2, K[8], in[9], 12);
|
||||
@round(ee, aa, bb, cc, dd, f4, K[3], in[5], 6); @round(eee, aaa, bbb, ccc, ddd, f2, K[8], in[7], 5);
|
||||
@round(dd, ee, aa, bb, cc, f4, K[3], in[6], 5); @round(ddd, eee, aaa, bbb, ccc, f2, K[8], in[10], 15);
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[2], 12); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[14], 8);
|
||||
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[4], 9); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[12], 8);
|
||||
@round(aa, bb, cc, dd, ee, f5, K[4], in[0], 15); @round(aaa, bbb, ccc, ddd, eee, f1, 0, in[15], 5);
|
||||
@round(ee, aa, bb, cc, dd, f5, K[4], in[5], 5); @round(eee, aaa, bbb, ccc, ddd, f1, 0, in[10], 12);
|
||||
@round(dd, ee, aa, bb, cc, f5, K[4], in[9], 11); @round(ddd, eee, aaa, bbb, ccc, f1, 0, in[4], 9);
|
||||
@round(cc, dd, ee, aa, bb, f5, K[4], in[7], 6); @round(ccc, ddd, eee, aaa, bbb, f1, 0, in[1], 12);
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[12], 8); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[5], 5);
|
||||
@round(aa, bb, cc, dd, ee, f5, K[4], in[2], 13); @round(aaa, bbb, ccc, ddd, eee, f1, 0, in[8], 14);
|
||||
@round(ee, aa, bb, cc, dd, f5, K[4], in[10], 12); @round(eee, aaa, bbb, ccc, ddd, f1, 0, in[7], 6);
|
||||
@round(dd, ee, aa, bb, cc, f5, K[4], in[14], 5); @round(ddd, eee, aaa, bbb, ccc, f1, 0, in[6], 8);
|
||||
@round(cc, dd, ee, aa, bb, f5, K[4], in[1], 12); @round(ccc, ddd, eee, aaa, bbb, f1, 0, in[2], 13);
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[3], 13); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[13], 6);
|
||||
@round(aa, bb, cc, dd, ee, f5, K[4], in[8], 14); @round(aaa, bbb, ccc, ddd, eee, f1, 0, in[14], 5);
|
||||
@round(ee, aa, bb, cc, dd, f5, K[4], in[11], 11); @round(eee, aaa, bbb, ccc, ddd, f1, 0, in[0], 15);
|
||||
@round(dd, ee, aa, bb, cc, f5, K[4], in[6], 8); @round(ddd, eee, aaa, bbb, ccc, f1, 0, in[3], 13);
|
||||
@round(cc, dd, ee, aa, bb, f5, K[4], in[15], 5); @round(ccc, ddd, eee, aaa, bbb, f1, 0, in[9], 11);
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[13], 6); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[11], 11);
|
||||
|
||||
ddd += cc + state[1];
|
||||
state[1] = state[2] + dd + eee;
|
||||
state[2] = state[3] + ee + aaa;
|
||||
state[3] = state[4] + aa + bbb;
|
||||
state[4] = state[0] + bb + ccc;
|
||||
state[0] = ddd;
|
||||
|
||||
$case 256:
|
||||
aa = state[0];
|
||||
bb = state[1];
|
||||
cc = state[2];
|
||||
dd = state[3];
|
||||
aaa = state[4];
|
||||
bbb = state[5];
|
||||
ccc = state[6];
|
||||
ddd = state[7];
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[0], 11); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[5], 8);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[1], 14); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[14], 9);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[2], 15); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[7], 9);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[3], 12); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[0], 11);
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[4], 5); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[9], 13);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[5], 8); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[2], 15);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[6], 7); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[11], 15);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[7], 9); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[4], 5);
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[8], 11); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[13], 7);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[9], 13); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[6], 7);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[10], 14); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[15], 8);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[11], 15); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[8], 11);
|
||||
@round(aa, bb, cc, dd, 0, f1, K[0], in[12], 6); @round(aaa, bbb, ccc, ddd, 0, f4, K[5], in[1], 14);
|
||||
@round(dd, aa, bb, cc, 0, f1, K[0], in[13], 7); @round(ddd, aaa, bbb, ccc, 0, f4, K[5], in[10], 14);
|
||||
@round(cc, dd, aa, bb, 0, f1, K[0], in[14], 9); @round(ccc, ddd, aaa, bbb, 0, f4, K[5], in[3], 12);
|
||||
@round(bb, cc, dd, aa, 0, f1, K[0], in[15], 8); @round(bbb, ccc, ddd, aaa, 0, f4, K[5], in[12], 6);
|
||||
|
||||
@swap(aa, aaa);
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[7], 7); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[6], 9);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[4], 6); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[11], 13);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[13], 8); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[3], 15);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[1], 13); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[7], 7);
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[10], 11); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[0], 12);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[6], 9); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[13], 8);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[15], 7); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[5], 9);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[3], 15); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[10], 11);
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[12], 7); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[14], 7);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[0], 12); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[15], 7);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[9], 15); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[8], 12);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[5], 9); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[12], 7);
|
||||
@round(aa, bb, cc, dd, 0, f2, K[1], in[2], 11); @round(aaa, bbb, ccc, ddd, 0, f3, K[6], in[4], 6);
|
||||
@round(dd, aa, bb, cc, 0, f2, K[1], in[14], 7); @round(ddd, aaa, bbb, ccc, 0, f3, K[6], in[9], 15);
|
||||
@round(cc, dd, aa, bb, 0, f2, K[1], in[11], 13); @round(ccc, ddd, aaa, bbb, 0, f3, K[6], in[1], 13);
|
||||
@round(bb, cc, dd, aa, 0, f2, K[1], in[8], 12); @round(bbb, ccc, ddd, aaa, 0, f3, K[6], in[2], 11);
|
||||
|
||||
@swap(bb, bbb);
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[3], 11); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[15], 9);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[10], 13); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[5], 7);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[14], 6); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[1], 15);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[4], 7); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[3], 11);
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[9], 14); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[7], 8);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[15], 9); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[14], 6);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[8], 13); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[6], 6);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[1], 15); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[9], 14);
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[2], 14); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[11], 12);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[7], 8); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[8], 13);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[0], 13); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[12], 5);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[6], 6); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[2], 14);
|
||||
@round(aa, bb, cc, dd, 0, f3, K[2], in[13], 5); @round(aaa, bbb, ccc, ddd, 0, f2, K[7], in[10], 13);
|
||||
@round(dd, aa, bb, cc, 0, f3, K[2], in[11], 12); @round(ddd, aaa, bbb, ccc, 0, f2, K[7], in[0], 13);
|
||||
@round(cc, dd, aa, bb, 0, f3, K[2], in[5], 7); @round(ccc, ddd, aaa, bbb, 0, f2, K[7], in[4], 7);
|
||||
@round(bb, cc, dd, aa, 0, f3, K[2], in[12], 5); @round(bbb, ccc, ddd, aaa, 0, f2, K[7], in[13], 5);
|
||||
|
||||
@swap(cc, ccc);
|
||||
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[1], 11); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[8], 15);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[9], 12); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[6], 5);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[11], 14); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[4], 8);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[10], 15); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[1], 11);
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[0], 14); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[3], 14);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[8], 15); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[11], 14);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[12], 9); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[15], 6);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[4], 8); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[0], 14);
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[13], 9); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[5], 6);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[3], 14); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[12], 9);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[7], 5); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[2], 12);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[15], 6); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[13], 9);
|
||||
@round(aa, bb, cc, dd, 0, f4, K[3], in[14], 8); @round(aaa, bbb, ccc, ddd, 0, f1, 0, in[9], 12);
|
||||
@round(dd, aa, bb, cc, 0, f4, K[3], in[5], 6); @round(ddd, aaa, bbb, ccc, 0, f1, 0, in[7], 5);
|
||||
@round(cc, dd, aa, bb, 0, f4, K[3], in[6], 5); @round(ccc, ddd, aaa, bbb, 0, f1, 0, in[10], 15);
|
||||
@round(bb, cc, dd, aa, 0, f4, K[3], in[2], 12); @round(bbb, ccc, ddd, aaa, 0, f1, 0, in[14], 8);
|
||||
|
||||
@swap(dd, ddd);
|
||||
|
||||
state[0] += aa;
|
||||
state[1] += bb;
|
||||
state[2] += cc;
|
||||
state[3] += dd;
|
||||
state[4] += aaa;
|
||||
state[5] += bbb;
|
||||
state[6] += ccc;
|
||||
state[7] += ddd;
|
||||
|
||||
$case 320:
|
||||
aa = state[0];
|
||||
bb = state[1];
|
||||
cc = state[2];
|
||||
dd = state[3];
|
||||
ee = state[4];
|
||||
aaa = state[5];
|
||||
bbb = state[6];
|
||||
ccc = state[7];
|
||||
ddd = state[8];
|
||||
eee = state[9];
|
||||
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[0], 11); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[5], 8);
|
||||
@round(ee, aa, bb, cc, dd, f1, K[0], in[1], 14); @round(eee, aaa, bbb, ccc, ddd, f5, K[5], in[14], 9);
|
||||
@round(dd, ee, aa, bb, cc, f1, K[0], in[2], 15); @round(ddd, eee, aaa, bbb, ccc, f5, K[5], in[7], 9);
|
||||
@round(cc, dd, ee, aa, bb, f1, K[0], in[3], 12); @round(ccc, ddd, eee, aaa, bbb, f5, K[5], in[0], 11);
|
||||
@round(bb, cc, dd, ee, aa, f1, K[0], in[4], 5); @round(bbb, ccc, ddd, eee, aaa, f5, K[5], in[9], 13);
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[5], 8); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[2], 15);
|
||||
@round(ee, aa, bb, cc, dd, f1, K[0], in[6], 7); @round(eee, aaa, bbb, ccc, ddd, f5, K[5], in[11], 15);
|
||||
@round(dd, ee, aa, bb, cc, f1, K[0], in[7], 9); @round(ddd, eee, aaa, bbb, ccc, f5, K[5], in[4], 5);
|
||||
@round(cc, dd, ee, aa, bb, f1, K[0], in[8], 11); @round(ccc, ddd, eee, aaa, bbb, f5, K[5], in[13], 7);
|
||||
@round(bb, cc, dd, ee, aa, f1, K[0], in[9], 13); @round(bbb, ccc, ddd, eee, aaa, f5, K[5], in[6], 7);
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[10], 14); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[15], 8);
|
||||
@round(ee, aa, bb, cc, dd, f1, K[0], in[11], 15); @round(eee, aaa, bbb, ccc, ddd, f5, K[5], in[8], 11);
|
||||
@round(dd, ee, aa, bb, cc, f1, K[0], in[12], 6); @round(ddd, eee, aaa, bbb, ccc, f5, K[5], in[1], 14);
|
||||
@round(cc, dd, ee, aa, bb, f1, K[0], in[13], 7); @round(ccc, ddd, eee, aaa, bbb, f5, K[5], in[10], 14);
|
||||
@round(bb, cc, dd, ee, aa, f1, K[0], in[14], 9); @round(bbb, ccc, ddd, eee, aaa, f5, K[5], in[3], 12);
|
||||
@round(aa, bb, cc, dd, ee, f1, K[0], in[15], 8); @round(aaa, bbb, ccc, ddd, eee, f5, K[5], in[12], 6);
|
||||
|
||||
@swap(aa, aaa);
|
||||
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[7], 7); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[6], 9);
|
||||
@round(dd, ee, aa, bb, cc, f2, K[1], in[4], 6); @round(ddd, eee, aaa, bbb, ccc, f4, K[6], in[11], 13);
|
||||
@round(cc, dd, ee, aa, bb, f2, K[1], in[13], 8); @round(ccc, ddd, eee, aaa, bbb, f4, K[6], in[3], 15);
|
||||
@round(bb, cc, dd, ee, aa, f2, K[1], in[1], 13); @round(bbb, ccc, ddd, eee, aaa, f4, K[6], in[7], 7);
|
||||
@round(aa, bb, cc, dd, ee, f2, K[1], in[10], 11); @round(aaa, bbb, ccc, ddd, eee, f4, K[6], in[0], 12);
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[6], 9); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[13], 8);
|
||||
@round(dd, ee, aa, bb, cc, f2, K[1], in[15], 7); @round(ddd, eee, aaa, bbb, ccc, f4, K[6], in[5], 9);
|
||||
@round(cc, dd, ee, aa, bb, f2, K[1], in[3], 15); @round(ccc, ddd, eee, aaa, bbb, f4, K[6], in[10], 11);
|
||||
@round(bb, cc, dd, ee, aa, f2, K[1], in[12], 7); @round(bbb, ccc, ddd, eee, aaa, f4, K[6], in[14], 7);
|
||||
@round(aa, bb, cc, dd, ee, f2, K[1], in[0], 12); @round(aaa, bbb, ccc, ddd, eee, f4, K[6], in[15], 7);
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[9], 15); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[8], 12);
|
||||
@round(dd, ee, aa, bb, cc, f2, K[1], in[5], 9); @round(ddd, eee, aaa, bbb, ccc, f4, K[6], in[12], 7);
|
||||
@round(cc, dd, ee, aa, bb, f2, K[1], in[2], 11); @round(ccc, ddd, eee, aaa, bbb, f4, K[6], in[4], 6);
|
||||
@round(bb, cc, dd, ee, aa, f2, K[1], in[14], 7); @round(bbb, ccc, ddd, eee, aaa, f4, K[6], in[9], 15);
|
||||
@round(aa, bb, cc, dd, ee, f2, K[1], in[11], 13); @round(aaa, bbb, ccc, ddd, eee, f4, K[6], in[1], 13);
|
||||
@round(ee, aa, bb, cc, dd, f2, K[1], in[8], 12); @round(eee, aaa, bbb, ccc, ddd, f4, K[6], in[2], 11);
|
||||
|
||||
@swap(bb, bbb);
|
||||
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[3], 11); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[15], 9);
|
||||
@round(cc, dd, ee, aa, bb, f3, K[2], in[10], 13); @round(ccc, ddd, eee, aaa, bbb, f3, K[7], in[5], 7);
|
||||
@round(bb, cc, dd, ee, aa, f3, K[2], in[14], 6); @round(bbb, ccc, ddd, eee, aaa, f3, K[7], in[1], 15);
|
||||
@round(aa, bb, cc, dd, ee, f3, K[2], in[4], 7); @round(aaa, bbb, ccc, ddd, eee, f3, K[7], in[3], 11);
|
||||
@round(ee, aa, bb, cc, dd, f3, K[2], in[9], 14); @round(eee, aaa, bbb, ccc, ddd, f3, K[7], in[7], 8);
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[15], 9); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[14], 6);
|
||||
@round(cc, dd, ee, aa, bb, f3, K[2], in[8], 13); @round(ccc, ddd, eee, aaa, bbb, f3, K[7], in[6], 6);
|
||||
@round(bb, cc, dd, ee, aa, f3, K[2], in[1], 15); @round(bbb, ccc, ddd, eee, aaa, f3, K[7], in[9], 14);
|
||||
@round(aa, bb, cc, dd, ee, f3, K[2], in[2], 14); @round(aaa, bbb, ccc, ddd, eee, f3, K[7], in[11], 12);
|
||||
@round(ee, aa, bb, cc, dd, f3, K[2], in[7], 8); @round(eee, aaa, bbb, ccc, ddd, f3, K[7], in[8], 13);
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[0], 13); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[12], 5);
|
||||
@round(cc, dd, ee, aa, bb, f3, K[2], in[6], 6); @round(ccc, ddd, eee, aaa, bbb, f3, K[7], in[2], 14);
|
||||
@round(bb, cc, dd, ee, aa, f3, K[2], in[13], 5); @round(bbb, ccc, ddd, eee, aaa, f3, K[7], in[10], 13);
|
||||
@round(aa, bb, cc, dd, ee, f3, K[2], in[11], 12); @round(aaa, bbb, ccc, ddd, eee, f3, K[7], in[0], 13);
|
||||
@round(ee, aa, bb, cc, dd, f3, K[2], in[5], 7); @round(eee, aaa, bbb, ccc, ddd, f3, K[7], in[4], 7);
|
||||
@round(dd, ee, aa, bb, cc, f3, K[2], in[12], 5); @round(ddd, eee, aaa, bbb, ccc, f3, K[7], in[13], 5);
|
||||
|
||||
@swap(cc, ccc);
|
||||
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[1], 11); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[8], 15);
|
||||
@round(bb, cc, dd, ee, aa, f4, K[3], in[9], 12); @round(bbb, ccc, ddd, eee, aaa, f2, K[8], in[6], 5);
|
||||
@round(aa, bb, cc, dd, ee, f4, K[3], in[11], 14); @round(aaa, bbb, ccc, ddd, eee, f2, K[8], in[4], 8);
|
||||
@round(ee, aa, bb, cc, dd, f4, K[3], in[10], 15); @round(eee, aaa, bbb, ccc, ddd, f2, K[8], in[1], 11);
|
||||
@round(dd, ee, aa, bb, cc, f4, K[3], in[0], 14); @round(ddd, eee, aaa, bbb, ccc, f2, K[8], in[3], 14);
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[8], 15); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[11], 14);
|
||||
@round(bb, cc, dd, ee, aa, f4, K[3], in[12], 9); @round(bbb, ccc, ddd, eee, aaa, f2, K[8], in[15], 6);
|
||||
@round(aa, bb, cc, dd, ee, f4, K[3], in[4], 8); @round(aaa, bbb, ccc, ddd, eee, f2, K[8], in[0], 14);
|
||||
@round(ee, aa, bb, cc, dd, f4, K[3], in[13], 9); @round(eee, aaa, bbb, ccc, ddd, f2, K[8], in[5], 6);
|
||||
@round(dd, ee, aa, bb, cc, f4, K[3], in[3], 14); @round(ddd, eee, aaa, bbb, ccc, f2, K[8], in[12], 9);
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[7], 5); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[2], 12);
|
||||
@round(bb, cc, dd, ee, aa, f4, K[3], in[15], 6); @round(bbb, ccc, ddd, eee, aaa, f2, K[8], in[13], 9);
|
||||
@round(aa, bb, cc, dd, ee, f4, K[3], in[14], 8); @round(aaa, bbb, ccc, ddd, eee, f2, K[8], in[9], 12);
|
||||
@round(ee, aa, bb, cc, dd, f4, K[3], in[5], 6); @round(eee, aaa, bbb, ccc, ddd, f2, K[8], in[7], 5);
|
||||
@round(dd, ee, aa, bb, cc, f4, K[3], in[6], 5); @round(ddd, eee, aaa, bbb, ccc, f2, K[8], in[10], 15);
|
||||
@round(cc, dd, ee, aa, bb, f4, K[3], in[2], 12); @round(ccc, ddd, eee, aaa, bbb, f2, K[8], in[14], 8);
|
||||
|
||||
@swap(dd, ddd);
|
||||
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[4], 9); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[12], 8);
|
||||
@round(aa, bb, cc, dd, ee, f5, K[4], in[0], 15); @round(aaa, bbb, ccc, ddd, eee, f1, 0, in[15], 5);
|
||||
@round(ee, aa, bb, cc, dd, f5, K[4], in[5], 5); @round(eee, aaa, bbb, ccc, ddd, f1, 0, in[10], 12);
|
||||
@round(dd, ee, aa, bb, cc, f5, K[4], in[9], 11); @round(ddd, eee, aaa, bbb, ccc, f1, 0, in[4], 9);
|
||||
@round(cc, dd, ee, aa, bb, f5, K[4], in[7], 6); @round(ccc, ddd, eee, aaa, bbb, f1, 0, in[1], 12);
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[12], 8); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[5], 5);
|
||||
@round(aa, bb, cc, dd, ee, f5, K[4], in[2], 13); @round(aaa, bbb, ccc, ddd, eee, f1, 0, in[8], 14);
|
||||
@round(ee, aa, bb, cc, dd, f5, K[4], in[10], 12); @round(eee, aaa, bbb, ccc, ddd, f1, 0, in[7], 6);
|
||||
@round(dd, ee, aa, bb, cc, f5, K[4], in[14], 5); @round(ddd, eee, aaa, bbb, ccc, f1, 0, in[6], 8);
|
||||
@round(cc, dd, ee, aa, bb, f5, K[4], in[1], 12); @round(ccc, ddd, eee, aaa, bbb, f1, 0, in[2], 13);
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[3], 13); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[13], 6);
|
||||
@round(aa, bb, cc, dd, ee, f5, K[4], in[8], 14); @round(aaa, bbb, ccc, ddd, eee, f1, 0, in[14], 5);
|
||||
@round(ee, aa, bb, cc, dd, f5, K[4], in[11], 11); @round(eee, aaa, bbb, ccc, ddd, f1, 0, in[0], 15);
|
||||
@round(dd, ee, aa, bb, cc, f5, K[4], in[6], 8); @round(ddd, eee, aaa, bbb, ccc, f1, 0, in[3], 13);
|
||||
@round(cc, dd, ee, aa, bb, f5, K[4], in[15], 5); @round(ccc, ddd, eee, aaa, bbb, f1, 0, in[9], 11);
|
||||
@round(bb, cc, dd, ee, aa, f5, K[4], in[13], 6); @round(bbb, ccc, ddd, eee, aaa, f1, 0, in[11], 11);
|
||||
|
||||
@swap(ee, eee);
|
||||
|
||||
state[0] += aa;
|
||||
state[1] += bb;
|
||||
state[2] += cc;
|
||||
state[3] += dd;
|
||||
state[4] += ee;
|
||||
state[5] += aaa;
|
||||
state[6] += bbb;
|
||||
state[7] += ccc;
|
||||
state[8] += ddd;
|
||||
state[9] += eee;
|
||||
|
||||
$default:
|
||||
$error "Invalid digest size";
|
||||
$endswitch
|
||||
}
|
||||
@@ -1,177 +1,175 @@
|
||||
module std::hash::sha256;
|
||||
|
||||
import std::hash::hmac;
|
||||
import std::bits, std::hash::hmac;
|
||||
|
||||
const BLOCK_SIZE = 64;
|
||||
const HASH_SIZE = 32;
|
||||
|
||||
const uint[64] K @local = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
// Right rotate function
|
||||
macro uint @rotr(uint x, uint n) @local => (((x) >> (n)) | ((x) << (32 - (n))));
|
||||
|
||||
// SHA-256 functions
|
||||
macro uint @ch(uint x, uint y, uint z) @local => (x & y) ^ (~x & z);
|
||||
macro uint @maj(uint x, uint y, uint z) @local => (x & y) ^ (x & z) ^ (y & z);
|
||||
macro uint @_sigma0(uint x) @local => @rotr(x, 2) ^ @rotr(x, 13) ^ @rotr(x, 22);
|
||||
macro uint @_sigma1(uint x) @local => @rotr(x, 6) ^ @rotr(x, 11) ^ @rotr(x, 25);
|
||||
macro uint @sigma0(uint x) @local => @rotr(x, 7) ^ @rotr(x, 18) ^ (x >> 3);
|
||||
macro uint @sigma1(uint x) @local => @rotr(x, 17) ^ @rotr(x, 19) ^ (x >> 10);
|
||||
|
||||
struct Sha256
|
||||
{
|
||||
uint[8] state;
|
||||
ulong bitcount;
|
||||
char[BLOCK_SIZE] buffer;
|
||||
}
|
||||
|
||||
alias HmacSha256 = Hmac{Sha256, HASH_SIZE, BLOCK_SIZE};
|
||||
alias hmac = hmac::hash{Sha256, HASH_SIZE, BLOCK_SIZE};
|
||||
alias pbkdf2 = hmac::pbkdf2{Sha256, HASH_SIZE, BLOCK_SIZE};
|
||||
|
||||
fn char[HASH_SIZE] hash(char[] data)
|
||||
const uint[64] K @local = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
macro uint @ch(uint x, uint y, uint z) @local => (x & y) ^ (~x & z);
|
||||
macro uint @maj(uint x, uint y, uint z) @local => (x & y) ^ (x & z) ^ (y & z);
|
||||
macro uint @_sigma0(uint x) @local => x.rotr(2) ^ x.rotr(13) ^ x.rotr(22);
|
||||
macro uint @_sigma1(uint x) @local => x.rotr(6) ^ x.rotr(11) ^ x.rotr(25);
|
||||
macro uint @sigma0(uint x) @local => x.rotr(7) ^ x.rotr(18) ^ (x >> 3);
|
||||
macro uint @sigma1(uint x) @local => x.rotr(17) ^ x.rotr(19) ^ (x >> 10);
|
||||
|
||||
struct Sha256
|
||||
{
|
||||
Sha256 sha256 @noinit;
|
||||
sha256.init();
|
||||
sha256.update(data);
|
||||
return sha256.final();
|
||||
uint[8] state @align(usz.sizeof);
|
||||
char[BLOCK_SIZE] buffer @align(ulong.sizeof); // must align along bitcount sizeof - see `final`
|
||||
ulong bitcount;
|
||||
}
|
||||
|
||||
fn void Sha256.init(&self)
|
||||
<*
|
||||
Compute and return a hash value.
|
||||
|
||||
@param [in] data : "The input data to hash."
|
||||
*>
|
||||
fn char[HASH_SIZE] hash(char[] data)
|
||||
{
|
||||
// Sha256 initialization constants
|
||||
*self = {
|
||||
.state = {
|
||||
0x6A09E667,
|
||||
0xBB67AE85,
|
||||
0x3C6EF372,
|
||||
0xA54FF53A,
|
||||
0x510E527F,
|
||||
0x9B05688C,
|
||||
0x1F83D9AB,
|
||||
0x5BE0CD19
|
||||
}
|
||||
};
|
||||
Sha256 sha256 @noinit;
|
||||
sha256.init();
|
||||
sha256.update(data);
|
||||
return sha256.final();
|
||||
}
|
||||
|
||||
fn void Sha256.init(&self) => *self = {
|
||||
.state = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
},
|
||||
};
|
||||
|
||||
<*
|
||||
@param [in] data
|
||||
@require data.len <= uint.max
|
||||
*>
|
||||
fn void Sha256.update(&self, char[] data) {
|
||||
uint i = 0;
|
||||
uint len = data.len;
|
||||
uint buffer_pos = (uint)(self.bitcount / 8) % BLOCK_SIZE;
|
||||
self.bitcount += ((ulong)len * 8);
|
||||
fn void Sha256.update(&self, char[] data)
|
||||
{
|
||||
uint buffer_pos = (uint)(self.bitcount >> 3) % BLOCK_SIZE;
|
||||
self.bitcount += (ulong)data.len << 3; // always record ingested bits count immediately
|
||||
|
||||
while (len--) {
|
||||
self.buffer[buffer_pos++] = data[i++];
|
||||
if (buffer_pos == BLOCK_SIZE) {
|
||||
sha256_transform(&self.state, &self.buffer);
|
||||
buffer_pos = 0; // Reset buffer position
|
||||
}
|
||||
}
|
||||
// Get the buffer position back to 0 if we're midway through consuming some data.
|
||||
if (buffer_pos > 0 && buffer_pos < BLOCK_SIZE)
|
||||
{
|
||||
usz len = min(BLOCK_SIZE - buffer_pos, data.len);
|
||||
self.buffer[buffer_pos:len] = data[:len];
|
||||
data = data[len..];
|
||||
if (buffer_pos + len == BLOCK_SIZE) self.transform();
|
||||
}
|
||||
|
||||
// When the data pointer is aligned, we can disregard unaligned loading in the `transform` macro.
|
||||
// We do this here from the outer call to reduce the expense of checking alignment on every single block.
|
||||
if (0 == (usz)data.ptr % usz.sizeof)
|
||||
{
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) self.transform((uint*)data.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; data.len >= BLOCK_SIZE; data = data[BLOCK_SIZE..]) self.transform_unaligned((uint*)data.ptr);
|
||||
}
|
||||
|
||||
// Leftover data just gets stored away for the next update or final.
|
||||
if (data.len)
|
||||
{
|
||||
self.buffer[..] = 0;
|
||||
self.buffer[:data.len] = data[..];
|
||||
}
|
||||
}
|
||||
|
||||
fn char[HASH_SIZE] Sha256.final(&self) {
|
||||
char[HASH_SIZE] hash;
|
||||
ulong i = (self.bitcount / 8) % BLOCK_SIZE;
|
||||
fn char[HASH_SIZE] Sha256.final(&self)
|
||||
{
|
||||
char[HASH_SIZE] hash @align(uint.sizeof);
|
||||
ulong i = (self.bitcount / 8) % BLOCK_SIZE;
|
||||
|
||||
// Append 0x80 to the buffer
|
||||
self.buffer[i++] = 0x80;
|
||||
// Append 0x80 to the buffer
|
||||
self.buffer[i++] = 0x80;
|
||||
|
||||
// Pad the buffer with zeros
|
||||
if (i > BLOCK_SIZE - 8) {
|
||||
while (i < BLOCK_SIZE) {
|
||||
self.buffer[i++] = 0x00;
|
||||
}
|
||||
sha256_transform(&self.state, &self.buffer);
|
||||
i = 0; // Reset buffer index after transformation
|
||||
}
|
||||
|
||||
while (i < BLOCK_SIZE - 8) {
|
||||
self.buffer[i++] = 0x00;
|
||||
}
|
||||
// Pad the buffer with zeros
|
||||
if (i > BLOCK_SIZE - 8)
|
||||
{
|
||||
self.buffer[i..] = 0x00;
|
||||
self.transform();
|
||||
i = 0; // Reset buffer index after transformation
|
||||
}
|
||||
|
||||
// Append the bitcount in big-endian format
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
self.buffer[BLOCK_SIZE - 8 + j] = (char)((self.bitcount >> (56 - j * 8)) & 0xFF);
|
||||
}
|
||||
self.buffer[i..(BLOCK_SIZE - 8)] = 0x00;
|
||||
|
||||
sha256_transform(&self.state, &self.buffer);
|
||||
// Append the bitcount in big-endian format
|
||||
*(ulong*)(&self.buffer[BLOCK_SIZE - 8]) = env::BIG_ENDIAN ??? self.bitcount : bswap(self.bitcount);
|
||||
|
||||
// Convert state to the final hash
|
||||
for (i = 0; i < 8; ++i) {
|
||||
hash[i * 4] = (char)((self.state[i] >> 24) & 0xFF);
|
||||
hash[i * 4 + 1] = (char)((self.state[i] >> 16) & 0xFF);
|
||||
hash[i * 4 + 2] = (char)((self.state[i] >> 8) & 0xFF);
|
||||
hash[i * 4 + 3] = (char)(self.state[i] & 0xFF);
|
||||
}
|
||||
|
||||
return hash;
|
||||
self.transform();
|
||||
|
||||
// Convert state to the final hash
|
||||
foreach (x, s : self.state) *(uint*)(&hash[x * uint.sizeof]) = env::BIG_ENDIAN ??? s : bswap(s);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
<*
|
||||
@param [&inout] state
|
||||
@param [&in] buffer
|
||||
*>
|
||||
fn void sha256_transform(uint* state, char* buffer) @local {
|
||||
uint a, b, c, d, e, f, g, h, t1, t2;
|
||||
uint[64] m;
|
||||
int i;
|
||||
// These wrappers are necessary to significantly reduce code generation from macro expansions.
|
||||
// Note that transformations on `self.buffer` (when incoming == null) should always be aligned.
|
||||
fn void Sha256.transform(&self, uint* incoming = null) @local @noinline => self.do_transform(incoming, true);
|
||||
fn void Sha256.transform_unaligned(&self, uint* incoming = null) @local @noinline => self.do_transform(incoming, false);
|
||||
|
||||
// Prepare the message schedule
|
||||
for (i = 0; i < 16; ++i) {
|
||||
m[i] = ((uint)buffer[i * 4] << 24) | ((uint)buffer[i * 4 + 1] << 16) |
|
||||
((uint)buffer[i * 4 + 2] << 8) | ((uint)buffer[i * 4 + 3]); // Ensure values are cast to uint for correct shifts
|
||||
}
|
||||
for (i = 16; i < 64; ++i) {
|
||||
m[i] = @sigma1(m[i - 2]) + m[i - 7] + @sigma0(m[i - 15]) + m[i - 16];
|
||||
}
|
||||
macro Sha256.do_transform(&self, uint* incoming = null, bool $aligned = true) @local
|
||||
{
|
||||
uint a, b, c, d, e, f, g, h, t1, t2 @noinit;
|
||||
uint[64] m @noinit;
|
||||
int i @noinit;
|
||||
|
||||
// Initialize working variables
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
f = state[5];
|
||||
g = state[6];
|
||||
h = state[7];
|
||||
if (!incoming) incoming = (uint*)&self.buffer;
|
||||
|
||||
// Perform the main SHA-256 compression function
|
||||
for (i = 0; i < 64; ++i) {
|
||||
t1 = h + @_sigma1(e) + @ch(e, f, g) + K[i] + m[i];
|
||||
t2 = @_sigma0(a) + @maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
$if env::BIG_ENDIAN:
|
||||
@as_char_view(m)[:BLOCK_SIZE] = @as_char_view(incoming)[:BLOCK_SIZE];
|
||||
$else
|
||||
// Unrolling this seems to make the hash slower.
|
||||
for (i = 0; i < 16; ++i) m[i] = bswap($aligned ??? incoming[i] : @unaligned_load(incoming[i], 1));
|
||||
$endif
|
||||
|
||||
// Update the state
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
state[5] += f;
|
||||
state[6] += g;
|
||||
state[7] += h;
|
||||
a = b = c = d = e = f = g = h = t1 = t2 = i = 0;
|
||||
m[:64] = buffer[:64] = 0;
|
||||
for (i = 16; i < 64; i++) m[i] = @sigma1(m[i - 2]) + m[i - 7] + @sigma0(m[i - 15]) + m[i - 16];
|
||||
|
||||
a = self.state[0];
|
||||
b = self.state[1];
|
||||
c = self.state[2];
|
||||
d = self.state[3];
|
||||
e = self.state[4];
|
||||
f = self.state[5];
|
||||
g = self.state[6];
|
||||
h = self.state[7];
|
||||
|
||||
$for usz $i = 0; $i < 64; $i++:
|
||||
t1 = h + @_sigma1(e) + @ch(e, f, g) + K[$i] + m[$i];
|
||||
t2 = @_sigma0(a) + @maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
$endfor
|
||||
|
||||
self.state[0] += a;
|
||||
self.state[1] += b;
|
||||
self.state[2] += c;
|
||||
self.state[3] += d;
|
||||
self.state[4] += e;
|
||||
self.state[5] += f;
|
||||
self.state[6] += g;
|
||||
self.state[7] += h;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ alias hash = siphash::hash { uint128, 4, 8 };
|
||||
|
||||
@require OutType.typeid == uint128.typeid || OutType.typeid == ulong.typeid : "Module OutType must be either uint128 or ulong."
|
||||
*>
|
||||
module std::hash::siphash { OutType, BLOCK_ROUNDS, FINALIZE_ROUNDS };
|
||||
module std::hash::siphash <OutType, BLOCK_ROUNDS, FINALIZE_ROUNDS>;
|
||||
|
||||
|
||||
struct SipHash
|
||||
|
||||
@@ -161,7 +161,7 @@ fn void Whirlpool.process_block(&self, char* block) @local
|
||||
// NOTE: These loops are unrolled with C3's Chad-tier compile-time evaluation.
|
||||
$for var $round = 0; $round < 8; $round++:
|
||||
k[$round] = self.hash[$round];
|
||||
state[$round] = $$bswap(@unaligned_load(((ulong*)block)[$round], 1)) ^ self.hash[$round];
|
||||
state[$round] = $$bswap(mem::load((ulong*)block + $round, 1)) ^ self.hash[$round];
|
||||
self.hash[$round] = state[$round];
|
||||
$endfor
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ fn ulong hash(char[] input, ulong seed = 0)
|
||||
{
|
||||
if (@likely(input.len >= 4))
|
||||
{
|
||||
a = (ulong)@unaligned_load(*(uint*)input.ptr, 1); // first 4 bytes widened to a u64
|
||||
b = (ulong)@unaligned_load(*(uint*)&input[^4], 1); // a walking 4-byte window based on input.len
|
||||
a = (ulong)mem::load((uint*)input.ptr, 1); // first 4 bytes widened to a u64
|
||||
b = (ulong)mem::load((uint*)&input[^4], 1); // a walking 4-byte window based on input.len
|
||||
}
|
||||
else if (input.len > 0)
|
||||
{
|
||||
@@ -44,8 +44,8 @@ fn ulong hash(char[] input, ulong seed = 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
a = @unaligned_load(*(ulong*)input.ptr, 1); // first 8 bytes
|
||||
b = @unaligned_load(*(ulong*)&input[^8], 1); // a walking 8-byte window based on input.len
|
||||
a = mem::load((ulong*)input.ptr, 1); // first 8 bytes
|
||||
b = mem::load((ulong*)&input[^8], 1); // a walking 8-byte window based on input.len
|
||||
}
|
||||
|
||||
uint128 r = ((uint128)a ^ 0xe703_7ed1_a0b4_28db) * ((uint128)b ^ seed);
|
||||
|
||||
@@ -102,8 +102,8 @@ fn void? File.close(&self) @inline @dynamic
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::ECONNRESET:
|
||||
case errno::EBADF: return io::FILE_NOT_VALID?;
|
||||
case errno::EINTR: return io::INTERRUPTED?;
|
||||
case errno::EBADF: return io::FILE_NOT_VALID~;
|
||||
case errno::EINTR: return io::INTERRUPTED~;
|
||||
case errno::EDQUOT:
|
||||
case errno::EFAULT:
|
||||
case errno::EAGAIN:
|
||||
@@ -111,8 +111,8 @@ fn void? File.close(&self) @inline @dynamic
|
||||
case errno::ENETDOWN:
|
||||
case errno::ENETUNREACH:
|
||||
case errno::ENOSPC:
|
||||
case errno::EIO: return io::INCOMPLETE_WRITE?;
|
||||
default: return io::UNKNOWN_ERROR?;
|
||||
case errno::EIO: return io::INCOMPLETE_WRITE~;
|
||||
default: return io::UNKNOWN_ERROR~;
|
||||
}
|
||||
}
|
||||
self.file = null;
|
||||
@@ -156,7 +156,7 @@ fn bool File.isatty(self) @if(env::LIBC)
|
||||
fn char? File.read_byte(&self) @dynamic
|
||||
{
|
||||
int c = libc::fgetc(self.file);
|
||||
if (c == -1) return io::EOF?;
|
||||
if (c == -1) return io::EOF~;
|
||||
return (char)c;
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ fn char[]? load_buffer(String filename, char[] buffer)
|
||||
File file = open(filename, "rb")!;
|
||||
defer (void)file.close();
|
||||
usz len = file.seek(0, END)!;
|
||||
if (len > buffer.len) return io::OVERFLOW?;
|
||||
if (len > buffer.len) return io::OVERFLOW~;
|
||||
file.seek(0, SET)!;
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
|
||||
@@ -26,8 +26,8 @@ fn void? FileMmap.destroy(&self) @maydiscard
|
||||
{
|
||||
fault err1 = @catch(self.file.close());
|
||||
fault err2 = @catch(self.vm.destroy());
|
||||
if (err1) return err1?;
|
||||
if (err2) return err2?;
|
||||
if (err1) return err1~;
|
||||
if (err2) return err2~;
|
||||
}
|
||||
|
||||
module std::io::file @if(env::LIBC &&& env::POSIX);
|
||||
|
||||
@@ -2,6 +2,9 @@ module std::io;
|
||||
import std::collections::map;
|
||||
import libc;
|
||||
|
||||
// It is vitally important that the formatter doesn't do any allocations,
|
||||
// or it ceases to be useful in constrained environments.
|
||||
|
||||
const int PRINTF_NTOA_BUFFER_SIZE = 256;
|
||||
|
||||
interface Printable
|
||||
@@ -93,9 +96,9 @@ fn usz? Formatter.out(&self, char c) @private
|
||||
{
|
||||
if (catch err = self.out_fn(self.data, c))
|
||||
{
|
||||
if (self.first_fault) return self.first_fault?;
|
||||
if (self.first_fault) return self.first_fault~;
|
||||
self.first_fault = err;
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -130,7 +133,7 @@ fn usz? Formatter.print_with_function(&self, Printable arg)
|
||||
if (!arg) return self.out_substr("(null)");
|
||||
return self.out_substr(arg.to_constant_string());
|
||||
}
|
||||
return NOT_FOUND?;
|
||||
return NOT_FOUND~;
|
||||
}
|
||||
|
||||
fn usz? Formatter.out_unknown(&self, String category, any arg) @private
|
||||
@@ -337,7 +340,7 @@ fn void? out_null_fn(void* data @unused, char c @unused) @private
|
||||
macro usz? @report_fault(Formatter* f, $fault)
|
||||
{
|
||||
(void)f.out_substr($fault);
|
||||
return INVALID_FORMAT?;
|
||||
return INVALID_FORMAT~;
|
||||
}
|
||||
|
||||
macro usz? @wrap_bad(Formatter* f, #action)
|
||||
@@ -349,11 +352,11 @@ macro usz? @wrap_bad(Formatter* f, #action)
|
||||
{
|
||||
case BUFFER_EXCEEDED:
|
||||
case INTERNAL_BUFFER_EXCEEDED:
|
||||
return f.first_err(err)?;
|
||||
return f.first_err(err)~;
|
||||
default:
|
||||
err = f.first_err(INVALID_ARGUMENT);
|
||||
f.out_substr("<INVALID>")!;
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
@@ -561,7 +564,7 @@ fn usz? Formatter.vprintf(&self, String format, any[] anys)
|
||||
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
|
||||
// return written chars without terminating \0
|
||||
if (self.first_fault) return self.first_fault?;
|
||||
if (self.first_fault) return self.first_fault~;
|
||||
return total_len;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ fn uint128? int_from_any(any arg, bool *is_neg) @private
|
||||
double d = *(double*)arg;
|
||||
return (uint128)((*is_neg = d < 0) ? -d : d);
|
||||
default:
|
||||
return BAD_FORMAT?;
|
||||
return BAD_FORMAT~;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ fn FloatType? float_from_any(any arg) @private
|
||||
case double:
|
||||
return (FloatType)*(double*)arg;
|
||||
default:
|
||||
return BAD_FORMAT?;
|
||||
return BAD_FORMAT~;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
} while (y);
|
||||
isz outlen = s - buf;
|
||||
isz explen = ebuf - estr;
|
||||
if (p > int.max - 2 - explen - pl) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (p > int.max - 2 - explen - pl) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
usz len;
|
||||
usz l = p && outlen - 2 < p
|
||||
? p + 2 + explen
|
||||
@@ -364,7 +364,10 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
}
|
||||
|
||||
// Perform rounding: j is precision after the radix (possibly neg)
|
||||
int j = (int)(p - (isz)(formatting == FLOAT ? 0 : e - (int)(formatting == ADAPTIVE && p)));
|
||||
int j = (int)p;
|
||||
if (formatting != FLOAT) j -= e;
|
||||
if (formatting == ADAPTIVE && p != 0) j -= 1;
|
||||
|
||||
if (j < 9 * (z - r - 1))
|
||||
{
|
||||
uint x;
|
||||
@@ -451,12 +454,12 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p > int.max - 1 - (isz)(p || self.flags.hash)) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (p > int.max - 1 - (isz)(p || self.flags.hash)) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
int l = (int)(1 + p + (isz)(p || self.flags.hash));
|
||||
char* estr @noinit;
|
||||
if (formatting == FLOAT)
|
||||
{
|
||||
if (e > int.max - l) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (e > int.max - l) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
if (e > 0) l += e;
|
||||
}
|
||||
else
|
||||
@@ -465,10 +468,10 @@ fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
|
||||
while (ebuf - estr < 2) (--estr)[0] = '0';
|
||||
*--estr = (e < 0 ? '-' : '+');
|
||||
*--estr = self.flags.uppercase ? 'E' : 'e';
|
||||
if (ebuf - estr > (isz)int.max - l) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (ebuf - estr > (isz)int.max - l) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
l += (int)(ebuf - estr);
|
||||
}
|
||||
if (l > int.max - pl) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (l > int.max - pl) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
usz len;
|
||||
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!;
|
||||
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!;
|
||||
@@ -556,7 +559,7 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
|
||||
case 2:
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0' + (char)value & 1;
|
||||
value >>= 1;
|
||||
}
|
||||
@@ -564,13 +567,13 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
|
||||
case 10:
|
||||
if (!value)
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0';
|
||||
break;
|
||||
}
|
||||
while (value >= 10)
|
||||
{
|
||||
if (len + 1 >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len + 1 >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
char digit = (char)(value % 100);
|
||||
buf[len:2] = DIGIT_PAIRS[2 * digit:2];
|
||||
len += 2;
|
||||
@@ -578,13 +581,13 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
|
||||
}
|
||||
if (value > 0)
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0' + (char)value;
|
||||
}
|
||||
case 16:
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
char digit = (char)value & 0xF;
|
||||
buf[len++] = digit + (digit < 10 ? '0' : past_10);
|
||||
value >>= 4;
|
||||
@@ -593,7 +596,7 @@ fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
|
||||
case 8:
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0' + (char)value & 0x7;
|
||||
value >>= 3;
|
||||
}
|
||||
@@ -613,12 +616,12 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
if (self.width && self.flags.zeropad && (negative || self.flags.plus || self.flags.space)) self.width--;
|
||||
while (len < self.prec)
|
||||
{
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while (self.flags.zeropad && len < self.width)
|
||||
{
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
@@ -633,7 +636,7 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
if (len + 1 >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len + 1 >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
switch (base)
|
||||
{
|
||||
case 16:
|
||||
@@ -652,13 +655,13 @@ fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
|
||||
switch (true)
|
||||
{
|
||||
case negative:
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '-';
|
||||
case self.flags.plus:
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = '+';
|
||||
case self.flags.space:
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED~;
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
if (len) self.out_reverse(buf[:len])!;
|
||||
@@ -738,10 +741,10 @@ fn int? printf_parse_format_field(
|
||||
if (c.is_digit()) return simple_atoi(format_ptr, format_len, index_ptr);
|
||||
if (c != '*') return 0;
|
||||
usz len = ++(*index_ptr);
|
||||
if (len >= format_len) return BAD_FORMAT?;
|
||||
if (*args_index_ptr >= args_len) return BAD_FORMAT?;
|
||||
if (len >= format_len) return BAD_FORMAT~;
|
||||
if (*args_index_ptr >= args_len) return BAD_FORMAT~;
|
||||
any val = args_ptr[(*args_index_ptr)++];
|
||||
if (!val.type.kindof.is_int()) return BAD_FORMAT?;
|
||||
if (!val.type.kindof.is_int()) return BAD_FORMAT~;
|
||||
uint? intval = types::any_to_int(val, int);
|
||||
return intval ?? BAD_FORMAT?;
|
||||
return intval ?? BAD_FORMAT~;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,11 @@ faultdef
|
||||
@return `The string containing the data read.`
|
||||
*>
|
||||
macro String? readline(Allocator allocator, stream = io::stdin())
|
||||
{
|
||||
return readline_impl{$typeof(stream)}(allocator, stream);
|
||||
}
|
||||
|
||||
fn String? readline_impl(Allocator allocator, Stream stream) <Stream> @private
|
||||
{
|
||||
if (allocator == tmem)
|
||||
{
|
||||
@@ -99,16 +104,21 @@ macro String? treadline(stream = io::stdin())
|
||||
*>
|
||||
macro usz? readline_to_stream(out_stream, in_stream = io::stdin())
|
||||
{
|
||||
bool $is_stream = $typeof(in_stream) == InStream;
|
||||
return readline_to_stream_impl{$typeof(in_stream), $typeof(out_stream)}(out_stream, in_stream);
|
||||
}
|
||||
|
||||
fn usz? readline_to_stream_impl(OStream out_stream, IStream in_stream) <IStream, OStream> @private
|
||||
{
|
||||
bool $is_stream = IStream == InStream;
|
||||
$if $is_stream:
|
||||
var func = &in_stream.read_byte;
|
||||
var func @safeinfer = &in_stream.read_byte;
|
||||
char val = func((void*)in_stream)!;
|
||||
$else
|
||||
char val = in_stream.read_byte()!;
|
||||
$endif
|
||||
bool $is_out_stream = $typeof(out_stream) == OutStream;
|
||||
bool $is_out_stream = OStream == OutStream;
|
||||
$if $is_out_stream:
|
||||
var out_func = &out_stream.write_byte;
|
||||
var out_func @safeinfer = &out_stream.write_byte;
|
||||
$endif
|
||||
|
||||
if (val == '\n') return 0;
|
||||
@@ -132,7 +142,7 @@ macro usz? readline_to_stream(out_stream, in_stream = io::stdin())
|
||||
if (catch err = c)
|
||||
{
|
||||
if (err == io::EOF) break;
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
if (c == '\r') continue;
|
||||
if (c == '\n') break;
|
||||
@@ -404,7 +414,7 @@ fn char[]? bprintf(char[] buffer, String format, args...) @maydiscard
|
||||
fn void? out_buffer_fn(void *data, char c) @private
|
||||
{
|
||||
BufferData *buffer_data = data;
|
||||
if (buffer_data.written >= buffer_data.buffer.len) return BUFFER_EXCEEDED?;
|
||||
if (buffer_data.written >= buffer_data.buffer.len) return BUFFER_EXCEEDED~;
|
||||
buffer_data.buffer[buffer_data.written++] = c;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,20 +11,20 @@ macro void? native_chdir(Path path)
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EACCES: return io::NO_PERMISSION?;
|
||||
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?;
|
||||
case errno::ENOTDIR: return io::FILE_NOT_DIR?;
|
||||
case errno::ENOENT: return io::FILE_NOT_FOUND?;
|
||||
case errno::ELOOP: return io::SYMLINK_FAILED?;
|
||||
default: return io::GENERAL_ERROR?;
|
||||
case errno::EACCES: return io::NO_PERMISSION~;
|
||||
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG~;
|
||||
case errno::ENOTDIR: return io::FILE_NOT_DIR~;
|
||||
case errno::ENOENT: return io::FILE_NOT_FOUND~;
|
||||
case errno::ELOOP: return io::SYMLINK_FAILED~;
|
||||
default: return io::GENERAL_ERROR~;
|
||||
}
|
||||
}
|
||||
$case env::WIN32:
|
||||
// TODO improve with better error handling.
|
||||
if (win32::setCurrentDirectoryW(path.str_view().to_temp_utf16()!!)) return;
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
$default:
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
$endswitch
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ fn void*? native_fopen(String filename, String mode) @inline => @pool()
|
||||
$else
|
||||
void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy());
|
||||
$endif
|
||||
return file ?: file_open_errno()?;
|
||||
return file ?: file_open_errno()~;
|
||||
}
|
||||
|
||||
fn void? native_remove(String filename) => @pool()
|
||||
@@ -27,10 +27,10 @@ fn void? native_remove(String filename) => @pool()
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::ENOENT:
|
||||
return io::FILE_NOT_FOUND?;
|
||||
return io::FILE_NOT_FOUND~;
|
||||
case errno::EACCES:
|
||||
default:
|
||||
return io::FILE_CANNOT_DELETE?;
|
||||
return io::FILE_CANNOT_DELETE~;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,19 +46,19 @@ fn void*? native_freopen(void* file, String filename, String mode) @inline => @p
|
||||
$else
|
||||
file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file);
|
||||
$endif
|
||||
return file ?: file_open_errno()?;
|
||||
return file ?: file_open_errno()~;
|
||||
}
|
||||
|
||||
fn void? native_fseek(void* file, isz offset, Seek seek_mode) @inline
|
||||
{
|
||||
if (libc::fseek(file, (SeekIndex)offset, seek_mode.ordinal)) return file_seek_errno()?;
|
||||
if (libc::fseek(file, (SeekIndex)offset, seek_mode.ordinal)) return file_seek_errno()~;
|
||||
}
|
||||
|
||||
|
||||
fn usz? native_ftell(CFile file) @inline
|
||||
{
|
||||
long index = libc::ftell(file);
|
||||
return index >= 0 ? (usz)index : file_seek_errno()?;
|
||||
return index >= 0 ? (usz)index : file_seek_errno()~;
|
||||
}
|
||||
|
||||
fn usz? native_fwrite(CFile file, char[] buffer) @inline
|
||||
@@ -68,7 +68,7 @@ fn usz? native_fwrite(CFile file, char[] buffer) @inline
|
||||
|
||||
fn void? native_fputc(CInt c, CFile stream) @inline
|
||||
{
|
||||
if (libc::fputc(c, stream) == libc::EOF) return io::EOF?;
|
||||
if (libc::fputc(c, stream) == libc::EOF) return io::EOF~;
|
||||
}
|
||||
|
||||
fn usz? native_fread(CFile file, char[] buffer) @inline
|
||||
|
||||
@@ -28,7 +28,7 @@ FputcFn native_fputc_fn @weak @if(!$defined(native_fputc_fn));
|
||||
fn void*? native_fopen(String filename, String mode) @inline
|
||||
{
|
||||
if (native_fopen_fn) return native_fopen_fn(filename, mode);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -39,7 +39,7 @@ fn void*? native_fopen(String filename, String mode) @inline
|
||||
fn void? native_remove(String filename) @inline
|
||||
{
|
||||
if (native_remove_fn) return native_remove_fn(filename);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -49,35 +49,35 @@ fn void? native_remove(String filename) @inline
|
||||
fn void*? native_freopen(void* file, String filename, String mode) @inline
|
||||
{
|
||||
if (native_freopen_fn) return native_freopen_fn(file, filename, mode);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn void? native_fseek(void* file, isz offset, Seek seek_mode) @inline
|
||||
{
|
||||
if (native_fseek_fn) return native_fseek_fn(file, offset, seek_mode);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn usz? native_ftell(CFile file) @inline
|
||||
{
|
||||
if (native_ftell_fn) return native_ftell_fn(file);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn usz? native_fwrite(CFile file, char[] buffer) @inline
|
||||
{
|
||||
if (native_fwrite_fn) return native_fwrite_fn(file, buffer);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn usz? native_fread(CFile file, char[] buffer) @inline
|
||||
{
|
||||
if (native_fread_fn) return native_fread_fn(file, buffer);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
fn void? native_fputc(CInt c, CFile stream) @inline
|
||||
{
|
||||
if (native_fputc_fn) return native_fputc_fn(c, stream);
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
@@ -14,25 +14,25 @@ fn void? native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || e
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EBADF:
|
||||
return io::FILE_NOT_VALID?;
|
||||
return io::FILE_NOT_VALID~;
|
||||
case errno::EFAULT:
|
||||
unreachable("Invalid stat");
|
||||
case errno::EIO:
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
case errno::EACCES:
|
||||
return io::NO_PERMISSION?;
|
||||
return io::NO_PERMISSION~;
|
||||
case errno::ELOOP:
|
||||
return io::NO_PERMISSION?;
|
||||
return io::NO_PERMISSION~;
|
||||
case errno::ENAMETOOLONG:
|
||||
return io::NAME_TOO_LONG?;
|
||||
return io::NAME_TOO_LONG~;
|
||||
case errno::ENOENT:
|
||||
return io::FILE_NOT_FOUND?;
|
||||
return io::FILE_NOT_FOUND~;
|
||||
case errno::ENOTDIR:
|
||||
return io::FILE_NOT_DIR?;
|
||||
return io::FILE_NOT_DIR~;
|
||||
case errno::EOVERFLOW:
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
default:
|
||||
return io::UNKNOWN_ERROR?;
|
||||
return io::UNKNOWN_ERROR~;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,14 +47,14 @@ fn usz? native_file_size(String path) @if(env::WIN32) => @pool()
|
||||
return (usz)size.quadPart;
|
||||
}
|
||||
|
||||
fn usz? native_file_size(String path) @if(!env::WIN32 && !env::DARWIN)
|
||||
fn usz? native_file_size(String path) @if(!env::WIN32 && !env::DARWIN && !env::LINUX && !env::ANDROID && !env::BSD_FAMILY)
|
||||
{
|
||||
File f = file::open(path, "r")!;
|
||||
defer (void)f.close();
|
||||
return f.seek(0, Seek.END)!;
|
||||
}
|
||||
|
||||
fn usz? native_file_size(String path) @if(env::DARWIN)
|
||||
fn usz? native_file_size(String path) @if(env::DARWIN || env::LINUX || env::ANDROID || env::BSD_FAMILY)
|
||||
{
|
||||
Stat stat;
|
||||
native_stat(&stat, path)!;
|
||||
|
||||
@@ -12,7 +12,7 @@ macro String? getcwd(Allocator allocator)
|
||||
defer if (free) libc::free(res);
|
||||
if (!res)
|
||||
{
|
||||
if (libc::errno() != errno::ERANGE) return io::GENERAL_ERROR?;
|
||||
if (libc::errno() != errno::ERANGE) return io::GENERAL_ERROR~;
|
||||
res = win32::_wgetcwd(null, 0);
|
||||
free = true;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ macro String? getcwd(Allocator allocator)
|
||||
if (!res)
|
||||
{
|
||||
// Improve error
|
||||
if (libc::errno() != errno::ERANGE) return io::GENERAL_ERROR?;
|
||||
if (libc::errno() != errno::ERANGE) return io::GENERAL_ERROR~;
|
||||
res = posix::getcwd(null, 0);
|
||||
free = true;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ macro String? getcwd(Allocator allocator)
|
||||
return res.copy(allocator);
|
||||
|
||||
$default:
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ fn PathList? native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
directory = posix::opendir(dir.str_view() ? dir.str_view().zstr_tcopy() : (ZString)".");
|
||||
};
|
||||
defer if (directory) posix::closedir(directory);
|
||||
if (!directory) return (path::is_dir(dir) ? io::CANNOT_READ_DIR : io::FILE_NOT_DIR)?;
|
||||
if (!directory) return (path::is_dir(dir) ? io::CANNOT_READ_DIR : io::FILE_NOT_DIR)~;
|
||||
Posix_dirent* entry;
|
||||
while ((entry = posix::readdir(directory)))
|
||||
{
|
||||
@@ -38,7 +38,7 @@ fn PathList? native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
WString result = dir.str_view().tconcat(`\*`).to_temp_wstring()!!;
|
||||
Win32_WIN32_FIND_DATAW find_data;
|
||||
Win32_HANDLE find = win32::findFirstFileW(result, &find_data);
|
||||
if (find == win32::INVALID_HANDLE_VALUE) return io::CANNOT_READ_DIR?;
|
||||
if (find == win32::INVALID_HANDLE_VALUE) return io::CANNOT_READ_DIR~;
|
||||
defer win32::findClose(find);
|
||||
do
|
||||
{
|
||||
|
||||
@@ -17,17 +17,17 @@ macro bool? native_mkdir(Path path, MkdirPermissions permissions)
|
||||
case errno::EACCES:
|
||||
case errno::EPERM:
|
||||
case errno::EROFS:
|
||||
case errno::EFAULT: return io::NO_PERMISSION?;
|
||||
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?;
|
||||
case errno::EFAULT: return io::NO_PERMISSION~;
|
||||
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG~;
|
||||
case errno::EDQUOT:
|
||||
case errno::ENOSPC: return io::OUT_OF_SPACE?;
|
||||
case errno::ENOSPC: return io::OUT_OF_SPACE~;
|
||||
case errno::EISDIR:
|
||||
case errno::EEXIST: return false;
|
||||
case errno::ELOOP: return io::SYMLINK_FAILED?;
|
||||
case errno::ENOTDIR: return io::FILE_NOT_FOUND?;
|
||||
case errno::ENOENT: return io::PARENT_DIR_MISSING?;
|
||||
case errno::ELOOP: return io::SYMLINK_FAILED~;
|
||||
case errno::ENOTDIR: return io::FILE_NOT_FOUND~;
|
||||
case errno::ENOENT: return io::PARENT_DIR_MISSING~;
|
||||
default:
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
}
|
||||
$case env::WIN32:
|
||||
// TODO security attributes
|
||||
@@ -35,18 +35,18 @@ macro bool? native_mkdir(Path path, MkdirPermissions permissions)
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_ACCESS_DENIED:
|
||||
return io::NO_PERMISSION?;
|
||||
return io::NO_PERMISSION~;
|
||||
case win32::ERROR_DISK_FULL:
|
||||
return io::OUT_OF_SPACE?;
|
||||
return io::OUT_OF_SPACE~;
|
||||
case win32::ERROR_ALREADY_EXISTS:
|
||||
return false;
|
||||
case win32::ERROR_PATH_NOT_FOUND:
|
||||
return io::FILE_NOT_FOUND?;
|
||||
return io::FILE_NOT_FOUND~;
|
||||
default:
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
}
|
||||
$default:
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
$endswitch
|
||||
};
|
||||
}
|
||||
@@ -13,36 +13,36 @@ macro bool? native_rmdir(Path path)
|
||||
if (!posix::rmdir(path.str_view().zstr_tcopy())) return true;
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EBUSY: return io::BUSY?;
|
||||
case errno::EBUSY: return io::BUSY~;
|
||||
case errno::EACCES:
|
||||
case errno::EPERM:
|
||||
case errno::EROFS:
|
||||
case errno::EFAULT: return io::NO_PERMISSION?;
|
||||
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?;
|
||||
case errno::EFAULT: return io::NO_PERMISSION~;
|
||||
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG~;
|
||||
case errno::ENOTDIR:
|
||||
case errno::ENOENT: return false;
|
||||
case errno::ENOTEMPTY: return io::DIR_NOT_EMPTY?;
|
||||
case errno::ELOOP: return io::SYMLINK_FAILED?;
|
||||
default: return io::GENERAL_ERROR?;
|
||||
case errno::ENOTEMPTY: return io::DIR_NOT_EMPTY~;
|
||||
case errno::ELOOP: return io::SYMLINK_FAILED~;
|
||||
default: return io::GENERAL_ERROR~;
|
||||
}
|
||||
$case env::WIN32:
|
||||
if (win32::removeDirectoryW(path.str_view().to_temp_utf16()!!)) return true;
|
||||
switch (win32::getLastError())
|
||||
{
|
||||
case win32::ERROR_ACCESS_DENIED:
|
||||
return io::NO_PERMISSION?;
|
||||
return io::NO_PERMISSION~;
|
||||
case win32::ERROR_CURRENT_DIRECTORY:
|
||||
return io::BUSY?;
|
||||
return io::BUSY~;
|
||||
case win32::ERROR_DIR_NOT_EMPTY:
|
||||
return io::DIR_NOT_EMPTY?;
|
||||
return io::DIR_NOT_EMPTY~;
|
||||
case win32::ERROR_DIRECTORY:
|
||||
case win32::ERROR_PATH_NOT_FOUND:
|
||||
return false;
|
||||
default:
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
}
|
||||
$default:
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
$endswitch
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ fn void? native_rmtree(Path dir)
|
||||
{
|
||||
DIRPtr directory = posix::opendir(dir.str_view().zstr_tcopy());
|
||||
defer if (directory) posix::closedir(directory);
|
||||
if (!directory) return path::is_dir(dir) ? io::CANNOT_READ_DIR? : io::FILE_NOT_DIR?;
|
||||
if (!directory) return path::is_dir(dir) ? io::CANNOT_READ_DIR~ : io::FILE_NOT_DIR~;
|
||||
Posix_dirent* entry;
|
||||
while ((entry = posix::readdir(directory)))
|
||||
{
|
||||
@@ -27,7 +27,7 @@ fn void? native_rmtree(Path dir)
|
||||
if (libc::remove(new_path.str_view().zstr_tcopy()))
|
||||
{
|
||||
// TODO improve
|
||||
return io::GENERAL_ERROR?;
|
||||
return io::GENERAL_ERROR~;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -44,7 +44,7 @@ fn void? native_rmtree(Path path)
|
||||
String s = path.str_view().tconcat("\\*");
|
||||
Win32_HANDLE find = win32::findFirstFileW(s.to_temp_utf16(), &find_data)!;
|
||||
|
||||
if (find == win32::INVALID_HANDLE_VALUE) return io::CANNOT_READ_DIR?;
|
||||
if (find == win32::INVALID_HANDLE_VALUE) return io::CANNOT_READ_DIR~;
|
||||
defer win32::findClose(find);
|
||||
do
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ fn String? win32_get_known_folder_temp(Win32_REFKNOWNFOLDERID rfid) @private @if
|
||||
{
|
||||
Win32_PWSTR path;
|
||||
Win32_HRESULT res = win32::shGetKnownFolderPath(rfid, 0x00008000 /* KF_FLAG_CREATE */, null, &path);
|
||||
if (res) return io::PATH_COULD_NOT_BE_FOUND?;
|
||||
if (res) return io::PATH_COULD_NOT_BE_FOUND~;
|
||||
return string::from_wstring(tmem, (WString)path);
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ fn Path? native_home_directory(Allocator allocator) => @pool()
|
||||
$case NETBSD:
|
||||
$case OPENBSD:
|
||||
$case HAIKU:
|
||||
return path::new(allocator, env::tget_var("HOME")) ?? io::PATH_COULD_NOT_BE_FOUND?;
|
||||
return path::new(allocator, env::tget_var("HOME")) ?? io::PATH_COULD_NOT_BE_FOUND~;
|
||||
$case WIN32:
|
||||
return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_PROFILE));
|
||||
$default:
|
||||
return io::PATH_COULD_NOT_BE_FOUND?;
|
||||
return io::PATH_COULD_NOT_BE_FOUND~;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => @poo
|
||||
case TEMPLATES: return path::new(allocator, posix::xdg_user_dir_lookup(tmem, "TEMPLATES"));
|
||||
case SAVED_GAMES:
|
||||
case SCREENSHOTS: nextcase;
|
||||
default: return io::PATH_COULD_NOT_BE_FOUND?;
|
||||
default: return io::PATH_COULD_NOT_BE_FOUND~;
|
||||
}
|
||||
$case IOS:
|
||||
$case MACOS:
|
||||
@@ -85,7 +85,7 @@ fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => @poo
|
||||
case SAVED_GAMES:
|
||||
case SCREENSHOTS:
|
||||
case TEMPLATES: nextcase;
|
||||
default: return io::PATH_COULD_NOT_BE_FOUND?;
|
||||
default: return io::PATH_COULD_NOT_BE_FOUND~;
|
||||
}
|
||||
$case WIN32:
|
||||
switch (dir)
|
||||
@@ -100,10 +100,10 @@ fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => @poo
|
||||
case SCREENSHOTS: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_SCREENSHOTS));
|
||||
case TEMPLATES: return path::new(allocator, win32_get_known_folder_temp(&win32::FOLDERID_TEMPLATES));
|
||||
case PUBLIC_SHARE: nextcase;
|
||||
default: return io::PATH_COULD_NOT_BE_FOUND?;
|
||||
default: return io::PATH_COULD_NOT_BE_FOUND~;
|
||||
}
|
||||
$default:
|
||||
return io::PATH_COULD_NOT_BE_FOUND?;
|
||||
return io::PATH_COULD_NOT_BE_FOUND~;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
@@ -121,15 +121,16 @@ fn Path? native_temp_directory(Allocator allocator) @if(!env::WIN32)
|
||||
fn Path? native_temp_directory(Allocator allocator) @if(env::WIN32) => @pool()
|
||||
{
|
||||
Win32_DWORD len = win32::getTempPathW(0, null);
|
||||
if (!len) return io::GENERAL_ERROR?;
|
||||
Char16[] buff = mem::talloc_array(Char16, len + (usz)1);
|
||||
if (!win32::getTempPathW(len, buff)) return io::GENERAL_ERROR?;
|
||||
return path::new(allocator, string::tfrom_utf16(buff[:len]));
|
||||
if (!len) return io::GENERAL_ERROR~;
|
||||
Char16[] buff = mem::talloc_array(Char16, len);
|
||||
Win32_DWORD res = win32::getTempPathW(len, buff);
|
||||
if (!res) return io::GENERAL_ERROR~;
|
||||
return path::new(allocator, string::tfrom_utf16(buff[:res]));
|
||||
}
|
||||
|
||||
module std::io::os @if(env::NO_LIBC);
|
||||
import std::io::path;
|
||||
|
||||
macro Path? native_home_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND?;
|
||||
macro Path? native_temp_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND?;
|
||||
fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => io::PATH_COULD_NOT_BE_FOUND?;
|
||||
macro Path? native_home_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND~;
|
||||
macro Path? native_temp_directory(Allocator allocator) => io::PATH_COULD_NOT_BE_FOUND~;
|
||||
fn Path? native_user_directory(Allocator allocator, NativeSystemDir dir) => io::PATH_COULD_NOT_BE_FOUND~;
|
||||
|
||||
@@ -86,7 +86,7 @@ fn PathList? ls(Allocator allocator, Path dir, bool no_dirs = false, bool no_sym
|
||||
$if $defined(os::native_ls):
|
||||
return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator);
|
||||
$else
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
$endif
|
||||
}
|
||||
|
||||
@@ -137,11 +137,11 @@ macro bool? rmdir(path)
|
||||
*>
|
||||
fn void? rmtree(Path path)
|
||||
{
|
||||
if (!path.path_string.len) return INVALID_PATH?;
|
||||
if (!path.path_string.len) return INVALID_PATH~;
|
||||
$if $defined(os::native_rmtree):
|
||||
return os::native_rmtree(path);
|
||||
$else
|
||||
return io::UNSUPPORTED_OPERATION?;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
$endif
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ fn usz? start_of_base_name(String str, PathEnv path_env) @local
|
||||
// Find the \ before "foo"
|
||||
usz last_index = 2 + str[2..].index_of_char('\\')!;
|
||||
// If they don't match, we're done
|
||||
if (last_index > index) return INVALID_PATH?;
|
||||
if (last_index > index) return INVALID_PATH~;
|
||||
if (last_index != index) return index + 1;
|
||||
// Otherwise just default to the volume length.
|
||||
}
|
||||
@@ -246,7 +246,7 @@ fn Path? String.to_absolute_path(self, Allocator allocator) => @pool()
|
||||
fn Path? Path.absolute(self, Allocator allocator)
|
||||
{
|
||||
String path_str = self.str_view();
|
||||
if (!path_str.len) return INVALID_PATH?;
|
||||
if (!path_str.len) return INVALID_PATH~;
|
||||
if (self.is_absolute()!) return new(allocator, path_str, self.env);
|
||||
if (path_str == ".")
|
||||
{
|
||||
@@ -262,7 +262,7 @@ fn Path? Path.absolute(self, Allocator allocator)
|
||||
const usz BUFFER_LEN = 4096;
|
||||
WString buffer = (WString)mem::talloc_array(Char16, BUFFER_LEN);
|
||||
buffer = win32::_wfullpath(buffer, path_str.to_temp_wstring()!, BUFFER_LEN);
|
||||
if (!buffer) return INVALID_PATH?;
|
||||
if (!buffer) return INVALID_PATH~;
|
||||
return { string::from_wstring(allocator, buffer), WIN32, allocator };
|
||||
};
|
||||
$else
|
||||
@@ -371,10 +371,10 @@ fn usz? volume_name_len(String path, PathEnv path_env) @local
|
||||
base_found = i;
|
||||
continue;
|
||||
}
|
||||
if (is_reserved_win32_path_char(c)) return INVALID_PATH?;
|
||||
if (is_reserved_win32_path_char(c)) return INVALID_PATH~;
|
||||
}
|
||||
if (base_found > 0 && base_found + 1 < len) return len;
|
||||
return INVALID_PATH?;
|
||||
return INVALID_PATH~;
|
||||
case 'A'..'Z':
|
||||
case 'a'..'z':
|
||||
return path[1] == ':' ? 2 : 0;
|
||||
@@ -392,7 +392,7 @@ fn usz? volume_name_len(String path, PathEnv path_env) @local
|
||||
*>
|
||||
fn Path? Path.parent(self)
|
||||
{
|
||||
if (self.path_string.len == 1 && is_separator(self.path_string[0], self.env)) return NO_PARENT?;
|
||||
if (self.path_string.len == 1 && is_separator(self.path_string[0], self.env)) return NO_PARENT~;
|
||||
foreach_r(i, c : self.path_string)
|
||||
{
|
||||
if (is_separator(c, self.env))
|
||||
@@ -405,7 +405,7 @@ fn Path? Path.parent(self)
|
||||
// Handle C:\foo
|
||||
if (volume_len == i)
|
||||
{
|
||||
if (i + 1 == self.path_string.len) return NO_PARENT?;
|
||||
if (i + 1 == self.path_string.len) return NO_PARENT~;
|
||||
return { self.path_string[:i + 1], WIN32, null };
|
||||
}
|
||||
}
|
||||
@@ -413,7 +413,7 @@ fn Path? Path.parent(self)
|
||||
return { self.path_string[:i], self.env, null };
|
||||
}
|
||||
}
|
||||
return NO_PARENT?;
|
||||
return NO_PARENT~;
|
||||
}
|
||||
|
||||
fn String? normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
|
||||
@@ -455,7 +455,7 @@ fn String? normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
|
||||
|
||||
// The rest are names of the path elements, so check that the
|
||||
// characters are valid.
|
||||
if (is_reserved_path_char(c, path_env)) return INVALID_PATH?;
|
||||
if (is_reserved_path_char(c, path_env)) return INVALID_PATH~;
|
||||
|
||||
// If we have '.' after a separator
|
||||
if (c == '.' && previous_was_separator)
|
||||
@@ -488,7 +488,7 @@ fn String? normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
|
||||
continue;
|
||||
case 2:
|
||||
// This is an error: /a/../..
|
||||
if (len == path_start && has_root) return INVALID_PATH?;
|
||||
if (len == path_start && has_root) return INVALID_PATH~;
|
||||
|
||||
// If this .. at the start, or after ../? If so, we just copy ..
|
||||
if (len == path_start ||
|
||||
@@ -657,21 +657,21 @@ macro bool is_reserved_path_char(char c, PathEnv path_env = DEFAULT_ENV)
|
||||
}
|
||||
fn bool? _mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL) @private
|
||||
{
|
||||
if (!path.path_string.len) return INVALID_PATH?;
|
||||
if (!path.path_string.len) return INVALID_PATH~;
|
||||
if (is_dir(path)) return false;
|
||||
if (exists(path)) return io::FILE_NOT_DIR?;
|
||||
if (exists(path)) return io::FILE_NOT_DIR~;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
if (try parent = path.parent()) mkdir(parent, true, permissions)!;
|
||||
}
|
||||
if (!is_dir(path.parent()) ?? false) return io::CANNOT_READ_DIR?;
|
||||
if (!is_dir(path.parent()) ?? false) return io::CANNOT_READ_DIR~;
|
||||
|
||||
return os::native_mkdir(path, permissions);
|
||||
}
|
||||
|
||||
fn bool? _rmdir(Path path) @private
|
||||
{
|
||||
if (!path.path_string.len) return INVALID_PATH?;
|
||||
if (!path.path_string.len) return INVALID_PATH~;
|
||||
return os::native_rmdir(path);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
module std::io;
|
||||
import std::math;
|
||||
import std::core::env;
|
||||
|
||||
|
||||
interface InStream
|
||||
{
|
||||
@@ -36,7 +34,7 @@ fn usz? available(InStream s)
|
||||
s.seek(curr, Seek.SET)!;
|
||||
return len - curr;
|
||||
}
|
||||
return 0;
|
||||
return io::UNSUPPORTED_OPERATION~;
|
||||
}
|
||||
|
||||
macro bool @is_instream(#expr) @const
|
||||
@@ -85,26 +83,36 @@ macro usz? read_all(stream, char[] buffer)
|
||||
{
|
||||
if (buffer.len == 0) return 0;
|
||||
usz n = stream.read(buffer)!;
|
||||
if (n != buffer.len) return UNEXPECTED_EOF?;
|
||||
if (n != buffer.len) return UNEXPECTED_EOF~;
|
||||
return n;
|
||||
}
|
||||
|
||||
<*
|
||||
This function will read to the end of the stream.
|
||||
|
||||
@require @is_instream(stream)
|
||||
*>
|
||||
macro char[]? read_fully(Allocator allocator, stream)
|
||||
{
|
||||
usz len = available(stream)!;
|
||||
char* data = allocator::malloc_try(allocator, len)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
// Efficient path if it is possible to pre-allocate
|
||||
if (try len = available(stream))
|
||||
{
|
||||
read += stream.read(data[read:len - read])!;
|
||||
char* data = allocator::malloc_try(allocator, len)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
{
|
||||
read += stream.read(data[read:len - read])!;
|
||||
}
|
||||
return data[:len];
|
||||
}
|
||||
return data[:len];
|
||||
ByteWriter writer;
|
||||
writer.init(allocator);
|
||||
copy_to(stream, &writer)!;
|
||||
return writer.array_view();
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
@require @is_outstream(stream)
|
||||
*>
|
||||
@@ -112,7 +120,7 @@ macro usz? write_all(stream, char[] buffer)
|
||||
{
|
||||
if (buffer.len == 0) return 0;
|
||||
usz n = stream.write(buffer)!;
|
||||
if (n != buffer.len) return INCOMPLETE_WRITE?;
|
||||
if (n != buffer.len) return INCOMPLETE_WRITE~;
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -128,7 +136,7 @@ macro usz? read_using_read_byte(s, char[] buffer)
|
||||
if (catch err = c)
|
||||
{
|
||||
if (err == io::EOF) return len;
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
*cptr = c;
|
||||
len++;
|
||||
@@ -152,7 +160,7 @@ macro char? read_byte_using_read(s)
|
||||
{
|
||||
char[1] buffer;
|
||||
usz read = s.read(&buffer)!;
|
||||
if (read != 1) return io::EOF?;
|
||||
if (read != 1) return io::EOF~;
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
@@ -197,12 +205,12 @@ macro usz? copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local
|
||||
if (catch err = len)
|
||||
{
|
||||
if (err == io::EOF) return total_copied;
|
||||
return err?;
|
||||
return err~;
|
||||
}
|
||||
if (!len) return total_copied;
|
||||
usz written = dst.write(buffer[:len])!;
|
||||
total_copied += len;
|
||||
if (written != len) return INCOMPLETE_WRITE?;
|
||||
if (written != len) return INCOMPLETE_WRITE~;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,8 +232,8 @@ macro usz? read_varint(stream, x_ptr)
|
||||
char? c = stream.read_byte();
|
||||
if (catch err = c)
|
||||
{
|
||||
if (err == io::EOF) return io::UNEXPECTED_EOF?;
|
||||
return err?;
|
||||
if (err == io::EOF) return io::UNEXPECTED_EOF~;
|
||||
return err~;
|
||||
}
|
||||
n++;
|
||||
if (c & 0x80 == 0)
|
||||
@@ -241,7 +249,7 @@ macro usz? read_varint(stream, x_ptr)
|
||||
x |= (c & 0x7F) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
return math::OVERFLOW?;
|
||||
return math::OVERFLOW~;
|
||||
}
|
||||
<*
|
||||
@require @is_outstream(stream)
|
||||
|
||||
@@ -49,7 +49,7 @@ fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
|
||||
fn char? ReadBuffer.read_byte(&self) @dynamic
|
||||
{
|
||||
if (self.read_idx == self.write_idx) self.refill()!;
|
||||
if (self.read_idx == self.write_idx) return io::EOF?;
|
||||
if (self.read_idx == self.write_idx) return io::EOF~;
|
||||
char c = self.bytes[self.read_idx];
|
||||
self.read_idx++;
|
||||
return c;
|
||||
@@ -132,5 +132,5 @@ fn void? WriteBuffer.write_byte(&self, char c) @dynamic
|
||||
fn void? WriteBuffer.write_pending(&self) @local
|
||||
{
|
||||
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
|
||||
if (self.index != 0) return INCOMPLETE_WRITE?;
|
||||
if (self.index != 0) return INCOMPLETE_WRITE~;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user