asmjit 0.2.0 → 0.2.2
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/Rakefile +5 -3
- data/asmjit.gemspec +1 -3
- 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 +167 -30
- data/ext/asmjit/extconf.rb +9 -9
- data/lib/asmjit/version.rb +1 -1
- data/lib/asmjit.rb +14 -4
- metadata +198 -17
@@ -0,0 +1,1773 @@
|
|
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_SUPPORT_H_INCLUDED
|
7
|
+
#define ASMJIT_CORE_SUPPORT_H_INCLUDED
|
8
|
+
|
9
|
+
#include "../core/globals.h"
|
10
|
+
|
11
|
+
#if defined(_MSC_VER)
|
12
|
+
#include <intrin.h>
|
13
|
+
#endif
|
14
|
+
|
15
|
+
ASMJIT_BEGIN_NAMESPACE
|
16
|
+
|
17
|
+
//! \addtogroup asmjit_utilities
|
18
|
+
//! \{
|
19
|
+
|
20
|
+
//! Contains support classes and functions that may be used by AsmJit source and header files. Anything defined
|
21
|
+
//! here is considered internal and should not be used outside of AsmJit and related projects like AsmTK.
|
22
|
+
namespace Support {
|
23
|
+
|
24
|
+
// Support - Basic Traits
|
25
|
+
// ======================
|
26
|
+
|
27
|
+
#if ASMJIT_ARCH_X86
|
28
|
+
typedef uint8_t FastUInt8;
|
29
|
+
#else
|
30
|
+
typedef uint32_t FastUInt8;
|
31
|
+
#endif
|
32
|
+
|
33
|
+
//! \cond INTERNAL
|
34
|
+
namespace Internal {
|
35
|
+
template<typename T, size_t Alignment>
|
36
|
+
struct AliasedUInt {};
|
37
|
+
|
38
|
+
template<> struct AliasedUInt<uint16_t, 2> { typedef uint16_t ASMJIT_MAY_ALIAS T; };
|
39
|
+
template<> struct AliasedUInt<uint32_t, 4> { typedef uint32_t ASMJIT_MAY_ALIAS T; };
|
40
|
+
template<> struct AliasedUInt<uint64_t, 8> { typedef uint64_t ASMJIT_MAY_ALIAS T; };
|
41
|
+
|
42
|
+
template<> struct AliasedUInt<uint16_t, 1> { typedef uint16_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
|
43
|
+
template<> struct AliasedUInt<uint32_t, 1> { typedef uint32_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
|
44
|
+
template<> struct AliasedUInt<uint32_t, 2> { typedef uint32_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 2); };
|
45
|
+
template<> struct AliasedUInt<uint64_t, 1> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
|
46
|
+
template<> struct AliasedUInt<uint64_t, 2> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 2); };
|
47
|
+
template<> struct AliasedUInt<uint64_t, 4> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 4); };
|
48
|
+
|
49
|
+
// StdInt - Make an int-type by size (signed or unsigned) that is the
|
50
|
+
// same as types defined by <stdint.h>.
|
51
|
+
// Int32Or64 - Make an int-type that has at least 32 bits: [u]int[32|64]_t.
|
52
|
+
|
53
|
+
template<size_t Size, unsigned Unsigned>
|
54
|
+
struct StdInt {}; // Fail if not specialized.
|
55
|
+
|
56
|
+
template<> struct StdInt<1, 0> { typedef int8_t Type; };
|
57
|
+
template<> struct StdInt<1, 1> { typedef uint8_t Type; };
|
58
|
+
template<> struct StdInt<2, 0> { typedef int16_t Type; };
|
59
|
+
template<> struct StdInt<2, 1> { typedef uint16_t Type; };
|
60
|
+
template<> struct StdInt<4, 0> { typedef int32_t Type; };
|
61
|
+
template<> struct StdInt<4, 1> { typedef uint32_t Type; };
|
62
|
+
template<> struct StdInt<8, 0> { typedef int64_t Type; };
|
63
|
+
template<> struct StdInt<8, 1> { typedef uint64_t Type; };
|
64
|
+
|
65
|
+
template<typename T, int Unsigned = std::is_unsigned<T>::value>
|
66
|
+
struct Int32Or64 : public StdInt<sizeof(T) <= 4 ? size_t(4) : sizeof(T), Unsigned> {};
|
67
|
+
}
|
68
|
+
//! \endcond
|
69
|
+
|
70
|
+
template<typename T>
|
71
|
+
static constexpr bool isUnsigned() noexcept { return std::is_unsigned<T>::value; }
|
72
|
+
|
73
|
+
//! Casts an integer `x` to either `int32_t` or `int64_t` depending on `T`.
|
74
|
+
template<typename T>
|
75
|
+
static constexpr typename Internal::Int32Or64<T, 0>::Type asInt(const T& x) noexcept {
|
76
|
+
return (typename Internal::Int32Or64<T, 0>::Type)x;
|
77
|
+
}
|
78
|
+
|
79
|
+
//! Casts an integer `x` to either `uint32_t` or `uint64_t` depending on `T`.
|
80
|
+
template<typename T>
|
81
|
+
static constexpr typename Internal::Int32Or64<T, 1>::Type asUInt(const T& x) noexcept {
|
82
|
+
return (typename Internal::Int32Or64<T, 1>::Type)x;
|
83
|
+
}
|
84
|
+
|
85
|
+
//! Casts an integer `x` to either `int32_t`, uint32_t`, `int64_t`, or `uint64_t` depending on `T`.
|
86
|
+
template<typename T>
|
87
|
+
static constexpr typename Internal::Int32Or64<T>::Type asNormalized(const T& x) noexcept {
|
88
|
+
return (typename Internal::Int32Or64<T>::Type)x;
|
89
|
+
}
|
90
|
+
|
91
|
+
//! Casts an integer `x` to the same type as defined by `<stdint.h>`.
|
92
|
+
template<typename T>
|
93
|
+
static constexpr typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type asStdInt(const T& x) noexcept {
|
94
|
+
return (typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type)x;
|
95
|
+
}
|
96
|
+
|
97
|
+
//! A helper class that can be used to iterate over enum values.
|
98
|
+
template<typename T, T from = (T)0, T to = T::kMaxValue>
|
99
|
+
struct EnumValues {
|
100
|
+
typedef typename std::underlying_type<T>::type ValueType;
|
101
|
+
|
102
|
+
struct Iterator {
|
103
|
+
ValueType value;
|
104
|
+
|
105
|
+
inline T operator*() const { return (T)value; }
|
106
|
+
inline void operator++() { ++value; }
|
107
|
+
|
108
|
+
inline bool operator==(const Iterator& other) const noexcept { return value == other.value; }
|
109
|
+
inline bool operator!=(const Iterator& other) const noexcept { return value != other.value; }
|
110
|
+
};
|
111
|
+
|
112
|
+
inline Iterator begin() const noexcept { return Iterator{ValueType(from)}; }
|
113
|
+
inline Iterator end() const noexcept { return Iterator{ValueType(to) + 1}; }
|
114
|
+
};
|
115
|
+
|
116
|
+
// Support - BitCast
|
117
|
+
// =================
|
118
|
+
|
119
|
+
//! \cond
|
120
|
+
namespace Internal {
|
121
|
+
template<typename DstT, typename SrcT>
|
122
|
+
union BitCastUnion {
|
123
|
+
inline BitCastUnion(SrcT src) noexcept : src(src) {}
|
124
|
+
SrcT src;
|
125
|
+
DstT dst;
|
126
|
+
};
|
127
|
+
}
|
128
|
+
//! \endcond
|
129
|
+
|
130
|
+
//! Bit-casts from `Src` type to `Dst` type.
|
131
|
+
//!
|
132
|
+
//! Useful to bit-cast between integers and floating points.
|
133
|
+
template<typename Dst, typename Src>
|
134
|
+
static inline Dst bitCast(const Src& x) noexcept { return Internal::BitCastUnion<Dst, Src>(x).dst; }
|
135
|
+
|
136
|
+
// Support - BitOps
|
137
|
+
// ================
|
138
|
+
|
139
|
+
//! Storage used to store a pack of bits (should by compatible with a machine word).
|
140
|
+
typedef Internal::StdInt<sizeof(uintptr_t), 1>::Type BitWord;
|
141
|
+
|
142
|
+
template<typename T>
|
143
|
+
static constexpr uint32_t bitSizeOf() noexcept { return uint32_t(sizeof(T) * 8u); }
|
144
|
+
|
145
|
+
//! Number of bits stored in a single `BitWord`.
|
146
|
+
static constexpr uint32_t kBitWordSizeInBits = bitSizeOf<BitWord>();
|
147
|
+
|
148
|
+
//! Returns `0 - x` in a safe way (no undefined behavior), works for unsigned numbers as well.
|
149
|
+
template<typename T>
|
150
|
+
static constexpr T neg(const T& x) noexcept {
|
151
|
+
typedef typename std::make_unsigned<T>::type U;
|
152
|
+
return T(U(0) - U(x));
|
153
|
+
}
|
154
|
+
|
155
|
+
template<typename T>
|
156
|
+
static constexpr T allOnes() noexcept { return neg<T>(T(1)); }
|
157
|
+
|
158
|
+
//! Returns `x << y` (shift left logical) by explicitly casting `x` to an unsigned type and back.
|
159
|
+
template<typename X, typename Y>
|
160
|
+
static constexpr X shl(const X& x, const Y& y) noexcept {
|
161
|
+
typedef typename std::make_unsigned<X>::type U;
|
162
|
+
return X(U(x) << y);
|
163
|
+
}
|
164
|
+
|
165
|
+
//! Returns `x >> y` (shift right logical) by explicitly casting `x` to an unsigned type and back.
|
166
|
+
template<typename X, typename Y>
|
167
|
+
static constexpr X shr(const X& x, const Y& y) noexcept {
|
168
|
+
typedef typename std::make_unsigned<X>::type U;
|
169
|
+
return X(U(x) >> y);
|
170
|
+
}
|
171
|
+
|
172
|
+
//! Returns `x >> y` (shift right arithmetic) by explicitly casting `x` to a signed type and back.
|
173
|
+
template<typename X, typename Y>
|
174
|
+
static constexpr X sar(const X& x, const Y& y) noexcept {
|
175
|
+
typedef typename std::make_signed<X>::type S;
|
176
|
+
return X(S(x) >> y);
|
177
|
+
}
|
178
|
+
|
179
|
+
template<typename X, typename Y>
|
180
|
+
static constexpr X ror(const X& x, const Y& y) noexcept {
|
181
|
+
typedef typename std::make_unsigned<X>::type U;
|
182
|
+
return X((U(x) >> y) | (U(x) << (bitSizeOf<U>() - y)));
|
183
|
+
}
|
184
|
+
|
185
|
+
//! Returns `x | (x >> y)` - helper used by some bit manipulation helpers.
|
186
|
+
template<typename X, typename Y>
|
187
|
+
static constexpr X or_shr(const X& x, const Y& y) noexcept { return X(x | shr(x, y)); }
|
188
|
+
|
189
|
+
//! Returns `x & -x` - extracts lowest set isolated bit (like BLSI instruction).
|
190
|
+
template<typename T>
|
191
|
+
static constexpr T blsi(T x) noexcept {
|
192
|
+
typedef typename std::make_unsigned<T>::type U;
|
193
|
+
return T(U(x) & neg(U(x)));
|
194
|
+
}
|
195
|
+
|
196
|
+
//! Tests whether the given value `x` has `n`th bit set.
|
197
|
+
template<typename T, typename IndexT>
|
198
|
+
static constexpr bool bitTest(T x, IndexT n) noexcept {
|
199
|
+
typedef typename std::make_unsigned<T>::type U;
|
200
|
+
return (U(x) & (U(1) << asStdInt(n))) != 0;
|
201
|
+
}
|
202
|
+
|
203
|
+
// Tests whether the given `value` is a consecutive mask of bits that starts at
|
204
|
+
// the least significant bit.
|
205
|
+
template<typename T>
|
206
|
+
static inline constexpr bool isLsbMask(const T& value) {
|
207
|
+
typedef typename std::make_unsigned<T>::type U;
|
208
|
+
return value && ((U(value) + 1u) & U(value)) == 0;
|
209
|
+
}
|
210
|
+
|
211
|
+
// Tests whether the given value contains at least one bit or whether it's a
|
212
|
+
// bit-mask of consecutive bits.
|
213
|
+
//
|
214
|
+
// This function is similar to \ref isLsbMask(), but the mask doesn't have to
|
215
|
+
// start at a least significant bit.
|
216
|
+
template<typename T>
|
217
|
+
static inline constexpr bool isConsecutiveMask(const T& value) {
|
218
|
+
typedef typename std::make_unsigned<T>::type U;
|
219
|
+
return value && isLsbMask((U(value) - 1u) | U(value));
|
220
|
+
}
|
221
|
+
|
222
|
+
//! Generates a trailing bit-mask that has `n` least significant (trailing) bits set.
|
223
|
+
template<typename T, typename CountT>
|
224
|
+
static constexpr T lsbMask(const CountT& n) noexcept {
|
225
|
+
typedef typename std::make_unsigned<T>::type U;
|
226
|
+
return (sizeof(U) < sizeof(uintptr_t))
|
227
|
+
// Prevent undefined behavior by using a larger type than T.
|
228
|
+
? T(U((uintptr_t(1) << n) - uintptr_t(1)))
|
229
|
+
// Prevent undefined behavior by checking `n` before shift.
|
230
|
+
: n ? T(shr(allOnes<T>(), bitSizeOf<T>() - size_t(n))) : T(0);
|
231
|
+
}
|
232
|
+
|
233
|
+
//! Generats a leading bit-mask that has `n` most significant (leading) bits set.
|
234
|
+
template<typename T, typename CountT>
|
235
|
+
static constexpr T msbMask(const CountT& n) noexcept {
|
236
|
+
typedef typename std::make_unsigned<T>::type U;
|
237
|
+
return (sizeof(U) < sizeof(uintptr_t))
|
238
|
+
// Prevent undefined behavior by using a larger type than T.
|
239
|
+
? T(allOnes<uintptr_t>() >> (bitSizeOf<uintptr_t>() - n))
|
240
|
+
// Prevent undefined behavior by performing `n & (nBits - 1)` so it's always within the range.
|
241
|
+
: T(sar(U(n != 0) << (bitSizeOf<U>() - 1), n ? uint32_t(n - 1) : uint32_t(0)));
|
242
|
+
}
|
243
|
+
|
244
|
+
//! Returns a bit-mask that has `x` bit set.
|
245
|
+
template<typename Index>
|
246
|
+
static constexpr uint32_t bitMask(const Index& x) noexcept { return (1u << asUInt(x)); }
|
247
|
+
|
248
|
+
//! Returns a bit-mask that has `x` bit set (multiple arguments).
|
249
|
+
template<typename Index, typename... Args>
|
250
|
+
static constexpr uint32_t bitMask(const Index& x, Args... args) noexcept { return bitMask(x) | bitMask(args...); }
|
251
|
+
|
252
|
+
//! Converts a boolean value `b` to zero or full mask (all bits set).
|
253
|
+
template<typename DstT, typename SrcT>
|
254
|
+
static constexpr DstT bitMaskFromBool(SrcT b) noexcept {
|
255
|
+
typedef typename std::make_unsigned<DstT>::type U;
|
256
|
+
return DstT(U(0) - U(b));
|
257
|
+
}
|
258
|
+
|
259
|
+
//! Tests whether `a & b` is non-zero.
|
260
|
+
template<typename A, typename B>
|
261
|
+
static inline constexpr bool test(A a, B b) noexcept { return (asUInt(a) & asUInt(b)) != 0; }
|
262
|
+
|
263
|
+
//! \cond
|
264
|
+
namespace Internal {
|
265
|
+
// Fills all trailing bits right from the first most significant bit set.
|
266
|
+
static constexpr uint8_t fillTrailingBitsImpl(uint8_t x) noexcept { return or_shr(or_shr(or_shr(x, 1), 2), 4); }
|
267
|
+
// Fills all trailing bits right from the first most significant bit set.
|
268
|
+
static constexpr uint16_t fillTrailingBitsImpl(uint16_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8); }
|
269
|
+
// Fills all trailing bits right from the first most significant bit set.
|
270
|
+
static constexpr uint32_t fillTrailingBitsImpl(uint32_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8), 16); }
|
271
|
+
// Fills all trailing bits right from the first most significant bit set.
|
272
|
+
static constexpr uint64_t fillTrailingBitsImpl(uint64_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8), 16), 32); }
|
273
|
+
}
|
274
|
+
//! \endcond
|
275
|
+
|
276
|
+
// Fills all trailing bits right from the first most significant bit set.
|
277
|
+
template<typename T>
|
278
|
+
static constexpr T fillTrailingBits(const T& x) noexcept {
|
279
|
+
typedef typename std::make_unsigned<T>::type U;
|
280
|
+
return T(Internal::fillTrailingBitsImpl(U(x)));
|
281
|
+
}
|
282
|
+
|
283
|
+
// Support - Count Leading/Trailing Zeros
|
284
|
+
// ======================================
|
285
|
+
|
286
|
+
//! \cond
|
287
|
+
namespace Internal {
|
288
|
+
namespace {
|
289
|
+
|
290
|
+
template<typename T>
|
291
|
+
struct BitScanData { T x; uint32_t n; };
|
292
|
+
|
293
|
+
template<typename T, uint32_t N>
|
294
|
+
struct BitScanCalc {
|
295
|
+
static constexpr BitScanData<T> advanceLeft(const BitScanData<T>& data, uint32_t n) noexcept {
|
296
|
+
return BitScanData<T> { data.x << n, data.n + n };
|
297
|
+
}
|
298
|
+
|
299
|
+
static constexpr BitScanData<T> advanceRight(const BitScanData<T>& data, uint32_t n) noexcept {
|
300
|
+
return BitScanData<T> { data.x >> n, data.n + n };
|
301
|
+
}
|
302
|
+
|
303
|
+
static constexpr BitScanData<T> clz(const BitScanData<T>& data) noexcept {
|
304
|
+
return BitScanCalc<T, N / 2>::clz(advanceLeft(data, data.x & (allOnes<T>() << (bitSizeOf<T>() - N)) ? uint32_t(0) : N));
|
305
|
+
}
|
306
|
+
|
307
|
+
static constexpr BitScanData<T> ctz(const BitScanData<T>& data) noexcept {
|
308
|
+
return BitScanCalc<T, N / 2>::ctz(advanceRight(data, data.x & (allOnes<T>() >> (bitSizeOf<T>() - N)) ? uint32_t(0) : N));
|
309
|
+
}
|
310
|
+
};
|
311
|
+
|
312
|
+
template<typename T>
|
313
|
+
struct BitScanCalc<T, 0> {
|
314
|
+
static constexpr BitScanData<T> clz(const BitScanData<T>& ctx) noexcept {
|
315
|
+
return BitScanData<T> { 0, ctx.n - uint32_t(ctx.x >> (bitSizeOf<T>() - 1)) };
|
316
|
+
}
|
317
|
+
|
318
|
+
static constexpr BitScanData<T> ctz(const BitScanData<T>& ctx) noexcept {
|
319
|
+
return BitScanData<T> { 0, ctx.n - uint32_t(ctx.x & 0x1) };
|
320
|
+
}
|
321
|
+
};
|
322
|
+
|
323
|
+
template<typename T>
|
324
|
+
constexpr uint32_t clzFallback(const T& x) noexcept {
|
325
|
+
return BitScanCalc<T, bitSizeOf<T>() / 2u>::clz(BitScanData<T>{x, 1}).n;
|
326
|
+
}
|
327
|
+
|
328
|
+
template<typename T>
|
329
|
+
constexpr uint32_t ctzFallback(const T& x) noexcept {
|
330
|
+
return BitScanCalc<T, bitSizeOf<T>() / 2u>::ctz(BitScanData<T>{x, 1}).n;
|
331
|
+
}
|
332
|
+
|
333
|
+
template<typename T> inline uint32_t clzImpl(const T& x) noexcept { return clzFallback(asUInt(x)); }
|
334
|
+
template<typename T> inline uint32_t ctzImpl(const T& x) noexcept { return ctzFallback(asUInt(x)); }
|
335
|
+
|
336
|
+
#if !defined(ASMJIT_NO_INTRINSICS)
|
337
|
+
# if defined(__GNUC__)
|
338
|
+
template<> inline uint32_t clzImpl(const uint32_t& x) noexcept { return uint32_t(__builtin_clz(x)); }
|
339
|
+
template<> inline uint32_t clzImpl(const uint64_t& x) noexcept { return uint32_t(__builtin_clzll(x)); }
|
340
|
+
template<> inline uint32_t ctzImpl(const uint32_t& x) noexcept { return uint32_t(__builtin_ctz(x)); }
|
341
|
+
template<> inline uint32_t ctzImpl(const uint64_t& x) noexcept { return uint32_t(__builtin_ctzll(x)); }
|
342
|
+
# elif defined(_MSC_VER)
|
343
|
+
template<> inline uint32_t clzImpl(const uint32_t& x) noexcept { unsigned long i; _BitScanReverse(&i, x); return uint32_t(i ^ 31); }
|
344
|
+
template<> inline uint32_t ctzImpl(const uint32_t& x) noexcept { unsigned long i; _BitScanForward(&i, x); return uint32_t(i); }
|
345
|
+
# if ASMJIT_ARCH_X86 == 64 || ASMJIT_ARCH_ARM == 64
|
346
|
+
template<> inline uint32_t clzImpl(const uint64_t& x) noexcept { unsigned long i; _BitScanReverse64(&i, x); return uint32_t(i ^ 63); }
|
347
|
+
template<> inline uint32_t ctzImpl(const uint64_t& x) noexcept { unsigned long i; _BitScanForward64(&i, x); return uint32_t(i); }
|
348
|
+
# endif
|
349
|
+
# endif
|
350
|
+
#endif
|
351
|
+
|
352
|
+
} // {anonymous}
|
353
|
+
} // {Internal}
|
354
|
+
//! \endcond
|
355
|
+
|
356
|
+
//! Count leading zeros in `x` (returns a position of a first bit set in `x`).
|
357
|
+
//!
|
358
|
+
//! \note The input MUST NOT be zero, otherwise the result is undefined.
|
359
|
+
template<typename T>
|
360
|
+
static inline uint32_t clz(T x) noexcept { return Internal::clzImpl(asUInt(x)); }
|
361
|
+
|
362
|
+
//! Count trailing zeros in `x` (returns a position of a first bit set in `x`).
|
363
|
+
//!
|
364
|
+
//! \note The input MUST NOT be zero, otherwise the result is undefined.
|
365
|
+
template<typename T>
|
366
|
+
static inline uint32_t ctz(T x) noexcept { return Internal::ctzImpl(asUInt(x)); }
|
367
|
+
|
368
|
+
template<uint64_t kInput>
|
369
|
+
struct ConstCTZ {
|
370
|
+
static constexpr uint32_t value =
|
371
|
+
(kInput & (uint64_t(1) << 0)) ? 0 :
|
372
|
+
(kInput & (uint64_t(1) << 1)) ? 1 :
|
373
|
+
(kInput & (uint64_t(1) << 2)) ? 2 :
|
374
|
+
(kInput & (uint64_t(1) << 3)) ? 3 :
|
375
|
+
(kInput & (uint64_t(1) << 4)) ? 4 :
|
376
|
+
(kInput & (uint64_t(1) << 5)) ? 5 :
|
377
|
+
(kInput & (uint64_t(1) << 6)) ? 6 :
|
378
|
+
(kInput & (uint64_t(1) << 7)) ? 7 :
|
379
|
+
(kInput & (uint64_t(1) << 8)) ? 8 :
|
380
|
+
(kInput & (uint64_t(1) << 9)) ? 9 :
|
381
|
+
(kInput & (uint64_t(1) << 10)) ? 10 :
|
382
|
+
(kInput & (uint64_t(1) << 11)) ? 11 :
|
383
|
+
(kInput & (uint64_t(1) << 12)) ? 12 :
|
384
|
+
(kInput & (uint64_t(1) << 13)) ? 13 :
|
385
|
+
(kInput & (uint64_t(1) << 14)) ? 14 :
|
386
|
+
(kInput & (uint64_t(1) << 15)) ? 15 :
|
387
|
+
(kInput & (uint64_t(1) << 16)) ? 16 :
|
388
|
+
(kInput & (uint64_t(1) << 17)) ? 17 :
|
389
|
+
(kInput & (uint64_t(1) << 18)) ? 18 :
|
390
|
+
(kInput & (uint64_t(1) << 19)) ? 19 :
|
391
|
+
(kInput & (uint64_t(1) << 20)) ? 20 :
|
392
|
+
(kInput & (uint64_t(1) << 21)) ? 21 :
|
393
|
+
(kInput & (uint64_t(1) << 22)) ? 22 :
|
394
|
+
(kInput & (uint64_t(1) << 23)) ? 23 :
|
395
|
+
(kInput & (uint64_t(1) << 24)) ? 24 :
|
396
|
+
(kInput & (uint64_t(1) << 25)) ? 25 :
|
397
|
+
(kInput & (uint64_t(1) << 26)) ? 26 :
|
398
|
+
(kInput & (uint64_t(1) << 27)) ? 27 :
|
399
|
+
(kInput & (uint64_t(1) << 28)) ? 28 :
|
400
|
+
(kInput & (uint64_t(1) << 29)) ? 29 :
|
401
|
+
(kInput & (uint64_t(1) << 30)) ? 30 :
|
402
|
+
(kInput & (uint64_t(1) << 31)) ? 31 :
|
403
|
+
(kInput & (uint64_t(1) << 32)) ? 32 :
|
404
|
+
(kInput & (uint64_t(1) << 33)) ? 33 :
|
405
|
+
(kInput & (uint64_t(1) << 34)) ? 34 :
|
406
|
+
(kInput & (uint64_t(1) << 35)) ? 35 :
|
407
|
+
(kInput & (uint64_t(1) << 36)) ? 36 :
|
408
|
+
(kInput & (uint64_t(1) << 37)) ? 37 :
|
409
|
+
(kInput & (uint64_t(1) << 38)) ? 38 :
|
410
|
+
(kInput & (uint64_t(1) << 39)) ? 39 :
|
411
|
+
(kInput & (uint64_t(1) << 40)) ? 40 :
|
412
|
+
(kInput & (uint64_t(1) << 41)) ? 41 :
|
413
|
+
(kInput & (uint64_t(1) << 42)) ? 42 :
|
414
|
+
(kInput & (uint64_t(1) << 43)) ? 43 :
|
415
|
+
(kInput & (uint64_t(1) << 44)) ? 44 :
|
416
|
+
(kInput & (uint64_t(1) << 45)) ? 45 :
|
417
|
+
(kInput & (uint64_t(1) << 46)) ? 46 :
|
418
|
+
(kInput & (uint64_t(1) << 47)) ? 47 :
|
419
|
+
(kInput & (uint64_t(1) << 48)) ? 48 :
|
420
|
+
(kInput & (uint64_t(1) << 49)) ? 49 :
|
421
|
+
(kInput & (uint64_t(1) << 50)) ? 50 :
|
422
|
+
(kInput & (uint64_t(1) << 51)) ? 51 :
|
423
|
+
(kInput & (uint64_t(1) << 52)) ? 52 :
|
424
|
+
(kInput & (uint64_t(1) << 53)) ? 53 :
|
425
|
+
(kInput & (uint64_t(1) << 54)) ? 54 :
|
426
|
+
(kInput & (uint64_t(1) << 55)) ? 55 :
|
427
|
+
(kInput & (uint64_t(1) << 56)) ? 56 :
|
428
|
+
(kInput & (uint64_t(1) << 57)) ? 57 :
|
429
|
+
(kInput & (uint64_t(1) << 58)) ? 58 :
|
430
|
+
(kInput & (uint64_t(1) << 59)) ? 59 :
|
431
|
+
(kInput & (uint64_t(1) << 60)) ? 60 :
|
432
|
+
(kInput & (uint64_t(1) << 61)) ? 61 :
|
433
|
+
(kInput & (uint64_t(1) << 62)) ? 62 :
|
434
|
+
(kInput & (uint64_t(1) << 63)) ? 63 : 64;
|
435
|
+
};
|
436
|
+
|
437
|
+
// Support - PopCnt
|
438
|
+
// ================
|
439
|
+
|
440
|
+
// Based on the following resource:
|
441
|
+
// http://graphics.stanford.edu/~seander/bithacks.html
|
442
|
+
//
|
443
|
+
// Alternatively, for a very small number of bits in `x`:
|
444
|
+
// uint32_t n = 0;
|
445
|
+
// while (x) {
|
446
|
+
// x &= x - 1;
|
447
|
+
// n++;
|
448
|
+
// }
|
449
|
+
// return n;
|
450
|
+
|
451
|
+
//! \cond
|
452
|
+
namespace Internal {
|
453
|
+
static inline uint32_t constPopcntImpl(uint32_t x) noexcept {
|
454
|
+
x = x - ((x >> 1) & 0x55555555u);
|
455
|
+
x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
|
456
|
+
return (((x + (x >> 4)) & 0x0F0F0F0Fu) * 0x01010101u) >> 24;
|
457
|
+
}
|
458
|
+
|
459
|
+
static inline uint32_t constPopcntImpl(uint64_t x) noexcept {
|
460
|
+
if (ASMJIT_ARCH_BITS >= 64) {
|
461
|
+
x = x - ((x >> 1) & 0x5555555555555555u);
|
462
|
+
x = (x & 0x3333333333333333u) + ((x >> 2) & 0x3333333333333333u);
|
463
|
+
return uint32_t((((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0Fu) * 0x0101010101010101u) >> 56);
|
464
|
+
}
|
465
|
+
else {
|
466
|
+
return constPopcntImpl(uint32_t(x >> 32)) +
|
467
|
+
constPopcntImpl(uint32_t(x & 0xFFFFFFFFu));
|
468
|
+
}
|
469
|
+
}
|
470
|
+
|
471
|
+
static inline uint32_t popcntImpl(uint32_t x) noexcept {
|
472
|
+
#if defined(__GNUC__)
|
473
|
+
return uint32_t(__builtin_popcount(x));
|
474
|
+
#else
|
475
|
+
return constPopcntImpl(asUInt(x));
|
476
|
+
#endif
|
477
|
+
}
|
478
|
+
|
479
|
+
static inline uint32_t popcntImpl(uint64_t x) noexcept {
|
480
|
+
#if defined(__GNUC__)
|
481
|
+
return uint32_t(__builtin_popcountll(x));
|
482
|
+
#else
|
483
|
+
return constPopcntImpl(asUInt(x));
|
484
|
+
#endif
|
485
|
+
}
|
486
|
+
}
|
487
|
+
//! \endcond
|
488
|
+
|
489
|
+
//! Calculates count of bits in `x`.
|
490
|
+
template<typename T>
|
491
|
+
static inline uint32_t popcnt(T x) noexcept { return Internal::popcntImpl(asUInt(x)); }
|
492
|
+
|
493
|
+
//! Calculates count of bits in `x` (useful in constant expressions).
|
494
|
+
template<typename T>
|
495
|
+
static inline uint32_t constPopcnt(T x) noexcept { return Internal::constPopcntImpl(asUInt(x)); }
|
496
|
+
|
497
|
+
// Support - Min/Max
|
498
|
+
// =================
|
499
|
+
|
500
|
+
// NOTE: These are constexpr `min()` and `max()` implementations that are not
|
501
|
+
// exactly the same as `std::min()` and `std::max()`. The return value is not
|
502
|
+
// a reference to `a` or `b` but it's a new value instead.
|
503
|
+
|
504
|
+
template<typename T>
|
505
|
+
static constexpr T min(const T& a, const T& b) noexcept { return b < a ? b : a; }
|
506
|
+
|
507
|
+
template<typename T, typename... Args>
|
508
|
+
static constexpr T min(const T& a, const T& b, Args&&... args) noexcept { return min(min(a, b), std::forward<Args>(args)...); }
|
509
|
+
|
510
|
+
template<typename T>
|
511
|
+
static constexpr T max(const T& a, const T& b) noexcept { return a < b ? b : a; }
|
512
|
+
|
513
|
+
template<typename T, typename... Args>
|
514
|
+
static constexpr T max(const T& a, const T& b, Args&&... args) noexcept { return max(max(a, b), std::forward<Args>(args)...); }
|
515
|
+
|
516
|
+
// Support - Immediate Helpers
|
517
|
+
// ===========================
|
518
|
+
|
519
|
+
namespace Internal {
|
520
|
+
template<typename T, bool IsFloat>
|
521
|
+
struct ImmConv {
|
522
|
+
static inline int64_t fromT(const T& x) noexcept { return int64_t(x); }
|
523
|
+
static inline T toT(int64_t x) noexcept { return T(uint64_t(x) & Support::allOnes<typename std::make_unsigned<T>::type>()); }
|
524
|
+
};
|
525
|
+
|
526
|
+
template<typename T>
|
527
|
+
struct ImmConv<T, true> {
|
528
|
+
static inline int64_t fromT(const T& x) noexcept { return int64_t(bitCast<int64_t>(double(x))); }
|
529
|
+
static inline T toT(int64_t x) noexcept { return T(bitCast<double>(x)); }
|
530
|
+
};
|
531
|
+
}
|
532
|
+
|
533
|
+
template<typename T>
|
534
|
+
static inline int64_t immediateFromT(const T& x) noexcept { return Internal::ImmConv<T, std::is_floating_point<T>::value>::fromT(x); }
|
535
|
+
|
536
|
+
template<typename T>
|
537
|
+
static inline T immediateToT(int64_t x) noexcept { return Internal::ImmConv<T, std::is_floating_point<T>::value>::toT(x); }
|
538
|
+
|
539
|
+
// Support - Overflow Arithmetic
|
540
|
+
// =============================
|
541
|
+
|
542
|
+
//! \cond
|
543
|
+
namespace Internal {
|
544
|
+
template<typename T>
|
545
|
+
inline T addOverflowFallback(T x, T y, FastUInt8* of) noexcept {
|
546
|
+
typedef typename std::make_unsigned<T>::type U;
|
547
|
+
|
548
|
+
U result = U(x) + U(y);
|
549
|
+
*of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0));
|
550
|
+
return T(result);
|
551
|
+
}
|
552
|
+
|
553
|
+
template<typename T>
|
554
|
+
inline T subOverflowFallback(T x, T y, FastUInt8* of) noexcept {
|
555
|
+
typedef typename std::make_unsigned<T>::type U;
|
556
|
+
|
557
|
+
U result = U(x) - U(y);
|
558
|
+
*of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0));
|
559
|
+
return T(result);
|
560
|
+
}
|
561
|
+
|
562
|
+
template<typename T>
|
563
|
+
inline T mulOverflowFallback(T x, T y, FastUInt8* of) noexcept {
|
564
|
+
typedef typename Internal::StdInt<sizeof(T) * 2, isUnsigned<T>()>::Type I;
|
565
|
+
typedef typename std::make_unsigned<I>::type U;
|
566
|
+
|
567
|
+
U mask = allOnes<U>();
|
568
|
+
if (std::is_signed<T>::value) {
|
569
|
+
U prod = U(I(x)) * U(I(y));
|
570
|
+
*of = FastUInt8(*of | FastUInt8(I(prod) < I(std::numeric_limits<T>::lowest()) || I(prod) > I(std::numeric_limits<T>::max())));
|
571
|
+
return T(I(prod & mask));
|
572
|
+
}
|
573
|
+
else {
|
574
|
+
U prod = U(x) * U(y);
|
575
|
+
*of = FastUInt8(*of | FastUInt8((prod & ~mask) != 0));
|
576
|
+
return T(prod & mask);
|
577
|
+
}
|
578
|
+
}
|
579
|
+
|
580
|
+
template<>
|
581
|
+
inline int64_t mulOverflowFallback(int64_t x, int64_t y, FastUInt8* of) noexcept {
|
582
|
+
int64_t result = int64_t(uint64_t(x) * uint64_t(y));
|
583
|
+
*of = FastUInt8(*of | FastUInt8(x && (result / x != y)));
|
584
|
+
return result;
|
585
|
+
}
|
586
|
+
|
587
|
+
template<>
|
588
|
+
inline uint64_t mulOverflowFallback(uint64_t x, uint64_t y, FastUInt8* of) noexcept {
|
589
|
+
uint64_t result = x * y;
|
590
|
+
*of = FastUInt8(*of | FastUInt8(y != 0 && allOnes<uint64_t>() / y < x));
|
591
|
+
return result;
|
592
|
+
}
|
593
|
+
|
594
|
+
// These can be specialized.
|
595
|
+
template<typename T> inline T addOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return addOverflowFallback(x, y, of); }
|
596
|
+
template<typename T> inline T subOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return subOverflowFallback(x, y, of); }
|
597
|
+
template<typename T> inline T mulOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return mulOverflowFallback(x, y, of); }
|
598
|
+
|
599
|
+
#if defined(__GNUC__) && !defined(ASMJIT_NO_INTRINSICS)
|
600
|
+
#if defined(__clang__) || __GNUC__ >= 5
|
601
|
+
#define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, RESULT_T, BUILTIN) \
|
602
|
+
template<> \
|
603
|
+
inline T FUNC(const T& x, const T& y, FastUInt8* of) noexcept { \
|
604
|
+
RESULT_T result; \
|
605
|
+
*of = FastUInt8(*of | (BUILTIN((RESULT_T)x, (RESULT_T)y, &result))); \
|
606
|
+
return T(result); \
|
607
|
+
}
|
608
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int32_t , int , __builtin_sadd_overflow )
|
609
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , __builtin_uadd_overflow )
|
610
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int64_t , long long , __builtin_saddll_overflow)
|
611
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned long long, __builtin_uaddll_overflow)
|
612
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int32_t , int , __builtin_ssub_overflow )
|
613
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , __builtin_usub_overflow )
|
614
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int64_t , long long , __builtin_ssubll_overflow)
|
615
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned long long, __builtin_usubll_overflow)
|
616
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int32_t , int , __builtin_smul_overflow )
|
617
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint32_t, unsigned int , __builtin_umul_overflow )
|
618
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int64_t , long long , __builtin_smulll_overflow)
|
619
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint64_t, unsigned long long, __builtin_umulll_overflow)
|
620
|
+
#undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE
|
621
|
+
#endif
|
622
|
+
#endif
|
623
|
+
|
624
|
+
// There is a bug in MSVC that makes these specializations unusable, maybe in the future...
|
625
|
+
#if defined(_MSC_VER) && 0
|
626
|
+
#define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, ALT_T, BUILTIN) \
|
627
|
+
template<> \
|
628
|
+
inline T FUNC(T x, T y, FastUInt8* of) noexcept { \
|
629
|
+
ALT_T result; \
|
630
|
+
*of = FastUInt8(*of | BUILTIN(0, (ALT_T)x, (ALT_T)y, &result)); \
|
631
|
+
return T(result); \
|
632
|
+
}
|
633
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , _addcarry_u32 )
|
634
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , _subborrow_u32)
|
635
|
+
#if ARCH_BITS >= 64
|
636
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned __int64 , _addcarry_u64 )
|
637
|
+
ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned __int64 , _subborrow_u64)
|
638
|
+
#endif
|
639
|
+
#undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE
|
640
|
+
#endif
|
641
|
+
} // {Internal}
|
642
|
+
//! \endcond
|
643
|
+
|
644
|
+
template<typename T>
|
645
|
+
static inline T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(asStdInt(x), asStdInt(y), of)); }
|
646
|
+
|
647
|
+
template<typename T>
|
648
|
+
static inline T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(asStdInt(x), asStdInt(y), of)); }
|
649
|
+
|
650
|
+
template<typename T>
|
651
|
+
static inline T mulOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::mulOverflowImpl(asStdInt(x), asStdInt(y), of)); }
|
652
|
+
|
653
|
+
// Support - Alignment
|
654
|
+
// ===================
|
655
|
+
|
656
|
+
template<typename X, typename Y>
|
657
|
+
static constexpr bool isAligned(X base, Y alignment) noexcept {
|
658
|
+
typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
|
659
|
+
return ((U)base % (U)alignment) == 0;
|
660
|
+
}
|
661
|
+
|
662
|
+
//! Tests whether the `x` is a power of two (only one bit is set).
|
663
|
+
template<typename T>
|
664
|
+
static constexpr bool isPowerOf2(T x) noexcept {
|
665
|
+
typedef typename std::make_unsigned<T>::type U;
|
666
|
+
return x && !(U(x) & (U(x) - U(1)));
|
667
|
+
}
|
668
|
+
|
669
|
+
template<typename X, typename Y>
|
670
|
+
static constexpr X alignUp(X x, Y alignment) noexcept {
|
671
|
+
typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
|
672
|
+
return (X)( ((U)x + ((U)(alignment) - 1u)) & ~((U)(alignment) - 1u) );
|
673
|
+
}
|
674
|
+
|
675
|
+
template<typename T>
|
676
|
+
static constexpr T alignUpPowerOf2(T x) noexcept {
|
677
|
+
typedef typename Internal::StdInt<sizeof(T), 1>::Type U;
|
678
|
+
return (T)(fillTrailingBits(U(x) - 1u) + 1u);
|
679
|
+
}
|
680
|
+
|
681
|
+
//! Returns either zero or a positive difference between `base` and `base` when
|
682
|
+
//! aligned to `alignment`.
|
683
|
+
template<typename X, typename Y>
|
684
|
+
static constexpr typename Internal::StdInt<sizeof(X), 1>::Type alignUpDiff(X base, Y alignment) noexcept {
|
685
|
+
typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
|
686
|
+
return alignUp(U(base), alignment) - U(base);
|
687
|
+
}
|
688
|
+
|
689
|
+
template<typename X, typename Y>
|
690
|
+
static constexpr X alignDown(X x, Y alignment) noexcept {
|
691
|
+
typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
|
692
|
+
return (X)( (U)x & ~((U)(alignment) - 1u) );
|
693
|
+
}
|
694
|
+
|
695
|
+
// Support - NumGranularized
|
696
|
+
// =========================
|
697
|
+
|
698
|
+
//! Calculates the number of elements that would be required if `base` is
|
699
|
+
//! granularized by `granularity`. This function can be used to calculate
|
700
|
+
//! the number of BitWords to represent N bits, for example.
|
701
|
+
template<typename X, typename Y>
|
702
|
+
static constexpr X numGranularized(X base, Y granularity) noexcept {
|
703
|
+
typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
|
704
|
+
return X((U(base) + U(granularity) - 1) / U(granularity));
|
705
|
+
}
|
706
|
+
|
707
|
+
// Support - IsBetween
|
708
|
+
// ===================
|
709
|
+
|
710
|
+
//! Checks whether `x` is greater than or equal to `a` and lesser than or equal to `b`.
|
711
|
+
template<typename T>
|
712
|
+
static constexpr bool isBetween(const T& x, const T& a, const T& b) noexcept {
|
713
|
+
return x >= a && x <= b;
|
714
|
+
}
|
715
|
+
|
716
|
+
// Support - IsInt & IsUInt
|
717
|
+
// ========================
|
718
|
+
|
719
|
+
//! Checks whether the given integer `x` can be casted to a 4-bit signed integer.
|
720
|
+
template<typename T>
|
721
|
+
static constexpr bool isInt4(T x) noexcept {
|
722
|
+
typedef typename std::make_signed<T>::type S;
|
723
|
+
typedef typename std::make_unsigned<T>::type U;
|
724
|
+
|
725
|
+
return std::is_signed<T>::value ? isBetween<S>(S(x), -8, 7) : U(x) <= U(7u);
|
726
|
+
}
|
727
|
+
|
728
|
+
//! Checks whether the given integer `x` can be casted to a 7-bit signed integer.
|
729
|
+
template<typename T>
|
730
|
+
static constexpr bool isInt7(T x) noexcept {
|
731
|
+
typedef typename std::make_signed<T>::type S;
|
732
|
+
typedef typename std::make_unsigned<T>::type U;
|
733
|
+
|
734
|
+
return std::is_signed<T>::value ? isBetween<S>(S(x), -64, 63) : U(x) <= U(63u);
|
735
|
+
}
|
736
|
+
|
737
|
+
//! Checks whether the given integer `x` can be casted to an 8-bit signed integer.
|
738
|
+
template<typename T>
|
739
|
+
static constexpr bool isInt8(T x) noexcept {
|
740
|
+
typedef typename std::make_signed<T>::type S;
|
741
|
+
typedef typename std::make_unsigned<T>::type U;
|
742
|
+
|
743
|
+
return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -128, 127) : U(x) <= U(127u);
|
744
|
+
}
|
745
|
+
|
746
|
+
//! Checks whether the given integer `x` can be casted to a 9-bit signed integer.
|
747
|
+
template<typename T>
|
748
|
+
static constexpr bool isInt9(T x) noexcept {
|
749
|
+
typedef typename std::make_signed<T>::type S;
|
750
|
+
typedef typename std::make_unsigned<T>::type U;
|
751
|
+
|
752
|
+
return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -256, 255)
|
753
|
+
: sizeof(T) <= 1 || U(x) <= U(255u);
|
754
|
+
}
|
755
|
+
|
756
|
+
//! Checks whether the given integer `x` can be casted to a 10-bit signed integer.
|
757
|
+
template<typename T>
|
758
|
+
static constexpr bool isInt10(T x) noexcept {
|
759
|
+
typedef typename std::make_signed<T>::type S;
|
760
|
+
typedef typename std::make_unsigned<T>::type U;
|
761
|
+
|
762
|
+
return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -512, 511)
|
763
|
+
: sizeof(T) <= 1 || U(x) <= U(511u);
|
764
|
+
}
|
765
|
+
|
766
|
+
//! Checks whether the given integer `x` can be casted to a 16-bit signed integer.
|
767
|
+
template<typename T>
|
768
|
+
static constexpr bool isInt16(T x) noexcept {
|
769
|
+
typedef typename std::make_signed<T>::type S;
|
770
|
+
typedef typename std::make_unsigned<T>::type U;
|
771
|
+
|
772
|
+
return std::is_signed<T>::value ? sizeof(T) <= 2 || isBetween<S>(S(x), -32768, 32767)
|
773
|
+
: sizeof(T) <= 1 || U(x) <= U(32767u);
|
774
|
+
}
|
775
|
+
|
776
|
+
//! Checks whether the given integer `x` can be casted to a 32-bit signed integer.
|
777
|
+
template<typename T>
|
778
|
+
static constexpr bool isInt32(T x) noexcept {
|
779
|
+
typedef typename std::make_signed<T>::type S;
|
780
|
+
typedef typename std::make_unsigned<T>::type U;
|
781
|
+
|
782
|
+
return std::is_signed<T>::value ? sizeof(T) <= 4 || isBetween<S>(S(x), -2147483647 - 1, 2147483647)
|
783
|
+
: sizeof(T) <= 2 || U(x) <= U(2147483647u);
|
784
|
+
}
|
785
|
+
|
786
|
+
//! Checks whether the given integer `x` can be casted to a 4-bit unsigned integer.
|
787
|
+
template<typename T>
|
788
|
+
static constexpr bool isUInt4(T x) noexcept {
|
789
|
+
typedef typename std::make_unsigned<T>::type U;
|
790
|
+
|
791
|
+
return std::is_signed<T>::value ? x >= T(0) && x <= T(15)
|
792
|
+
: U(x) <= U(15u);
|
793
|
+
}
|
794
|
+
|
795
|
+
//! Checks whether the given integer `x` can be casted to an 8-bit unsigned integer.
|
796
|
+
template<typename T>
|
797
|
+
static constexpr bool isUInt8(T x) noexcept {
|
798
|
+
typedef typename std::make_unsigned<T>::type U;
|
799
|
+
|
800
|
+
return std::is_signed<T>::value ? (sizeof(T) <= 1 || T(x) <= T(255)) && x >= T(0)
|
801
|
+
: (sizeof(T) <= 1 || U(x) <= U(255u));
|
802
|
+
}
|
803
|
+
|
804
|
+
//! Checks whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific).
|
805
|
+
template<typename T>
|
806
|
+
static constexpr bool isUInt12(T x) noexcept {
|
807
|
+
typedef typename std::make_unsigned<T>::type U;
|
808
|
+
|
809
|
+
return std::is_signed<T>::value ? (sizeof(T) <= 1 || T(x) <= T(4095)) && x >= T(0)
|
810
|
+
: (sizeof(T) <= 1 || U(x) <= U(4095u));
|
811
|
+
}
|
812
|
+
|
813
|
+
//! Checks whether the given integer `x` can be casted to a 16-bit unsigned integer.
|
814
|
+
template<typename T>
|
815
|
+
static constexpr bool isUInt16(T x) noexcept {
|
816
|
+
typedef typename std::make_unsigned<T>::type U;
|
817
|
+
|
818
|
+
return std::is_signed<T>::value ? (sizeof(T) <= 2 || T(x) <= T(65535)) && x >= T(0)
|
819
|
+
: (sizeof(T) <= 2 || U(x) <= U(65535u));
|
820
|
+
}
|
821
|
+
|
822
|
+
//! Checks whether the given integer `x` can be casted to a 32-bit unsigned integer.
|
823
|
+
template<typename T>
|
824
|
+
static constexpr bool isUInt32(T x) noexcept {
|
825
|
+
typedef typename std::make_unsigned<T>::type U;
|
826
|
+
|
827
|
+
return std::is_signed<T>::value ? (sizeof(T) <= 4 || T(x) <= T(4294967295u)) && x >= T(0)
|
828
|
+
: (sizeof(T) <= 4 || U(x) <= U(4294967295u));
|
829
|
+
}
|
830
|
+
|
831
|
+
//! Checks whether the given integer `x` can be casted to a 32-bit unsigned integer.
|
832
|
+
template<typename T>
|
833
|
+
static constexpr bool isIntOrUInt32(T x) noexcept {
|
834
|
+
return sizeof(T) <= 4 ? true : (uint32_t(uint64_t(x) >> 32) + 1u) <= 1u;
|
835
|
+
}
|
836
|
+
|
837
|
+
static bool inline isEncodableOffset32(int32_t offset, uint32_t nBits) noexcept {
|
838
|
+
uint32_t nRev = 32 - nBits;
|
839
|
+
return Support::sar(Support::shl(offset, nRev), nRev) == offset;
|
840
|
+
}
|
841
|
+
|
842
|
+
static bool inline isEncodableOffset64(int64_t offset, uint32_t nBits) noexcept {
|
843
|
+
uint32_t nRev = 64 - nBits;
|
844
|
+
return Support::sar(Support::shl(offset, nRev), nRev) == offset;
|
845
|
+
}
|
846
|
+
|
847
|
+
// Support - ByteSwap
|
848
|
+
// ==================
|
849
|
+
|
850
|
+
static inline uint16_t byteswap16(uint16_t x) noexcept {
|
851
|
+
return uint16_t(((x >> 8) & 0xFFu) | ((x & 0xFFu) << 8));
|
852
|
+
}
|
853
|
+
|
854
|
+
static inline uint32_t byteswap32(uint32_t x) noexcept {
|
855
|
+
return (x << 24) | (x >> 24) | ((x << 8) & 0x00FF0000u) | ((x >> 8) & 0x0000FF00);
|
856
|
+
}
|
857
|
+
|
858
|
+
static inline uint64_t byteswap64(uint64_t x) noexcept {
|
859
|
+
#if (defined(__GNUC__) || defined(__clang__)) && !defined(ASMJIT_NO_INTRINSICS)
|
860
|
+
return uint64_t(__builtin_bswap64(uint64_t(x)));
|
861
|
+
#elif defined(_MSC_VER) && !defined(ASMJIT_NO_INTRINSICS)
|
862
|
+
return uint64_t(_byteswap_uint64(uint64_t(x)));
|
863
|
+
#else
|
864
|
+
return (uint64_t(byteswap32(uint32_t(uint64_t(x) >> 32 ))) ) |
|
865
|
+
(uint64_t(byteswap32(uint32_t(uint64_t(x) & 0xFFFFFFFFu))) << 32) ;
|
866
|
+
#endif
|
867
|
+
}
|
868
|
+
|
869
|
+
// Support - BytePack & Unpack
|
870
|
+
// ===========================
|
871
|
+
|
872
|
+
//! Pack four 8-bit integer into a 32-bit integer as it is an array of `{b0,b1,b2,b3}`.
|
873
|
+
static constexpr uint32_t bytepack32_4x8(uint32_t a, uint32_t b, uint32_t c, uint32_t d) noexcept {
|
874
|
+
return ASMJIT_ARCH_LE ? (a | (b << 8) | (c << 16) | (d << 24))
|
875
|
+
: (d | (c << 8) | (b << 16) | (a << 24));
|
876
|
+
}
|
877
|
+
|
878
|
+
template<typename T>
|
879
|
+
static constexpr uint32_t unpackU32At0(T x) noexcept { return ASMJIT_ARCH_LE ? uint32_t(uint64_t(x) & 0xFFFFFFFFu) : uint32_t(uint64_t(x) >> 32); }
|
880
|
+
template<typename T>
|
881
|
+
static constexpr uint32_t unpackU32At1(T x) noexcept { return ASMJIT_ARCH_BE ? uint32_t(uint64_t(x) & 0xFFFFFFFFu) : uint32_t(uint64_t(x) >> 32); }
|
882
|
+
|
883
|
+
// Support - Position of byte (in bit-shift)
|
884
|
+
// =========================================
|
885
|
+
|
886
|
+
static inline uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept {
|
887
|
+
return ASMJIT_ARCH_LE ? index * 8 : (uint32_t(sizeof(uint32_t)) - 1u - index) * 8;
|
888
|
+
}
|
889
|
+
|
890
|
+
// Support - String Utilities
|
891
|
+
// ==========================
|
892
|
+
|
893
|
+
template<typename T>
|
894
|
+
static constexpr T asciiToLower(T c) noexcept { return T(c ^ T(T(c >= T('A') && c <= T('Z')) << 5)); }
|
895
|
+
|
896
|
+
template<typename T>
|
897
|
+
static constexpr T asciiToUpper(T c) noexcept { return T(c ^ T(T(c >= T('a') && c <= T('z')) << 5)); }
|
898
|
+
|
899
|
+
static ASMJIT_FORCE_INLINE size_t strLen(const char* s, size_t maxSize) noexcept {
|
900
|
+
size_t i = 0;
|
901
|
+
while (i < maxSize && s[i] != '\0')
|
902
|
+
i++;
|
903
|
+
return i;
|
904
|
+
}
|
905
|
+
|
906
|
+
static constexpr uint32_t hashRound(uint32_t hash, uint32_t c) noexcept { return hash * 65599 + c; }
|
907
|
+
|
908
|
+
// Gets a hash of the given string `data` of size `size`. Size must be valid
|
909
|
+
// as this function doesn't check for a null terminator and allows it in the
|
910
|
+
// middle of the string.
|
911
|
+
static inline uint32_t hashString(const char* data, size_t size) noexcept {
|
912
|
+
uint32_t hashCode = 0;
|
913
|
+
for (uint32_t i = 0; i < size; i++)
|
914
|
+
hashCode = hashRound(hashCode, uint8_t(data[i]));
|
915
|
+
return hashCode;
|
916
|
+
}
|
917
|
+
|
918
|
+
static ASMJIT_FORCE_INLINE const char* findPackedString(const char* p, uint32_t id) noexcept {
|
919
|
+
uint32_t i = 0;
|
920
|
+
while (i < id) {
|
921
|
+
while (p[0])
|
922
|
+
p++;
|
923
|
+
p++;
|
924
|
+
i++;
|
925
|
+
}
|
926
|
+
return p;
|
927
|
+
}
|
928
|
+
|
929
|
+
//! Compares two instruction names.
|
930
|
+
//!
|
931
|
+
//! `a` is a null terminated instruction name from arch-specific `nameData[]`
|
932
|
+
//! table. `b` is a possibly non-null terminated instruction name passed to
|
933
|
+
//! `InstAPI::stringToInstId()`.
|
934
|
+
static ASMJIT_FORCE_INLINE int cmpInstName(const char* a, const char* b, size_t size) noexcept {
|
935
|
+
for (size_t i = 0; i < size; i++) {
|
936
|
+
int c = int(uint8_t(a[i])) - int(uint8_t(b[i]));
|
937
|
+
if (c != 0) return c;
|
938
|
+
}
|
939
|
+
return int(uint8_t(a[size]));
|
940
|
+
}
|
941
|
+
|
942
|
+
// Support - Memory Read Access - 8 Bits
|
943
|
+
// =====================================
|
944
|
+
|
945
|
+
static inline uint8_t readU8(const void* p) noexcept { return static_cast<const uint8_t*>(p)[0]; }
|
946
|
+
static inline int8_t readI8(const void* p) noexcept { return static_cast<const int8_t*>(p)[0]; }
|
947
|
+
|
948
|
+
// Support - Memory Read Access - 16 Bits
|
949
|
+
// ======================================
|
950
|
+
|
951
|
+
template<ByteOrder BO, size_t Alignment>
|
952
|
+
static inline uint16_t readU16x(const void* p) noexcept {
|
953
|
+
typedef typename Internal::AliasedUInt<uint16_t, Alignment>::T U16AlignedToN;
|
954
|
+
uint16_t x = static_cast<const U16AlignedToN*>(p)[0];
|
955
|
+
return BO == ByteOrder::kNative ? x : byteswap16(x);
|
956
|
+
}
|
957
|
+
|
958
|
+
template<size_t Alignment = 1>
|
959
|
+
static inline uint16_t readU16u(const void* p) noexcept { return readU16x<ByteOrder::kNative, Alignment>(p); }
|
960
|
+
template<size_t Alignment = 1>
|
961
|
+
static inline uint16_t readU16uLE(const void* p) noexcept { return readU16x<ByteOrder::kLE, Alignment>(p); }
|
962
|
+
template<size_t Alignment = 1>
|
963
|
+
static inline uint16_t readU16uBE(const void* p) noexcept { return readU16x<ByteOrder::kBE, Alignment>(p); }
|
964
|
+
|
965
|
+
static inline uint16_t readU16a(const void* p) noexcept { return readU16x<ByteOrder::kNative, 2>(p); }
|
966
|
+
static inline uint16_t readU16aLE(const void* p) noexcept { return readU16x<ByteOrder::kLE, 2>(p); }
|
967
|
+
static inline uint16_t readU16aBE(const void* p) noexcept { return readU16x<ByteOrder::kBE, 2>(p); }
|
968
|
+
|
969
|
+
template<ByteOrder BO, size_t Alignment>
|
970
|
+
static inline int16_t readI16x(const void* p) noexcept { return int16_t(readU16x<BO, Alignment>(p)); }
|
971
|
+
|
972
|
+
template<size_t Alignment = 1>
|
973
|
+
static inline int16_t readI16u(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kNative, Alignment>(p)); }
|
974
|
+
template<size_t Alignment = 1>
|
975
|
+
static inline int16_t readI16uLE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kLE, Alignment>(p)); }
|
976
|
+
template<size_t Alignment = 1>
|
977
|
+
static inline int16_t readI16uBE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kBE, Alignment>(p)); }
|
978
|
+
|
979
|
+
static inline int16_t readI16a(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kNative, 2>(p)); }
|
980
|
+
static inline int16_t readI16aLE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kLE, 2>(p)); }
|
981
|
+
static inline int16_t readI16aBE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kBE, 2>(p)); }
|
982
|
+
|
983
|
+
// Support - Memory Read Access - 24 Bits
|
984
|
+
// ======================================
|
985
|
+
|
986
|
+
template<ByteOrder BO = ByteOrder::kNative>
|
987
|
+
static inline uint32_t readU24u(const void* p) noexcept {
|
988
|
+
uint32_t b0 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 2 : 0));
|
989
|
+
uint32_t b1 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 1 : 1));
|
990
|
+
uint32_t b2 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 0 : 2));
|
991
|
+
return (b0 << 16) | (b1 << 8) | b2;
|
992
|
+
}
|
993
|
+
|
994
|
+
static inline uint32_t readU24uLE(const void* p) noexcept { return readU24u<ByteOrder::kLE>(p); }
|
995
|
+
static inline uint32_t readU24uBE(const void* p) noexcept { return readU24u<ByteOrder::kBE>(p); }
|
996
|
+
|
997
|
+
// Support - Memory Read Access - 32 Bits
|
998
|
+
// ======================================
|
999
|
+
|
1000
|
+
template<ByteOrder BO, size_t Alignment>
|
1001
|
+
static inline uint32_t readU32x(const void* p) noexcept {
|
1002
|
+
typedef typename Internal::AliasedUInt<uint32_t, Alignment>::T U32AlignedToN;
|
1003
|
+
uint32_t x = static_cast<const U32AlignedToN*>(p)[0];
|
1004
|
+
return BO == ByteOrder::kNative ? x : byteswap32(x);
|
1005
|
+
}
|
1006
|
+
|
1007
|
+
template<size_t Alignment = 1>
|
1008
|
+
static inline uint32_t readU32u(const void* p) noexcept { return readU32x<ByteOrder::kNative, Alignment>(p); }
|
1009
|
+
template<size_t Alignment = 1>
|
1010
|
+
static inline uint32_t readU32uLE(const void* p) noexcept { return readU32x<ByteOrder::kLE, Alignment>(p); }
|
1011
|
+
template<size_t Alignment = 1>
|
1012
|
+
static inline uint32_t readU32uBE(const void* p) noexcept { return readU32x<ByteOrder::kBE, Alignment>(p); }
|
1013
|
+
|
1014
|
+
static inline uint32_t readU32a(const void* p) noexcept { return readU32x<ByteOrder::kNative, 4>(p); }
|
1015
|
+
static inline uint32_t readU32aLE(const void* p) noexcept { return readU32x<ByteOrder::kLE, 4>(p); }
|
1016
|
+
static inline uint32_t readU32aBE(const void* p) noexcept { return readU32x<ByteOrder::kBE, 4>(p); }
|
1017
|
+
|
1018
|
+
template<ByteOrder BO, size_t Alignment>
|
1019
|
+
static inline uint32_t readI32x(const void* p) noexcept { return int32_t(readU32x<BO, Alignment>(p)); }
|
1020
|
+
|
1021
|
+
template<size_t Alignment = 1>
|
1022
|
+
static inline int32_t readI32u(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kNative, Alignment>(p)); }
|
1023
|
+
template<size_t Alignment = 1>
|
1024
|
+
static inline int32_t readI32uLE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kLE, Alignment>(p)); }
|
1025
|
+
template<size_t Alignment = 1>
|
1026
|
+
static inline int32_t readI32uBE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kBE, Alignment>(p)); }
|
1027
|
+
|
1028
|
+
static inline int32_t readI32a(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kNative, 4>(p)); }
|
1029
|
+
static inline int32_t readI32aLE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kLE, 4>(p)); }
|
1030
|
+
static inline int32_t readI32aBE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kBE, 4>(p)); }
|
1031
|
+
|
1032
|
+
// Support - Memory Read Access - 64 Bits
|
1033
|
+
// ======================================
|
1034
|
+
|
1035
|
+
template<ByteOrder BO, size_t Alignment>
|
1036
|
+
static inline uint64_t readU64x(const void* p) noexcept {
|
1037
|
+
typedef typename Internal::AliasedUInt<uint64_t, Alignment>::T U64AlignedToN;
|
1038
|
+
uint64_t x = static_cast<const U64AlignedToN*>(p)[0];
|
1039
|
+
return BO == ByteOrder::kNative ? x : byteswap64(x);
|
1040
|
+
}
|
1041
|
+
|
1042
|
+
template<size_t Alignment = 1>
|
1043
|
+
static inline uint64_t readU64u(const void* p) noexcept { return readU64x<ByteOrder::kNative, Alignment>(p); }
|
1044
|
+
template<size_t Alignment = 1>
|
1045
|
+
static inline uint64_t readU64uLE(const void* p) noexcept { return readU64x<ByteOrder::kLE, Alignment>(p); }
|
1046
|
+
template<size_t Alignment = 1>
|
1047
|
+
static inline uint64_t readU64uBE(const void* p) noexcept { return readU64x<ByteOrder::kBE, Alignment>(p); }
|
1048
|
+
|
1049
|
+
static inline uint64_t readU64a(const void* p) noexcept { return readU64x<ByteOrder::kNative, 8>(p); }
|
1050
|
+
static inline uint64_t readU64aLE(const void* p) noexcept { return readU64x<ByteOrder::kLE, 8>(p); }
|
1051
|
+
static inline uint64_t readU64aBE(const void* p) noexcept { return readU64x<ByteOrder::kBE, 8>(p); }
|
1052
|
+
|
1053
|
+
template<ByteOrder BO, size_t Alignment>
|
1054
|
+
static inline int64_t readI64x(const void* p) noexcept { return int64_t(readU64x<BO, Alignment>(p)); }
|
1055
|
+
|
1056
|
+
template<size_t Alignment = 1>
|
1057
|
+
static inline int64_t readI64u(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kNative, Alignment>(p)); }
|
1058
|
+
template<size_t Alignment = 1>
|
1059
|
+
static inline int64_t readI64uLE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kLE, Alignment>(p)); }
|
1060
|
+
template<size_t Alignment = 1>
|
1061
|
+
static inline int64_t readI64uBE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kBE, Alignment>(p)); }
|
1062
|
+
|
1063
|
+
static inline int64_t readI64a(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kNative, 8>(p)); }
|
1064
|
+
static inline int64_t readI64aLE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kLE, 8>(p)); }
|
1065
|
+
static inline int64_t readI64aBE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kBE, 8>(p)); }
|
1066
|
+
|
1067
|
+
// Support - Memory Write Access - 8 Bits
|
1068
|
+
// ======================================
|
1069
|
+
|
1070
|
+
static inline void writeU8(void* p, uint8_t x) noexcept { static_cast<uint8_t*>(p)[0] = x; }
|
1071
|
+
static inline void writeI8(void* p, int8_t x) noexcept { static_cast<int8_t*>(p)[0] = x; }
|
1072
|
+
|
1073
|
+
// Support - Memory Write Access - 16 Bits
|
1074
|
+
// =======================================
|
1075
|
+
|
1076
|
+
template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
|
1077
|
+
static inline void writeU16x(void* p, uint16_t x) noexcept {
|
1078
|
+
typedef typename Internal::AliasedUInt<uint16_t, Alignment>::T U16AlignedToN;
|
1079
|
+
static_cast<U16AlignedToN*>(p)[0] = BO == ByteOrder::kNative ? x : byteswap16(x);
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
template<size_t Alignment = 1>
|
1083
|
+
static inline void writeU16uLE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kLE, Alignment>(p, x); }
|
1084
|
+
template<size_t Alignment = 1>
|
1085
|
+
static inline void writeU16uBE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kBE, Alignment>(p, x); }
|
1086
|
+
|
1087
|
+
static inline void writeU16a(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kNative, 2>(p, x); }
|
1088
|
+
static inline void writeU16aLE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kLE, 2>(p, x); }
|
1089
|
+
static inline void writeU16aBE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kBE, 2>(p, x); }
|
1090
|
+
|
1091
|
+
|
1092
|
+
template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
|
1093
|
+
static inline void writeI16x(void* p, int16_t x) noexcept { writeU16x<BO, Alignment>(p, uint16_t(x)); }
|
1094
|
+
|
1095
|
+
template<size_t Alignment = 1>
|
1096
|
+
static inline void writeI16uLE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kLE, Alignment>(p, uint16_t(x)); }
|
1097
|
+
template<size_t Alignment = 1>
|
1098
|
+
static inline void writeI16uBE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kBE, Alignment>(p, uint16_t(x)); }
|
1099
|
+
|
1100
|
+
static inline void writeI16a(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kNative, 2>(p, uint16_t(x)); }
|
1101
|
+
static inline void writeI16aLE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kLE, 2>(p, uint16_t(x)); }
|
1102
|
+
static inline void writeI16aBE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kBE, 2>(p, uint16_t(x)); }
|
1103
|
+
|
1104
|
+
// Support - Memory Write Access - 24 Bits
|
1105
|
+
// =======================================
|
1106
|
+
|
1107
|
+
template<ByteOrder BO = ByteOrder::kNative>
|
1108
|
+
static inline void writeU24u(void* p, uint32_t v) noexcept {
|
1109
|
+
static_cast<uint8_t*>(p)[0] = uint8_t((v >> (BO == ByteOrder::kLE ? 0 : 16)) & 0xFFu);
|
1110
|
+
static_cast<uint8_t*>(p)[1] = uint8_t((v >> (BO == ByteOrder::kLE ? 8 : 8)) & 0xFFu);
|
1111
|
+
static_cast<uint8_t*>(p)[2] = uint8_t((v >> (BO == ByteOrder::kLE ? 16 : 0)) & 0xFFu);
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
static inline void writeU24uLE(void* p, uint32_t v) noexcept { writeU24u<ByteOrder::kLE>(p, v); }
|
1115
|
+
static inline void writeU24uBE(void* p, uint32_t v) noexcept { writeU24u<ByteOrder::kBE>(p, v); }
|
1116
|
+
|
1117
|
+
// Support - Memory Write Access - 32 Bits
|
1118
|
+
// =======================================
|
1119
|
+
|
1120
|
+
template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
|
1121
|
+
static inline void writeU32x(void* p, uint32_t x) noexcept {
|
1122
|
+
typedef typename Internal::AliasedUInt<uint32_t, Alignment>::T U32AlignedToN;
|
1123
|
+
static_cast<U32AlignedToN*>(p)[0] = (BO == ByteOrder::kNative) ? x : Support::byteswap32(x);
|
1124
|
+
}
|
1125
|
+
|
1126
|
+
template<size_t Alignment = 1>
|
1127
|
+
static inline void writeU32u(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kNative, Alignment>(p, x); }
|
1128
|
+
template<size_t Alignment = 1>
|
1129
|
+
static inline void writeU32uLE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kLE, Alignment>(p, x); }
|
1130
|
+
template<size_t Alignment = 1>
|
1131
|
+
static inline void writeU32uBE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kBE, Alignment>(p, x); }
|
1132
|
+
|
1133
|
+
static inline void writeU32a(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kNative, 4>(p, x); }
|
1134
|
+
static inline void writeU32aLE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kLE, 4>(p, x); }
|
1135
|
+
static inline void writeU32aBE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kBE, 4>(p, x); }
|
1136
|
+
|
1137
|
+
template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
|
1138
|
+
static inline void writeI32x(void* p, int32_t x) noexcept { writeU32x<BO, Alignment>(p, uint32_t(x)); }
|
1139
|
+
|
1140
|
+
template<size_t Alignment = 1>
|
1141
|
+
static inline void writeI32u(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kNative, Alignment>(p, uint32_t(x)); }
|
1142
|
+
template<size_t Alignment = 1>
|
1143
|
+
static inline void writeI32uLE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kLE, Alignment>(p, uint32_t(x)); }
|
1144
|
+
template<size_t Alignment = 1>
|
1145
|
+
static inline void writeI32uBE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kBE, Alignment>(p, uint32_t(x)); }
|
1146
|
+
|
1147
|
+
static inline void writeI32a(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kNative, 4>(p, uint32_t(x)); }
|
1148
|
+
static inline void writeI32aLE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kLE, 4>(p, uint32_t(x)); }
|
1149
|
+
static inline void writeI32aBE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kBE, 4>(p, uint32_t(x)); }
|
1150
|
+
|
1151
|
+
// Support - Memory Write Access - 64 Bits
|
1152
|
+
// =======================================
|
1153
|
+
|
1154
|
+
template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
|
1155
|
+
static inline void writeU64x(void* p, uint64_t x) noexcept {
|
1156
|
+
typedef typename Internal::AliasedUInt<uint64_t, Alignment>::T U64AlignedToN;
|
1157
|
+
static_cast<U64AlignedToN*>(p)[0] = BO == ByteOrder::kNative ? x : byteswap64(x);
|
1158
|
+
}
|
1159
|
+
|
1160
|
+
template<size_t Alignment = 1>
|
1161
|
+
static inline void writeU64u(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kNative, Alignment>(p, x); }
|
1162
|
+
template<size_t Alignment = 1>
|
1163
|
+
static inline void writeU64uLE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kLE, Alignment>(p, x); }
|
1164
|
+
template<size_t Alignment = 1>
|
1165
|
+
static inline void writeU64uBE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kBE, Alignment>(p, x); }
|
1166
|
+
|
1167
|
+
static inline void writeU64a(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kNative, 8>(p, x); }
|
1168
|
+
static inline void writeU64aLE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kLE, 8>(p, x); }
|
1169
|
+
static inline void writeU64aBE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kBE, 8>(p, x); }
|
1170
|
+
|
1171
|
+
template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
|
1172
|
+
static inline void writeI64x(void* p, int64_t x) noexcept { writeU64x<BO, Alignment>(p, uint64_t(x)); }
|
1173
|
+
|
1174
|
+
template<size_t Alignment = 1>
|
1175
|
+
static inline void writeI64u(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kNative, Alignment>(p, uint64_t(x)); }
|
1176
|
+
template<size_t Alignment = 1>
|
1177
|
+
static inline void writeI64uLE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kLE, Alignment>(p, uint64_t(x)); }
|
1178
|
+
template<size_t Alignment = 1>
|
1179
|
+
static inline void writeI64uBE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kBE, Alignment>(p, uint64_t(x)); }
|
1180
|
+
|
1181
|
+
static inline void writeI64a(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kNative, 8>(p, uint64_t(x)); }
|
1182
|
+
static inline void writeI64aLE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kLE, 8>(p, uint64_t(x)); }
|
1183
|
+
static inline void writeI64aBE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kBE, 8>(p, uint64_t(x)); }
|
1184
|
+
|
1185
|
+
// Support - Operators
|
1186
|
+
// ===================
|
1187
|
+
|
1188
|
+
//! \cond INTERNAL
|
1189
|
+
struct Set { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return y; } };
|
1190
|
+
struct SetNot { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return ~y; } };
|
1191
|
+
struct And { template<typename T> static inline T op(T x, T y) noexcept { return x & y; } };
|
1192
|
+
struct AndNot { template<typename T> static inline T op(T x, T y) noexcept { return x & ~y; } };
|
1193
|
+
struct NotAnd { template<typename T> static inline T op(T x, T y) noexcept { return ~x & y; } };
|
1194
|
+
struct Or { template<typename T> static inline T op(T x, T y) noexcept { return x | y; } };
|
1195
|
+
struct Xor { template<typename T> static inline T op(T x, T y) noexcept { return x ^ y; } };
|
1196
|
+
struct Add { template<typename T> static inline T op(T x, T y) noexcept { return x + y; } };
|
1197
|
+
struct Sub { template<typename T> static inline T op(T x, T y) noexcept { return x - y; } };
|
1198
|
+
struct Min { template<typename T> static inline T op(T x, T y) noexcept { return min<T>(x, y); } };
|
1199
|
+
struct Max { template<typename T> static inline T op(T x, T y) noexcept { return max<T>(x, y); } };
|
1200
|
+
//! \endcond
|
1201
|
+
|
1202
|
+
// Support - BitWordIterator
|
1203
|
+
// =========================
|
1204
|
+
|
1205
|
+
//! Iterates over each bit in a number which is set to 1.
|
1206
|
+
//!
|
1207
|
+
//! Example of use:
|
1208
|
+
//!
|
1209
|
+
//! ```
|
1210
|
+
//! uint32_t bitsToIterate = 0x110F;
|
1211
|
+
//! Support::BitWordIterator<uint32_t> it(bitsToIterate);
|
1212
|
+
//!
|
1213
|
+
//! while (it.hasNext()) {
|
1214
|
+
//! uint32_t bitIndex = it.next();
|
1215
|
+
//! std::printf("Bit at %u is set\n", unsigned(bitIndex));
|
1216
|
+
//! }
|
1217
|
+
//! ```
|
1218
|
+
template<typename T>
|
1219
|
+
class BitWordIterator {
|
1220
|
+
public:
|
1221
|
+
ASMJIT_FORCE_INLINE explicit BitWordIterator(T bitWord) noexcept
|
1222
|
+
: _bitWord(bitWord) {}
|
1223
|
+
|
1224
|
+
ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
|
1225
|
+
ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
|
1226
|
+
|
1227
|
+
ASMJIT_FORCE_INLINE uint32_t next() noexcept {
|
1228
|
+
ASMJIT_ASSERT(_bitWord != 0);
|
1229
|
+
uint32_t index = ctz(_bitWord);
|
1230
|
+
_bitWord ^= T(1u) << index;
|
1231
|
+
return index;
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
T _bitWord;
|
1235
|
+
};
|
1236
|
+
|
1237
|
+
// Support - BitWordFlipIterator
|
1238
|
+
// =============================
|
1239
|
+
|
1240
|
+
template<typename T>
|
1241
|
+
class BitWordFlipIterator {
|
1242
|
+
public:
|
1243
|
+
ASMJIT_FORCE_INLINE explicit BitWordFlipIterator(T bitWord) noexcept
|
1244
|
+
: _bitWord(bitWord) {}
|
1245
|
+
|
1246
|
+
ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
|
1247
|
+
ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
|
1248
|
+
|
1249
|
+
ASMJIT_FORCE_INLINE uint32_t nextAndFlip() noexcept {
|
1250
|
+
ASMJIT_ASSERT(_bitWord != 0);
|
1251
|
+
uint32_t index = ctz(_bitWord);
|
1252
|
+
_bitWord ^= T(1u) << index;
|
1253
|
+
return index;
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
T _bitWord;
|
1257
|
+
T _xorMask;
|
1258
|
+
};
|
1259
|
+
|
1260
|
+
// Support - BitVectorOps
|
1261
|
+
// ======================
|
1262
|
+
|
1263
|
+
//! \cond
|
1264
|
+
namespace Internal {
|
1265
|
+
template<typename T, class OperatorT, class FullWordOpT>
|
1266
|
+
static inline void bitVectorOp(T* buf, size_t index, size_t count) noexcept {
|
1267
|
+
if (count == 0)
|
1268
|
+
return;
|
1269
|
+
|
1270
|
+
const size_t kTSizeInBits = bitSizeOf<T>();
|
1271
|
+
size_t vecIndex = index / kTSizeInBits; // T[]
|
1272
|
+
size_t bitIndex = index % kTSizeInBits; // T[][]
|
1273
|
+
|
1274
|
+
buf += vecIndex;
|
1275
|
+
|
1276
|
+
// The first BitWord requires special handling to preserve bits outside the fill region.
|
1277
|
+
const T kFillMask = allOnes<T>();
|
1278
|
+
size_t firstNBits = min<size_t>(kTSizeInBits - bitIndex, count);
|
1279
|
+
|
1280
|
+
buf[0] = OperatorT::op(buf[0], (kFillMask >> (kTSizeInBits - firstNBits)) << bitIndex);
|
1281
|
+
buf++;
|
1282
|
+
count -= firstNBits;
|
1283
|
+
|
1284
|
+
// All bits between the first and last affected BitWords can be just filled.
|
1285
|
+
while (count >= kTSizeInBits) {
|
1286
|
+
buf[0] = FullWordOpT::op(buf[0], kFillMask);
|
1287
|
+
buf++;
|
1288
|
+
count -= kTSizeInBits;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
// The last BitWord requires special handling as well
|
1292
|
+
if (count)
|
1293
|
+
buf[0] = OperatorT::op(buf[0], kFillMask >> (kTSizeInBits - count));
|
1294
|
+
}
|
1295
|
+
}
|
1296
|
+
//! \endcond
|
1297
|
+
|
1298
|
+
//! Sets bit in a bit-vector `buf` at `index`.
|
1299
|
+
template<typename T>
|
1300
|
+
static inline bool bitVectorGetBit(T* buf, size_t index) noexcept {
|
1301
|
+
const size_t kTSizeInBits = bitSizeOf<T>();
|
1302
|
+
|
1303
|
+
size_t vecIndex = index / kTSizeInBits;
|
1304
|
+
size_t bitIndex = index % kTSizeInBits;
|
1305
|
+
|
1306
|
+
return bool((buf[vecIndex] >> bitIndex) & 0x1u);
|
1307
|
+
}
|
1308
|
+
|
1309
|
+
//! Sets bit in a bit-vector `buf` at `index` to `value`.
|
1310
|
+
template<typename T>
|
1311
|
+
static inline void bitVectorSetBit(T* buf, size_t index, bool value) noexcept {
|
1312
|
+
const size_t kTSizeInBits = bitSizeOf<T>();
|
1313
|
+
|
1314
|
+
size_t vecIndex = index / kTSizeInBits;
|
1315
|
+
size_t bitIndex = index % kTSizeInBits;
|
1316
|
+
|
1317
|
+
T bitMask = T(1u) << bitIndex;
|
1318
|
+
if (value)
|
1319
|
+
buf[vecIndex] |= bitMask;
|
1320
|
+
else
|
1321
|
+
buf[vecIndex] &= ~bitMask;
|
1322
|
+
}
|
1323
|
+
|
1324
|
+
//! Sets bit in a bit-vector `buf` at `index` to `value`.
|
1325
|
+
template<typename T>
|
1326
|
+
static inline void bitVectorFlipBit(T* buf, size_t index) noexcept {
|
1327
|
+
const size_t kTSizeInBits = bitSizeOf<T>();
|
1328
|
+
|
1329
|
+
size_t vecIndex = index / kTSizeInBits;
|
1330
|
+
size_t bitIndex = index % kTSizeInBits;
|
1331
|
+
|
1332
|
+
T bitMask = T(1u) << bitIndex;
|
1333
|
+
buf[vecIndex] ^= bitMask;
|
1334
|
+
}
|
1335
|
+
|
1336
|
+
//! Fills `count` bits in bit-vector `buf` starting at bit-index `index`.
|
1337
|
+
template<typename T>
|
1338
|
+
static inline void bitVectorFill(T* buf, size_t index, size_t count) noexcept { Internal::bitVectorOp<T, Or, Set>(buf, index, count); }
|
1339
|
+
|
1340
|
+
//! Clears `count` bits in bit-vector `buf` starting at bit-index `index`.
|
1341
|
+
template<typename T>
|
1342
|
+
static inline void bitVectorClear(T* buf, size_t index, size_t count) noexcept { Internal::bitVectorOp<T, AndNot, SetNot>(buf, index, count); }
|
1343
|
+
|
1344
|
+
template<typename T>
|
1345
|
+
static inline size_t bitVectorIndexOf(T* buf, size_t start, bool value) noexcept {
|
1346
|
+
const size_t kTSizeInBits = bitSizeOf<T>();
|
1347
|
+
size_t vecIndex = start / kTSizeInBits; // T[]
|
1348
|
+
size_t bitIndex = start % kTSizeInBits; // T[][]
|
1349
|
+
|
1350
|
+
T* p = buf + vecIndex;
|
1351
|
+
|
1352
|
+
// We always look for zeros, if value is `true` we have to flip all bits before the search.
|
1353
|
+
const T kFillMask = allOnes<T>();
|
1354
|
+
const T kFlipMask = value ? T(0) : kFillMask;
|
1355
|
+
|
1356
|
+
// The first BitWord requires special handling as there are some bits we want to ignore.
|
1357
|
+
T bits = (*p ^ kFlipMask) & (kFillMask << bitIndex);
|
1358
|
+
for (;;) {
|
1359
|
+
if (bits)
|
1360
|
+
return (size_t)(p - buf) * kTSizeInBits + ctz(bits);
|
1361
|
+
bits = *++p ^ kFlipMask;
|
1362
|
+
}
|
1363
|
+
}
|
1364
|
+
|
1365
|
+
// Support - BitVectorIterator
|
1366
|
+
// ===========================
|
1367
|
+
|
1368
|
+
template<typename T>
|
1369
|
+
class BitVectorIterator {
|
1370
|
+
public:
|
1371
|
+
const T* _ptr;
|
1372
|
+
size_t _idx;
|
1373
|
+
size_t _end;
|
1374
|
+
T _current;
|
1375
|
+
|
1376
|
+
ASMJIT_FORCE_INLINE BitVectorIterator(const BitVectorIterator& other) noexcept = default;
|
1377
|
+
|
1378
|
+
ASMJIT_FORCE_INLINE BitVectorIterator(const T* data, size_t numBitWords, size_t start = 0) noexcept {
|
1379
|
+
init(data, numBitWords, start);
|
1380
|
+
}
|
1381
|
+
|
1382
|
+
ASMJIT_FORCE_INLINE void init(const T* data, size_t numBitWords, size_t start = 0) noexcept {
|
1383
|
+
const T* ptr = data + (start / bitSizeOf<T>());
|
1384
|
+
size_t idx = alignDown(start, bitSizeOf<T>());
|
1385
|
+
size_t end = numBitWords * bitSizeOf<T>();
|
1386
|
+
|
1387
|
+
T bitWord = T(0);
|
1388
|
+
if (idx < end) {
|
1389
|
+
bitWord = *ptr++ & (allOnes<T>() << (start % bitSizeOf<T>()));
|
1390
|
+
while (!bitWord && (idx += bitSizeOf<T>()) < end)
|
1391
|
+
bitWord = *ptr++;
|
1392
|
+
}
|
1393
|
+
|
1394
|
+
_ptr = ptr;
|
1395
|
+
_idx = idx;
|
1396
|
+
_end = end;
|
1397
|
+
_current = bitWord;
|
1398
|
+
}
|
1399
|
+
|
1400
|
+
ASMJIT_FORCE_INLINE bool hasNext() const noexcept {
|
1401
|
+
return _current != T(0);
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
ASMJIT_FORCE_INLINE size_t next() noexcept {
|
1405
|
+
T bitWord = _current;
|
1406
|
+
ASMJIT_ASSERT(bitWord != T(0));
|
1407
|
+
|
1408
|
+
uint32_t bit = ctz(bitWord);
|
1409
|
+
bitWord ^= T(1u) << bit;
|
1410
|
+
|
1411
|
+
size_t n = _idx + bit;
|
1412
|
+
while (!bitWord && (_idx += bitSizeOf<T>()) < _end)
|
1413
|
+
bitWord = *_ptr++;
|
1414
|
+
|
1415
|
+
_current = bitWord;
|
1416
|
+
return n;
|
1417
|
+
}
|
1418
|
+
|
1419
|
+
ASMJIT_FORCE_INLINE size_t peekNext() const noexcept {
|
1420
|
+
ASMJIT_ASSERT(_current != T(0));
|
1421
|
+
return _idx + ctz(_current);
|
1422
|
+
}
|
1423
|
+
};
|
1424
|
+
|
1425
|
+
// Support - BitVectorOpIterator
|
1426
|
+
// =============================
|
1427
|
+
|
1428
|
+
template<typename T, class OperatorT>
|
1429
|
+
class BitVectorOpIterator {
|
1430
|
+
public:
|
1431
|
+
enum : uint32_t {
|
1432
|
+
kTSizeInBits = bitSizeOf<T>()
|
1433
|
+
};
|
1434
|
+
|
1435
|
+
const T* _aPtr;
|
1436
|
+
const T* _bPtr;
|
1437
|
+
size_t _idx;
|
1438
|
+
size_t _end;
|
1439
|
+
T _current;
|
1440
|
+
|
1441
|
+
ASMJIT_FORCE_INLINE BitVectorOpIterator(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept {
|
1442
|
+
init(aData, bData, numBitWords, start);
|
1443
|
+
}
|
1444
|
+
|
1445
|
+
ASMJIT_FORCE_INLINE void init(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept {
|
1446
|
+
const T* aPtr = aData + (start / bitSizeOf<T>());
|
1447
|
+
const T* bPtr = bData + (start / bitSizeOf<T>());
|
1448
|
+
size_t idx = alignDown(start, bitSizeOf<T>());
|
1449
|
+
size_t end = numBitWords * bitSizeOf<T>();
|
1450
|
+
|
1451
|
+
T bitWord = T(0);
|
1452
|
+
if (idx < end) {
|
1453
|
+
bitWord = OperatorT::op(*aPtr++, *bPtr++) & (allOnes<T>() << (start % bitSizeOf<T>()));
|
1454
|
+
while (!bitWord && (idx += kTSizeInBits) < end)
|
1455
|
+
bitWord = OperatorT::op(*aPtr++, *bPtr++);
|
1456
|
+
}
|
1457
|
+
|
1458
|
+
_aPtr = aPtr;
|
1459
|
+
_bPtr = bPtr;
|
1460
|
+
_idx = idx;
|
1461
|
+
_end = end;
|
1462
|
+
_current = bitWord;
|
1463
|
+
}
|
1464
|
+
|
1465
|
+
ASMJIT_FORCE_INLINE bool hasNext() noexcept {
|
1466
|
+
return _current != T(0);
|
1467
|
+
}
|
1468
|
+
|
1469
|
+
ASMJIT_FORCE_INLINE size_t next() noexcept {
|
1470
|
+
T bitWord = _current;
|
1471
|
+
ASMJIT_ASSERT(bitWord != T(0));
|
1472
|
+
|
1473
|
+
uint32_t bit = ctz(bitWord);
|
1474
|
+
bitWord ^= T(1u) << bit;
|
1475
|
+
|
1476
|
+
size_t n = _idx + bit;
|
1477
|
+
while (!bitWord && (_idx += kTSizeInBits) < _end)
|
1478
|
+
bitWord = OperatorT::op(*_aPtr++, *_bPtr++);
|
1479
|
+
|
1480
|
+
_current = bitWord;
|
1481
|
+
return n;
|
1482
|
+
}
|
1483
|
+
};
|
1484
|
+
|
1485
|
+
// Support - Sorting
|
1486
|
+
// =================
|
1487
|
+
|
1488
|
+
//! Sort order.
|
1489
|
+
enum class SortOrder : uint32_t {
|
1490
|
+
//!< Ascending order.
|
1491
|
+
kAscending = 0,
|
1492
|
+
//!< Descending order.
|
1493
|
+
kDescending = 1
|
1494
|
+
};
|
1495
|
+
|
1496
|
+
//! A helper class that provides comparison of any user-defined type that
|
1497
|
+
//! implements `<` and `>` operators (primitive types are supported as well).
|
1498
|
+
template<SortOrder kOrder = SortOrder::kAscending>
|
1499
|
+
struct Compare {
|
1500
|
+
template<typename A, typename B>
|
1501
|
+
inline int operator()(const A& a, const B& b) const noexcept {
|
1502
|
+
return kOrder == SortOrder::kAscending ? int(a > b) - int(a < b) : int(a < b) - int(a > b);
|
1503
|
+
}
|
1504
|
+
};
|
1505
|
+
|
1506
|
+
//! Insertion sort.
|
1507
|
+
template<typename T, typename CompareT = Compare<SortOrder::kAscending>>
|
1508
|
+
static inline void iSort(T* base, size_t size, const CompareT& cmp = CompareT()) noexcept {
|
1509
|
+
for (T* pm = base + 1; pm < base + size; pm++)
|
1510
|
+
for (T* pl = pm; pl > base && cmp(pl[-1], pl[0]) > 0; pl--)
|
1511
|
+
std::swap(pl[-1], pl[0]);
|
1512
|
+
}
|
1513
|
+
|
1514
|
+
//! \cond
|
1515
|
+
namespace Internal {
|
1516
|
+
//! Quick-sort implementation.
|
1517
|
+
template<typename T, class CompareT>
|
1518
|
+
struct QSortImpl {
|
1519
|
+
enum : size_t {
|
1520
|
+
kStackSize = 64 * 2,
|
1521
|
+
kISortThreshold = 7
|
1522
|
+
};
|
1523
|
+
|
1524
|
+
// Based on "PDCLib - Public Domain C Library" and rewritten to C++.
|
1525
|
+
static void sort(T* base, size_t size, const CompareT& cmp) noexcept {
|
1526
|
+
T* end = base + size;
|
1527
|
+
T* stack[kStackSize];
|
1528
|
+
T** stackptr = stack;
|
1529
|
+
|
1530
|
+
for (;;) {
|
1531
|
+
if ((size_t)(end - base) > kISortThreshold) {
|
1532
|
+
// We work from second to last - first will be pivot element.
|
1533
|
+
T* pi = base + 1;
|
1534
|
+
T* pj = end - 1;
|
1535
|
+
std::swap(base[(size_t)(end - base) / 2], base[0]);
|
1536
|
+
|
1537
|
+
if (cmp(*pi , *pj ) > 0) std::swap(*pi , *pj );
|
1538
|
+
if (cmp(*base, *pj ) > 0) std::swap(*base, *pj );
|
1539
|
+
if (cmp(*pi , *base) > 0) std::swap(*pi , *base);
|
1540
|
+
|
1541
|
+
// Now we have the median for pivot element, entering main loop.
|
1542
|
+
for (;;) {
|
1543
|
+
while (pi < pj && cmp(*++pi, *base) < 0) continue; // Move `i` right until `*i >= pivot`.
|
1544
|
+
while (pj > base && cmp(*--pj, *base) > 0) continue; // Move `j` left until `*j <= pivot`.
|
1545
|
+
|
1546
|
+
if (pi > pj) break;
|
1547
|
+
std::swap(*pi, *pj);
|
1548
|
+
}
|
1549
|
+
|
1550
|
+
// Move pivot into correct place.
|
1551
|
+
std::swap(*base, *pj);
|
1552
|
+
|
1553
|
+
// Larger subfile base / end to stack, sort smaller.
|
1554
|
+
if (pj - base > end - pi) {
|
1555
|
+
// Left is larger.
|
1556
|
+
*stackptr++ = base;
|
1557
|
+
*stackptr++ = pj;
|
1558
|
+
base = pi;
|
1559
|
+
}
|
1560
|
+
else {
|
1561
|
+
// Right is larger.
|
1562
|
+
*stackptr++ = pi;
|
1563
|
+
*stackptr++ = end;
|
1564
|
+
end = pj;
|
1565
|
+
}
|
1566
|
+
ASMJIT_ASSERT(stackptr <= stack + kStackSize);
|
1567
|
+
}
|
1568
|
+
else {
|
1569
|
+
// UB sanitizer doesn't like applying offset to a nullptr base.
|
1570
|
+
if (base != end)
|
1571
|
+
iSort(base, (size_t)(end - base), cmp);
|
1572
|
+
|
1573
|
+
if (stackptr == stack)
|
1574
|
+
break;
|
1575
|
+
|
1576
|
+
end = *--stackptr;
|
1577
|
+
base = *--stackptr;
|
1578
|
+
}
|
1579
|
+
}
|
1580
|
+
}
|
1581
|
+
};
|
1582
|
+
}
|
1583
|
+
//! \endcond
|
1584
|
+
|
1585
|
+
//! Quick sort implementation.
|
1586
|
+
//!
|
1587
|
+
//! The main reason to provide a custom qsort implementation is that we needed something that will
|
1588
|
+
//! never throw `bad_alloc` exception. This implementation doesn't use dynamic memory allocation.
|
1589
|
+
template<typename T, class CompareT = Compare<SortOrder::kAscending>>
|
1590
|
+
static inline void qSort(T* base, size_t size, const CompareT& cmp = CompareT()) noexcept {
|
1591
|
+
Internal::QSortImpl<T, CompareT>::sort(base, size, cmp);
|
1592
|
+
}
|
1593
|
+
|
1594
|
+
// Support - Array
|
1595
|
+
// ===============
|
1596
|
+
|
1597
|
+
//! Array type, similar to std::array<T, N>, with the possibility to use enums in operator[].
|
1598
|
+
//!
|
1599
|
+
//! \note The array has C semantics - the elements in the array are not initialized.
|
1600
|
+
template<typename T, size_t N>
|
1601
|
+
struct Array {
|
1602
|
+
//! \name Members
|
1603
|
+
//! \{
|
1604
|
+
|
1605
|
+
//! The underlying array data, use \ref data() to access it.
|
1606
|
+
T _data[N];
|
1607
|
+
|
1608
|
+
//! \}
|
1609
|
+
|
1610
|
+
//! \cond
|
1611
|
+
// std compatibility.
|
1612
|
+
typedef T value_type;
|
1613
|
+
typedef size_t size_type;
|
1614
|
+
typedef ptrdiff_t difference_type;
|
1615
|
+
|
1616
|
+
typedef value_type& reference;
|
1617
|
+
typedef const value_type& const_reference;
|
1618
|
+
|
1619
|
+
typedef value_type* pointer;
|
1620
|
+
typedef const value_type* const_pointer;
|
1621
|
+
|
1622
|
+
typedef pointer iterator;
|
1623
|
+
typedef const_pointer const_iterator;
|
1624
|
+
//! \endcond
|
1625
|
+
|
1626
|
+
//! \name Overloaded Operators
|
1627
|
+
//! \{
|
1628
|
+
|
1629
|
+
template<typename Index>
|
1630
|
+
inline T& operator[](const Index& index) noexcept {
|
1631
|
+
typedef typename Internal::StdInt<sizeof(Index), 1>::Type U;
|
1632
|
+
ASMJIT_ASSERT(U(index) < N);
|
1633
|
+
return _data[U(index)];
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
template<typename Index>
|
1637
|
+
inline const T& operator[](const Index& index) const noexcept {
|
1638
|
+
typedef typename Internal::StdInt<sizeof(Index), 1>::Type U;
|
1639
|
+
ASMJIT_ASSERT(U(index) < N);
|
1640
|
+
return _data[U(index)];
|
1641
|
+
}
|
1642
|
+
|
1643
|
+
inline bool operator==(const Array& other) const noexcept {
|
1644
|
+
for (size_t i = 0; i < N; i++)
|
1645
|
+
if (_data[i] != other._data[i])
|
1646
|
+
return false;
|
1647
|
+
return true;
|
1648
|
+
}
|
1649
|
+
|
1650
|
+
inline bool operator!=(const Array& other) const noexcept {
|
1651
|
+
return !operator==(other);
|
1652
|
+
}
|
1653
|
+
|
1654
|
+
//! \}
|
1655
|
+
|
1656
|
+
//! \name Accessors
|
1657
|
+
//! \{
|
1658
|
+
|
1659
|
+
inline bool empty() const noexcept { return false; }
|
1660
|
+
inline size_t size() const noexcept { return N; }
|
1661
|
+
|
1662
|
+
inline T* data() noexcept { return _data; }
|
1663
|
+
inline const T* data() const noexcept { return _data; }
|
1664
|
+
|
1665
|
+
inline T& front() noexcept { return _data[0]; }
|
1666
|
+
inline const T& front() const noexcept { return _data[0]; }
|
1667
|
+
|
1668
|
+
inline T& back() noexcept { return _data[N - 1]; }
|
1669
|
+
inline const T& back() const noexcept { return _data[N - 1]; }
|
1670
|
+
|
1671
|
+
inline T* begin() noexcept { return _data; }
|
1672
|
+
inline T* end() noexcept { return _data + N; }
|
1673
|
+
|
1674
|
+
inline const T* begin() const noexcept { return _data; }
|
1675
|
+
inline const T* end() const noexcept { return _data + N; }
|
1676
|
+
|
1677
|
+
inline const T* cbegin() const noexcept { return _data; }
|
1678
|
+
inline const T* cend() const noexcept { return _data + N; }
|
1679
|
+
|
1680
|
+
//! \}
|
1681
|
+
|
1682
|
+
//! \name Utilities
|
1683
|
+
//! \{
|
1684
|
+
|
1685
|
+
inline void swap(Array& other) noexcept {
|
1686
|
+
for (size_t i = 0; i < N; i++)
|
1687
|
+
std::swap(_data[i], other._data[i]);
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
inline void fill(const T& value) noexcept {
|
1691
|
+
for (size_t i = 0; i < N; i++)
|
1692
|
+
_data[i] = value;
|
1693
|
+
}
|
1694
|
+
|
1695
|
+
inline void copyFrom(const Array& other) noexcept {
|
1696
|
+
for (size_t i = 0; i < N; i++)
|
1697
|
+
_data[i] = other._data[i];
|
1698
|
+
}
|
1699
|
+
|
1700
|
+
template<typename Operator>
|
1701
|
+
inline void combine(const Array& other) noexcept {
|
1702
|
+
for (size_t i = 0; i < N; i++)
|
1703
|
+
_data[i] = Operator::op(_data[i], other._data[i]);
|
1704
|
+
}
|
1705
|
+
|
1706
|
+
template<typename Operator>
|
1707
|
+
inline T aggregate(T initialValue = T()) const noexcept {
|
1708
|
+
T value = initialValue;
|
1709
|
+
for (size_t i = 0; i < N; i++)
|
1710
|
+
value = Operator::op(value, _data[i]);
|
1711
|
+
return value;
|
1712
|
+
}
|
1713
|
+
|
1714
|
+
template<typename Fn>
|
1715
|
+
inline void forEach(Fn&& fn) noexcept {
|
1716
|
+
for (size_t i = 0; i < N; i++)
|
1717
|
+
fn(_data[i]);
|
1718
|
+
}
|
1719
|
+
//! \}
|
1720
|
+
};
|
1721
|
+
|
1722
|
+
// Support::Temporary
|
1723
|
+
// ==================
|
1724
|
+
|
1725
|
+
//! Used to pass a temporary buffer to:
|
1726
|
+
//!
|
1727
|
+
//! - Containers that use user-passed buffer as an initial storage (still can grow).
|
1728
|
+
//! - Zone allocator that would use the temporary buffer as a first block.
|
1729
|
+
struct Temporary {
|
1730
|
+
//! \name Members
|
1731
|
+
//! \{
|
1732
|
+
|
1733
|
+
void* _data;
|
1734
|
+
size_t _size;
|
1735
|
+
|
1736
|
+
//! \}
|
1737
|
+
|
1738
|
+
//! \name Construction & Destruction
|
1739
|
+
//! \{
|
1740
|
+
|
1741
|
+
inline constexpr Temporary(const Temporary& other) noexcept = default;
|
1742
|
+
inline constexpr Temporary(void* data, size_t size) noexcept
|
1743
|
+
: _data(data),
|
1744
|
+
_size(size) {}
|
1745
|
+
|
1746
|
+
//! \}
|
1747
|
+
|
1748
|
+
//! \name Overloaded Operators
|
1749
|
+
//! \{
|
1750
|
+
|
1751
|
+
inline Temporary& operator=(const Temporary& other) noexcept = default;
|
1752
|
+
|
1753
|
+
//! \}
|
1754
|
+
|
1755
|
+
//! \name Accessors
|
1756
|
+
//! \{
|
1757
|
+
|
1758
|
+
//! Returns the data storage.
|
1759
|
+
template<typename T = void>
|
1760
|
+
inline constexpr T* data() const noexcept { return static_cast<T*>(_data); }
|
1761
|
+
//! Returns the data storage size in bytes.
|
1762
|
+
inline constexpr size_t size() const noexcept { return _size; }
|
1763
|
+
|
1764
|
+
//! \}
|
1765
|
+
};
|
1766
|
+
|
1767
|
+
} // {Support}
|
1768
|
+
|
1769
|
+
//! \}
|
1770
|
+
|
1771
|
+
ASMJIT_END_NAMESPACE
|
1772
|
+
|
1773
|
+
#endif // ASMJIT_CORE_SUPPORT_H_INCLUDED
|