asmjit 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/asmjit.gemspec +1 -1
- data/ext/asmjit/asmjit/.editorconfig +10 -0
- data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
- data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
- data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
- data/ext/asmjit/asmjit/.gitignore +6 -0
- data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
- data/ext/asmjit/asmjit/LICENSE.md +17 -0
- data/ext/asmjit/asmjit/README.md +69 -0
- data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
- data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
- data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
- data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
- data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
- data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
- data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
- data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
- data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
- data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
- data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
- data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
- data/ext/asmjit/asmjit/test/broken.cpp +312 -0
- data/ext/asmjit/asmjit/test/broken.h +148 -0
- data/ext/asmjit/asmjit/test/cmdline.h +61 -0
- data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
- data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
- data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
- data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
- data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
- data/ext/asmjit/asmjit.cc +18 -0
- data/lib/asmjit/version.rb +1 -1
- metadata +197 -2
@@ -0,0 +1,120 @@
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
2
|
+
//
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
4
|
+
// SPDX-License-Identifier: Zlib
|
5
|
+
|
6
|
+
#ifndef ASMJIT_CORE_ZONESTRING_H_INCLUDED
|
7
|
+
#define ASMJIT_CORE_ZONESTRING_H_INCLUDED
|
8
|
+
|
9
|
+
#include "../core/globals.h"
|
10
|
+
#include "../core/zone.h"
|
11
|
+
|
12
|
+
ASMJIT_BEGIN_NAMESPACE
|
13
|
+
|
14
|
+
//! \addtogroup asmjit_zone
|
15
|
+
//! \{
|
16
|
+
|
17
|
+
//! A helper class used by \ref ZoneString implementation.
|
18
|
+
struct ZoneStringBase {
|
19
|
+
union {
|
20
|
+
struct {
|
21
|
+
uint32_t _size;
|
22
|
+
char _embedded[sizeof(void*) * 2 - 4];
|
23
|
+
};
|
24
|
+
struct {
|
25
|
+
void* _dummy;
|
26
|
+
char* _external;
|
27
|
+
};
|
28
|
+
};
|
29
|
+
|
30
|
+
inline void reset() noexcept {
|
31
|
+
_dummy = nullptr;
|
32
|
+
_external = nullptr;
|
33
|
+
}
|
34
|
+
|
35
|
+
Error setData(Zone* zone, uint32_t maxEmbeddedSize, const char* str, size_t size) noexcept {
|
36
|
+
if (size == SIZE_MAX)
|
37
|
+
size = strlen(str);
|
38
|
+
|
39
|
+
if (size <= maxEmbeddedSize) {
|
40
|
+
memcpy(_embedded, str, size);
|
41
|
+
_embedded[size] = '\0';
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
char* external = static_cast<char*>(zone->dup(str, size, true));
|
45
|
+
if (ASMJIT_UNLIKELY(!external))
|
46
|
+
return DebugUtils::errored(kErrorOutOfMemory);
|
47
|
+
_external = external;
|
48
|
+
}
|
49
|
+
|
50
|
+
_size = uint32_t(size);
|
51
|
+
return kErrorOk;
|
52
|
+
}
|
53
|
+
};
|
54
|
+
|
55
|
+
//! A string template that can be zone allocated.
|
56
|
+
//!
|
57
|
+
//! Helps with creating strings that can be either statically allocated if they are small, or externally allocated
|
58
|
+
//! in case their size exceeds the limit. The `N` represents the size of the whole `ZoneString` structure, based on
|
59
|
+
//! that size the maximum size of the internal buffer is determined.
|
60
|
+
template<size_t N>
|
61
|
+
class ZoneString {
|
62
|
+
public:
|
63
|
+
//! \name Constants
|
64
|
+
//! \{
|
65
|
+
|
66
|
+
enum : uint32_t {
|
67
|
+
kWholeSize = (N > sizeof(ZoneStringBase)) ? uint32_t(N) : uint32_t(sizeof(ZoneStringBase)),
|
68
|
+
kMaxEmbeddedSize = kWholeSize - 5
|
69
|
+
};
|
70
|
+
|
71
|
+
//! \}
|
72
|
+
|
73
|
+
//! \name Members
|
74
|
+
//! \{
|
75
|
+
|
76
|
+
union {
|
77
|
+
ZoneStringBase _base;
|
78
|
+
char _wholeData[kWholeSize];
|
79
|
+
};
|
80
|
+
|
81
|
+
//! \}
|
82
|
+
|
83
|
+
//! \name Construction & Destruction
|
84
|
+
//! \{
|
85
|
+
|
86
|
+
inline ZoneString() noexcept { reset(); }
|
87
|
+
inline void reset() noexcept { _base.reset(); }
|
88
|
+
|
89
|
+
//! \}
|
90
|
+
|
91
|
+
//! \name Accessors
|
92
|
+
//! \{
|
93
|
+
|
94
|
+
//! Tests whether the string is empty.
|
95
|
+
inline bool empty() const noexcept { return _base._size == 0; }
|
96
|
+
|
97
|
+
//! Returns the string data.
|
98
|
+
inline const char* data() const noexcept { return _base._size <= kMaxEmbeddedSize ? _base._embedded : _base._external; }
|
99
|
+
//! Returns the string size.
|
100
|
+
inline uint32_t size() const noexcept { return _base._size; }
|
101
|
+
|
102
|
+
//! Tests whether the string is embedded (e.g. no dynamically allocated).
|
103
|
+
inline bool isEmbedded() const noexcept { return _base._size <= kMaxEmbeddedSize; }
|
104
|
+
|
105
|
+
//! Copies a new `data` of the given `size` to the string.
|
106
|
+
//!
|
107
|
+
//! If the `size` exceeds the internal buffer the given `zone` will be used to duplicate the data, otherwise
|
108
|
+
//! the internal buffer will be used as a storage.
|
109
|
+
inline Error setData(Zone* zone, const char* data, size_t size) noexcept {
|
110
|
+
return _base.setData(zone, kMaxEmbeddedSize, data, size);
|
111
|
+
}
|
112
|
+
|
113
|
+
//! \}
|
114
|
+
};
|
115
|
+
|
116
|
+
//! \}
|
117
|
+
|
118
|
+
ASMJIT_END_NAMESPACE
|
119
|
+
|
120
|
+
#endif // ASMJIT_CORE_ZONESTRING_H_INCLUDED
|
@@ -0,0 +1,99 @@
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
2
|
+
//
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
4
|
+
// SPDX-License-Identifier: Zlib
|
5
|
+
|
6
|
+
#include "../core/api-build_p.h"
|
7
|
+
#include "../core/support.h"
|
8
|
+
#include "../core/zone.h"
|
9
|
+
#include "../core/zonetree.h"
|
10
|
+
|
11
|
+
ASMJIT_BEGIN_NAMESPACE
|
12
|
+
|
13
|
+
// ZoneTreeBase - Tests
|
14
|
+
// ====================
|
15
|
+
|
16
|
+
#if defined(ASMJIT_TEST)
|
17
|
+
template<typename NodeT>
|
18
|
+
struct ZoneRBUnit {
|
19
|
+
typedef ZoneTree<NodeT> Tree;
|
20
|
+
|
21
|
+
static void verifyTree(Tree& tree) noexcept {
|
22
|
+
EXPECT(checkHeight(static_cast<NodeT*>(tree._root)) > 0);
|
23
|
+
}
|
24
|
+
|
25
|
+
// Check whether the Red-Black tree is valid.
|
26
|
+
static int checkHeight(NodeT* node) noexcept {
|
27
|
+
if (!node) return 1;
|
28
|
+
|
29
|
+
NodeT* ln = node->left();
|
30
|
+
NodeT* rn = node->right();
|
31
|
+
|
32
|
+
// Invalid tree.
|
33
|
+
EXPECT(ln == nullptr || *ln < *node);
|
34
|
+
EXPECT(rn == nullptr || *rn > *node);
|
35
|
+
|
36
|
+
// Red violation.
|
37
|
+
EXPECT(!node->isRed() ||
|
38
|
+
(!ZoneTreeNode::_isValidRed(ln) && !ZoneTreeNode::_isValidRed(rn)));
|
39
|
+
|
40
|
+
// Black violation.
|
41
|
+
int lh = checkHeight(ln);
|
42
|
+
int rh = checkHeight(rn);
|
43
|
+
EXPECT(!lh || !rh || lh == rh);
|
44
|
+
|
45
|
+
// Only count black links.
|
46
|
+
return (lh && rh) ? lh + !node->isRed() : 0;
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
class MyRBNode : public ZoneTreeNodeT<MyRBNode> {
|
51
|
+
public:
|
52
|
+
ASMJIT_NONCOPYABLE(MyRBNode)
|
53
|
+
|
54
|
+
inline explicit MyRBNode(uint32_t key) noexcept
|
55
|
+
: _key(key) {}
|
56
|
+
|
57
|
+
inline bool operator<(const MyRBNode& other) const noexcept { return _key < other._key; }
|
58
|
+
inline bool operator>(const MyRBNode& other) const noexcept { return _key > other._key; }
|
59
|
+
|
60
|
+
inline bool operator<(uint32_t queryKey) const noexcept { return _key < queryKey; }
|
61
|
+
inline bool operator>(uint32_t queryKey) const noexcept { return _key > queryKey; }
|
62
|
+
|
63
|
+
uint32_t _key;
|
64
|
+
};
|
65
|
+
|
66
|
+
UNIT(zone_rbtree) {
|
67
|
+
uint32_t kCount = BrokenAPI::hasArg("--quick") ? 1000 : 10000;
|
68
|
+
|
69
|
+
Zone zone(4096);
|
70
|
+
ZoneTree<MyRBNode> rbTree;
|
71
|
+
|
72
|
+
uint32_t key;
|
73
|
+
INFO("Inserting %u elements to RBTree and validating each operation", unsigned(kCount));
|
74
|
+
for (key = 0; key < kCount; key++) {
|
75
|
+
rbTree.insert(zone.newT<MyRBNode>(key));
|
76
|
+
ZoneRBUnit<MyRBNode>::verifyTree(rbTree);
|
77
|
+
}
|
78
|
+
|
79
|
+
uint32_t count = kCount;
|
80
|
+
INFO("Removing %u elements from RBTree and validating each operation", unsigned(kCount));
|
81
|
+
do {
|
82
|
+
MyRBNode* node;
|
83
|
+
|
84
|
+
for (key = 0; key < count; key++) {
|
85
|
+
node = rbTree.get(key);
|
86
|
+
EXPECT(node != nullptr);
|
87
|
+
EXPECT(node->_key == key);
|
88
|
+
}
|
89
|
+
|
90
|
+
node = rbTree.get(--count);
|
91
|
+
rbTree.remove(node);
|
92
|
+
ZoneRBUnit<MyRBNode>::verifyTree(rbTree);
|
93
|
+
} while (count);
|
94
|
+
|
95
|
+
EXPECT(rbTree.empty());
|
96
|
+
}
|
97
|
+
#endif
|
98
|
+
|
99
|
+
ASMJIT_END_NAMESPACE
|
@@ -0,0 +1,380 @@
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
2
|
+
//
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
4
|
+
// SPDX-License-Identifier: Zlib
|
5
|
+
|
6
|
+
#ifndef ASMJIT_CORE_ZONETREE_H_INCLUDED
|
7
|
+
#define ASMJIT_CORE_ZONETREE_H_INCLUDED
|
8
|
+
|
9
|
+
#include "../core/support.h"
|
10
|
+
|
11
|
+
ASMJIT_BEGIN_NAMESPACE
|
12
|
+
|
13
|
+
//! \addtogroup asmjit_zone
|
14
|
+
//! \{
|
15
|
+
|
16
|
+
//! RB-Tree node.
|
17
|
+
//!
|
18
|
+
//! The color is stored in a least significant bit of the `left` node.
|
19
|
+
//!
|
20
|
+
//! WARNING: Always use accessors to access left and right children.
|
21
|
+
class ZoneTreeNode {
|
22
|
+
public:
|
23
|
+
ASMJIT_NONCOPYABLE(ZoneTreeNode)
|
24
|
+
|
25
|
+
//! \name Constants
|
26
|
+
//! \{
|
27
|
+
|
28
|
+
enum : uintptr_t {
|
29
|
+
kRedMask = 0x1,
|
30
|
+
kPtrMask = ~kRedMask
|
31
|
+
};
|
32
|
+
|
33
|
+
//! \}
|
34
|
+
|
35
|
+
//! \name Members
|
36
|
+
//! \{
|
37
|
+
|
38
|
+
uintptr_t _rbNodeData[2];
|
39
|
+
|
40
|
+
//! \}
|
41
|
+
|
42
|
+
//! \name Construction & Destruction
|
43
|
+
//! \{
|
44
|
+
|
45
|
+
inline ZoneTreeNode() noexcept
|
46
|
+
: _rbNodeData { 0, 0 } {}
|
47
|
+
|
48
|
+
//! \}
|
49
|
+
|
50
|
+
//! \name Accessors
|
51
|
+
//! \{
|
52
|
+
|
53
|
+
inline bool isRed() const noexcept { return static_cast<bool>(_rbNodeData[0] & kRedMask); }
|
54
|
+
|
55
|
+
inline bool hasChild(size_t i) const noexcept { return _rbNodeData[i] > kRedMask; }
|
56
|
+
inline bool hasLeft() const noexcept { return _rbNodeData[0] > kRedMask; }
|
57
|
+
inline bool hasRight() const noexcept { return _rbNodeData[1] != 0; }
|
58
|
+
|
59
|
+
template<typename T = ZoneTreeNode>
|
60
|
+
inline T* child(size_t i) const noexcept { return static_cast<T*>(_getChild(i)); }
|
61
|
+
template<typename T = ZoneTreeNode>
|
62
|
+
inline T* left() const noexcept { return static_cast<T*>(_getLeft()); }
|
63
|
+
template<typename T = ZoneTreeNode>
|
64
|
+
inline T* right() const noexcept { return static_cast<T*>(_getRight()); }
|
65
|
+
|
66
|
+
//! \}
|
67
|
+
|
68
|
+
//! \cond INTERNAL
|
69
|
+
//! \name Internal
|
70
|
+
//! \{
|
71
|
+
|
72
|
+
inline ZoneTreeNode* _getChild(size_t i) const noexcept { return (ZoneTreeNode*)(_rbNodeData[i] & kPtrMask); }
|
73
|
+
inline ZoneTreeNode* _getLeft() const noexcept { return (ZoneTreeNode*)(_rbNodeData[0] & kPtrMask); }
|
74
|
+
inline ZoneTreeNode* _getRight() const noexcept { return (ZoneTreeNode*)(_rbNodeData[1]); }
|
75
|
+
|
76
|
+
inline void _setChild(size_t i, ZoneTreeNode* node) noexcept { _rbNodeData[i] = (_rbNodeData[i] & kRedMask) | (uintptr_t)node; }
|
77
|
+
inline void _setLeft(ZoneTreeNode* node) noexcept { _rbNodeData[0] = (_rbNodeData[0] & kRedMask) | (uintptr_t)node; }
|
78
|
+
inline void _setRight(ZoneTreeNode* node) noexcept { _rbNodeData[1] = (uintptr_t)node; }
|
79
|
+
|
80
|
+
inline void _makeRed() noexcept { _rbNodeData[0] |= kRedMask; }
|
81
|
+
inline void _makeBlack() noexcept { _rbNodeData[0] &= kPtrMask; }
|
82
|
+
|
83
|
+
//! Tests whether the node is RED (RED node must be non-null and must have RED flag set).
|
84
|
+
static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return node && node->isRed(); }
|
85
|
+
|
86
|
+
//! \}
|
87
|
+
//! \endcond
|
88
|
+
};
|
89
|
+
|
90
|
+
//! RB-Tree node casted to `NodeT`.
|
91
|
+
template<typename NodeT>
|
92
|
+
class ZoneTreeNodeT : public ZoneTreeNode {
|
93
|
+
public:
|
94
|
+
ASMJIT_NONCOPYABLE(ZoneTreeNodeT)
|
95
|
+
|
96
|
+
//! \name Construction & Destruction
|
97
|
+
//! \{
|
98
|
+
|
99
|
+
inline ZoneTreeNodeT() noexcept
|
100
|
+
: ZoneTreeNode() {}
|
101
|
+
|
102
|
+
//! \}
|
103
|
+
|
104
|
+
//! \name Accessors
|
105
|
+
//! \{
|
106
|
+
|
107
|
+
inline NodeT* child(size_t i) const noexcept { return static_cast<NodeT*>(_getChild(i)); }
|
108
|
+
inline NodeT* left() const noexcept { return static_cast<NodeT*>(_getLeft()); }
|
109
|
+
inline NodeT* right() const noexcept { return static_cast<NodeT*>(_getRight()); }
|
110
|
+
|
111
|
+
//! \}
|
112
|
+
};
|
113
|
+
|
114
|
+
//! RB-Tree.
|
115
|
+
template<typename NodeT>
|
116
|
+
class ZoneTree {
|
117
|
+
public:
|
118
|
+
ASMJIT_NONCOPYABLE(ZoneTree)
|
119
|
+
|
120
|
+
typedef NodeT Node;
|
121
|
+
NodeT* _root;
|
122
|
+
|
123
|
+
//! \name Construction & Destruction
|
124
|
+
//! \{
|
125
|
+
|
126
|
+
inline ZoneTree() noexcept
|
127
|
+
: _root(nullptr) {}
|
128
|
+
|
129
|
+
inline ZoneTree(ZoneTree&& other) noexcept
|
130
|
+
: _root(other._root) {}
|
131
|
+
|
132
|
+
inline void reset() noexcept { _root = nullptr; }
|
133
|
+
|
134
|
+
//! \}
|
135
|
+
|
136
|
+
//! \name Accessors
|
137
|
+
//! \{
|
138
|
+
|
139
|
+
inline bool empty() const noexcept { return _root == nullptr; }
|
140
|
+
inline NodeT* root() const noexcept { return static_cast<NodeT*>(_root); }
|
141
|
+
|
142
|
+
//! \}
|
143
|
+
|
144
|
+
//! \name Utilities
|
145
|
+
//! \{
|
146
|
+
|
147
|
+
inline void swap(ZoneTree& other) noexcept {
|
148
|
+
std::swap(_root, other._root);
|
149
|
+
}
|
150
|
+
|
151
|
+
template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
152
|
+
void insert(NodeT* ASMJIT_NONNULL(node), const CompareT& cmp = CompareT()) noexcept {
|
153
|
+
// Node to insert must not contain garbage.
|
154
|
+
ASMJIT_ASSERT(!node->hasLeft());
|
155
|
+
ASMJIT_ASSERT(!node->hasRight());
|
156
|
+
ASMJIT_ASSERT(!node->isRed());
|
157
|
+
|
158
|
+
if (!_root) {
|
159
|
+
_root = node;
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
|
163
|
+
ZoneTreeNode head; // False root node,
|
164
|
+
head._setRight(_root); // having root on the right.
|
165
|
+
|
166
|
+
ZoneTreeNode* g = nullptr; // Grandparent.
|
167
|
+
ZoneTreeNode* p = nullptr; // Parent.
|
168
|
+
ZoneTreeNode* t = &head; // Iterator.
|
169
|
+
ZoneTreeNode* q = _root; // Query.
|
170
|
+
|
171
|
+
size_t dir = 0; // Direction for accessing child nodes.
|
172
|
+
size_t last = 0; // Not needed to initialize, but makes some tools happy.
|
173
|
+
|
174
|
+
node->_makeRed(); // New nodes are always red and violations fixed appropriately.
|
175
|
+
|
176
|
+
// Search down the tree.
|
177
|
+
for (;;) {
|
178
|
+
if (!q) {
|
179
|
+
// Insert new node at the bottom.
|
180
|
+
q = node;
|
181
|
+
p->_setChild(dir, node);
|
182
|
+
}
|
183
|
+
else if (_isValidRed(q->_getLeft()) && _isValidRed(q->_getRight())) {
|
184
|
+
// Color flip.
|
185
|
+
q->_makeRed();
|
186
|
+
q->_getLeft()->_makeBlack();
|
187
|
+
q->_getRight()->_makeBlack();
|
188
|
+
}
|
189
|
+
|
190
|
+
// Fix red violation.
|
191
|
+
if (_isValidRed(q) && _isValidRed(p)) {
|
192
|
+
ASMJIT_ASSUME(g != nullptr);
|
193
|
+
ASMJIT_ASSUME(p != nullptr);
|
194
|
+
t->_setChild(t->_getRight() == g,
|
195
|
+
q == p->_getChild(last) ? _singleRotate(g, !last) : _doubleRotate(g, !last));
|
196
|
+
}
|
197
|
+
|
198
|
+
// Stop if found.
|
199
|
+
if (q == node)
|
200
|
+
break;
|
201
|
+
|
202
|
+
last = dir;
|
203
|
+
dir = cmp(*static_cast<NodeT*>(q), *static_cast<NodeT*>(node)) < 0;
|
204
|
+
|
205
|
+
// Update helpers.
|
206
|
+
if (g) t = g;
|
207
|
+
|
208
|
+
g = p;
|
209
|
+
p = q;
|
210
|
+
q = q->_getChild(dir);
|
211
|
+
}
|
212
|
+
|
213
|
+
// Update root and make it black.
|
214
|
+
_root = static_cast<NodeT*>(head._getRight());
|
215
|
+
_root->_makeBlack();
|
216
|
+
}
|
217
|
+
|
218
|
+
//! Remove node from RBTree.
|
219
|
+
template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
220
|
+
void remove(ZoneTreeNode* ASMJIT_NONNULL(node), const CompareT& cmp = CompareT()) noexcept {
|
221
|
+
ZoneTreeNode head; // False root node,
|
222
|
+
head._setRight(_root); // having root on the right.
|
223
|
+
|
224
|
+
ZoneTreeNode* g = nullptr; // Grandparent.
|
225
|
+
ZoneTreeNode* p = nullptr; // Parent.
|
226
|
+
ZoneTreeNode* q = &head; // Query.
|
227
|
+
|
228
|
+
ZoneTreeNode* f = nullptr; // Found item.
|
229
|
+
ZoneTreeNode* gf = nullptr; // Found grandparent.
|
230
|
+
size_t dir = 1; // Direction (0 or 1).
|
231
|
+
|
232
|
+
// Search and push a red down.
|
233
|
+
while (q->hasChild(dir)) {
|
234
|
+
size_t last = dir;
|
235
|
+
|
236
|
+
// Update helpers.
|
237
|
+
g = p;
|
238
|
+
p = q;
|
239
|
+
q = q->_getChild(dir);
|
240
|
+
dir = cmp(*static_cast<NodeT*>(q), *static_cast<NodeT*>(node)) < 0;
|
241
|
+
|
242
|
+
// Save found node.
|
243
|
+
if (q == node) {
|
244
|
+
f = q;
|
245
|
+
gf = g;
|
246
|
+
}
|
247
|
+
|
248
|
+
// Push the red node down.
|
249
|
+
if (!_isValidRed(q) && !_isValidRed(q->_getChild(dir))) {
|
250
|
+
if (_isValidRed(q->_getChild(!dir))) {
|
251
|
+
ZoneTreeNode* child = _singleRotate(q, dir);
|
252
|
+
p->_setChild(last, child);
|
253
|
+
p = child;
|
254
|
+
}
|
255
|
+
else if (!_isValidRed(q->_getChild(!dir)) && p->_getChild(!last)) {
|
256
|
+
ZoneTreeNode* s = p->_getChild(!last);
|
257
|
+
if (!_isValidRed(s->_getChild(!last)) && !_isValidRed(s->_getChild(last))) {
|
258
|
+
// Color flip.
|
259
|
+
p->_makeBlack();
|
260
|
+
s->_makeRed();
|
261
|
+
q->_makeRed();
|
262
|
+
}
|
263
|
+
else {
|
264
|
+
ASMJIT_ASSUME(g != nullptr);
|
265
|
+
ASMJIT_ASSUME(s != nullptr);
|
266
|
+
|
267
|
+
size_t dir2 = g->_getRight() == p;
|
268
|
+
ZoneTreeNode* child = g->_getChild(dir2);
|
269
|
+
|
270
|
+
if (_isValidRed(s->_getChild(last))) {
|
271
|
+
child = _doubleRotate(p, last);
|
272
|
+
g->_setChild(dir2, child);
|
273
|
+
}
|
274
|
+
else if (_isValidRed(s->_getChild(!last))) {
|
275
|
+
child = _singleRotate(p, last);
|
276
|
+
g->_setChild(dir2, child);
|
277
|
+
}
|
278
|
+
|
279
|
+
// Ensure correct coloring.
|
280
|
+
q->_makeRed();
|
281
|
+
child->_makeRed();
|
282
|
+
child->_getLeft()->_makeBlack();
|
283
|
+
child->_getRight()->_makeBlack();
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
// Replace and remove.
|
290
|
+
ASMJIT_ASSERT(f != nullptr);
|
291
|
+
ASMJIT_ASSERT(f != &head);
|
292
|
+
ASMJIT_ASSERT(q != &head);
|
293
|
+
|
294
|
+
p->_setChild(p->_getRight() == q,
|
295
|
+
q->_getChild(q->_getLeft() == nullptr));
|
296
|
+
|
297
|
+
// NOTE: The original algorithm used a trick to just copy 'key/value' to `f` and mark `q` for deletion. But this
|
298
|
+
// is unacceptable here as we really want to destroy the passed `node`. So, we have to make sure that we have
|
299
|
+
// really removed `f` and not `q`.
|
300
|
+
if (f != q) {
|
301
|
+
ASMJIT_ASSERT(f != &head);
|
302
|
+
ASMJIT_ASSERT(f != gf);
|
303
|
+
|
304
|
+
ZoneTreeNode* n = gf ? gf : &head;
|
305
|
+
dir = (n == &head) ? 1 : cmp(*static_cast<NodeT*>(n), *static_cast<NodeT*>(node)) < 0;
|
306
|
+
|
307
|
+
for (;;) {
|
308
|
+
if (n->_getChild(dir) == f) {
|
309
|
+
n->_setChild(dir, q);
|
310
|
+
// RAW copy, including the color.
|
311
|
+
q->_rbNodeData[0] = f->_rbNodeData[0];
|
312
|
+
q->_rbNodeData[1] = f->_rbNodeData[1];
|
313
|
+
break;
|
314
|
+
}
|
315
|
+
|
316
|
+
n = n->_getChild(dir);
|
317
|
+
|
318
|
+
// Cannot be true as we know that it must reach `f` in few iterations.
|
319
|
+
ASMJIT_ASSERT(n != nullptr);
|
320
|
+
dir = cmp(*static_cast<NodeT*>(n), *static_cast<NodeT*>(node)) < 0;
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
// Update root and make it black.
|
325
|
+
_root = static_cast<NodeT*>(head._getRight());
|
326
|
+
if (_root) _root->_makeBlack();
|
327
|
+
}
|
328
|
+
|
329
|
+
template<typename KeyT, typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
330
|
+
inline NodeT* get(const KeyT& key, const CompareT& cmp = CompareT()) const noexcept {
|
331
|
+
ZoneTreeNode* node = _root;
|
332
|
+
while (node) {
|
333
|
+
auto result = cmp(*static_cast<const NodeT*>(node), key);
|
334
|
+
if (result == 0) break;
|
335
|
+
|
336
|
+
// Go left or right depending on the `result`.
|
337
|
+
node = node->_getChild(result < 0);
|
338
|
+
}
|
339
|
+
return static_cast<NodeT*>(node);
|
340
|
+
}
|
341
|
+
|
342
|
+
//! \}
|
343
|
+
|
344
|
+
//! \cond INTERNAL
|
345
|
+
//! \name Internal
|
346
|
+
//! \{
|
347
|
+
|
348
|
+
static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return ZoneTreeNode::_isValidRed(node); }
|
349
|
+
|
350
|
+
//! Single rotation.
|
351
|
+
static inline ZoneTreeNode* _singleRotate(ZoneTreeNode* ASMJIT_NONNULL(root), size_t dir) noexcept {
|
352
|
+
ZoneTreeNode* save = root->_getChild(!dir);
|
353
|
+
ASMJIT_ASSUME(save != nullptr);
|
354
|
+
|
355
|
+
ZoneTreeNode* saveChild = save->_getChild(dir);
|
356
|
+
root->_setChild(!dir, saveChild);
|
357
|
+
save->_setChild( dir, root);
|
358
|
+
root->_makeRed();
|
359
|
+
save->_makeBlack();
|
360
|
+
return save;
|
361
|
+
}
|
362
|
+
|
363
|
+
//! Double rotation.
|
364
|
+
static inline ZoneTreeNode* _doubleRotate(ZoneTreeNode* ASMJIT_NONNULL(root), size_t dir) noexcept {
|
365
|
+
ZoneTreeNode* child = root->_getChild(!dir);
|
366
|
+
ASMJIT_ASSUME(child != nullptr);
|
367
|
+
|
368
|
+
root->_setChild(!dir, _singleRotate(child, !dir));
|
369
|
+
return _singleRotate(root, dir);
|
370
|
+
}
|
371
|
+
|
372
|
+
//! \}
|
373
|
+
//! \endcond
|
374
|
+
};
|
375
|
+
|
376
|
+
//! \}
|
377
|
+
|
378
|
+
ASMJIT_END_NAMESPACE
|
379
|
+
|
380
|
+
#endif // ASMJIT_CORE_ZONETREE_H_INCLUDED
|