This can be used to find what's taking up memory in the compiler. Here's an example of how to use it: ``` ./zig test ../lib/std/std.zig --cache off -fmem-report ``` And here's the output I get for this on x86_64-linux-gnu today: ``` Const: 6462833 items, 152 bytes each, total 936.84 MiB ConstGlobalRefs: 17236534 items, 24 bytes each, total 394.51 MiB ResetResult: 1698108 items, 160 bytes each, total 259.11 MiB ConstExprValue: 3118299 items, 80 bytes each, total 237.91 MiB EndExpr: 1345395 items, 168 bytes each, total 215.56 MiB Unknown_8: 27370821 items, 8 bytes each, total 208.82 MiB VarPtr: 1127866 items, 168 bytes each, total 180.70 MiB IrBasicBlock: 794834 items, 120 bytes each, total 90.96 MiB LoadPtr: 554024 items, 160 bytes each, total 84.54 MiB Unknown_64: 1245715 items, 64 bytes each, total 76.03 MiB Unknown_40: 1879218 items, 40 bytes each, total 71.69 MiB Unknown_72: 989117 items, 72 bytes each, total 67.92 MiB Return: 423783 items, 160 bytes each, total 64.66 MiB Unknown_168: 332480 items, 168 bytes each, total 53.27 MiB Unknown_152: 336890 items, 152 bytes each, total 48.84 MiB AddImplicitReturnType: 230819 items, 168 bytes each, total 36.98 MiB Br: 217835 items, 168 bytes each, total 34.90 MiB Unknown_184: 179529 items, 184 bytes each, total 31.50 MiB FieldPtr: 179388 items, 184 bytes each, total 31.48 MiB BinOp: 171004 items, 176 bytes each, total 28.70 MiB LoadPtrGen: 173287 items, 168 bytes each, total 27.76 MiB CondBr: 137864 items, 192 bytes each, total 25.24 MiB Unknown_720: 30918 items, 720 bytes each, total 21.23 MiB CallSrc: 99320 items, 216 bytes each, total 20.46 MiB Unknown_160: 129243 items, 160 bytes each, total 19.72 MiB Unknown_1: 19339456 items, 1 bytes each, total 18.44 MiB CheckStatementIsVoid: 119838 items, 160 bytes each, total 18.29 MiB Unknown_48: 371178 items, 48 bytes each, total 16.99 MiB TestComptime: 101443 items, 160 bytes each, total 15.48 MiB DeclVarSrc: 72578 items, 184 bytes each, total 12.74 MiB StorePtr: 72776 items, 176 bytes each, total 12.22 MiB ZigVar: 79201 items, 160 bytes each, total 12.09 MiB Unknown_16: 770643 items, 16 bytes each, total 11.76 MiB Phi: 60482 items, 184 bytes each, total 10.61 MiB TestErrSrc: 66177 items, 168 bytes each, total 10.60 MiB Unknown_240: 45164 items, 240 bytes each, total 10.34 MiB ElemPtr: 58232 items, 184 bytes each, total 10.22 MiB AllocaSrc: 60053 items, 176 bytes each, total 10.08 MiB CallGen: 44873 items, 224 bytes each, total 9.59 MiB SaveErrRetAddr: 63787 items, 152 bytes each, total 9.25 MiB Unknown_112: 82283 items, 112 bytes each, total 8.79 MiB AllocaGen: 51909 items, 176 bytes each, total 8.71 MiB Unknown_24: 373599 items, 24 bytes each, total 8.55 MiB ResultLocPeer: 113683 items, 72 bytes each, total 7.81 MiB DeclRef: 36343 items, 168 bytes each, total 5.82 MiB UnwrapErrPayload: 34603 items, 168 bytes each, total 5.54 MiB Ref: 33414 items, 168 bytes each, total 5.35 MiB Unknown_104: 53882 items, 104 bytes each, total 5.34 MiB DeclVarGen: 32540 items, 168 bytes each, total 5.21 MiB StructFieldPtr: 30449 items, 176 bytes each, total 5.11 MiB UnwrapErrCode: 31508 items, 168 bytes each, total 5.05 MiB Unknown_56: 90256 items, 56 bytes each, total 4.82 MiB SpillBegin: 28722 items, 168 bytes each, total 4.60 MiB SpillEnd: 28722 items, 160 bytes each, total 4.38 MiB ResultLocReturn: 64573 items, 48 bytes each, total 2.96 MiB PtrType: 14702 items, 184 bytes each, total 2.58 MiB SliceType: 15005 items, 176 bytes each, total 2.52 MiB Unknown_176: 13326 items, 176 bytes each, total 2.24 MiB RefGen: 12881 items, 168 bytes each, total 2.06 MiB UnOp: 12102 items, 176 bytes each, total 2.03 MiB SwitchBr: 9453 items, 200 bytes each, total 1.80 MiB TestErrGen: 11143 items, 160 bytes each, total 1.70 MiB Unknown_32: 52359 items, 32 bytes each, total 1.60 MiB CheckSwitchProngs: 9094 items, 184 bytes each, total 1.60 MiB TypeOf: 9259 items, 160 bytes each, total 1.41 MiB IntCast: 8772 items, 168 bytes each, total 1.41 MiB OptionalUnwrapPtr: 8755 items, 168 bytes each, total 1.40 MiB SwitchTarget: 9094 items, 160 bytes each, total 1.39 MiB Cast: 8198 items, 176 bytes each, total 1.38 MiB WidenOrShorten: 8448 items, 160 bytes each, total 1.29 MiB ErrorUnion: 7613 items, 176 bytes each, total 1.28 MiB SliceSrc: 6249 items, 192 bytes each, total 1.14 MiB ErrWrapCode: 7133 items, 168 bytes each, total 1.14 MiB TypeName: 7328 items, 160 bytes each, total 1.12 MiB ImplicitCast: 5480 items, 176 bytes each, total 941.88 KiB ResolveResult: 5638 items, 168 bytes each, total 924.98 KiB ResultLocInstruction: 22696 items, 40 bytes each, total 886.56 KiB BitCastSrc: 4947 items, 168 bytes each, total 811.62 KiB CompileErr: 5148 items, 160 bytes each, total 804.38 KiB ReturnPtr: 5305 items, 152 bytes each, total 787.46 KiB Unreachable: 5038 items, 152 bytes each, total 747.83 KiB TestNonNull: 4716 items, 160 bytes each, total 736.88 KiB BitCastGen: 4431 items, 160 bytes each, total 692.34 KiB PtrToInt: 4289 items, 160 bytes each, total 670.16 KiB SliceGen: 3573 items, 192 bytes each, total 669.94 KiB ArrayType: 4081 items, 168 bytes each, total 669.54 KiB IntType: 3868 items, 168 bytes each, total 634.59 KiB Unknown_88: 7213 items, 88 bytes each, total 619.87 KiB Truncate: 3771 items, 168 bytes each, total 618.68 KiB TypeInfo: 3740 items, 160 bytes each, total 584.38 KiB SwitchVar: 3385 items, 176 bytes each, total 581.80 KiB ContainerInitFields: 3223 items, 184 bytes each, total 579.13 KiB ContainerInitList: 2309 items, 192 bytes each, total 432.94 KiB PtrCastGen: 2626 items, 168 bytes each, total 430.83 KiB BoolNot: 2457 items, 160 bytes each, total 383.91 KiB FnProto: 2054 items, 184 bytes each, total 369.08 KiB MergeErrSets: 1927 items, 176 bytes each, total 331.20 KiB Unknown_136: 2486 items, 136 bytes each, total 330.17 KiB Unknown_80: 4059 items, 80 bytes each, total 317.11 KiB Bswap: 1670 items, 168 bytes each, total 273.98 KiB TypeId: 1680 items, 160 bytes each, total 262.50 KiB PtrCastSrc: 1371 items, 176 bytes each, total 235.64 KiB ErrName: 1193 items, 160 bytes each, total 186.41 KiB UnionTag: 1120 items, 160 bytes each, total 175.00 KiB TagName: 1050 items, 160 bytes each, total 164.06 KiB SizeOf: 942 items, 160 bytes each, total 147.19 KiB MemberName: 871 items, 168 bytes each, total 142.90 KiB Import: 881 items, 160 bytes each, total 137.66 KiB PtrOfArrayToSlice: 758 items, 168 bytes each, total 124.36 KiB UnionFieldPtr: 710 items, 176 bytes each, total 122.03 KiB EnumToInt: 778 items, 160 bytes each, total 121.56 KiB CheckRuntimeScope: 700 items, 168 bytes each, total 114.84 KiB FieldParentPtr: 632 items, 184 bytes each, total 113.56 KiB BoolToInt: 719 items, 160 bytes each, total 112.34 KiB ResultLocPeerParent: 904 items, 104 bytes each, total 91.81 KiB IntToPtr: 537 items, 168 bytes each, total 88.10 KiB AlignOf: 561 items, 160 bytes each, total 87.66 KiB AtomicRmw: 356 items, 208 bytes each, total 72.31 KiB MemberCount: 441 items, 160 bytes each, total 68.91 KiB Memset: 342 items, 176 bytes each, total 58.78 KiB PopCount: 321 items, 168 bytes each, total 52.66 KiB AlignCast: 251 items, 168 bytes each, total 41.18 KiB IrInstruction *: 5230 items, 8 bytes each, total 40.86 KiB IrBasicBlock *: 5230 items, 8 bytes each, total 40.86 KiB TagType: 261 items, 160 bytes each, total 40.78 KiB HasDecl: 234 items, 168 bytes each, total 38.39 KiB OverflowOp: 191 items, 200 bytes each, total 37.30 KiB Export: 209 items, 176 bytes each, total 35.92 KiB SetCold: 219 items, 160 bytes each, total 34.22 KiB ReturnAddress: 216 items, 152 bytes each, total 32.06 KiB FromBytes: 178 items, 176 bytes each, total 30.59 KiB SetRuntimeSafety: 188 items, 160 bytes each, total 29.38 KiB OptionalWrap: 151 items, 168 bytes each, total 24.77 KiB Clz: 143 items, 168 bytes each, total 23.46 KiB ResizeSlice: 135 items, 168 bytes each, total 22.15 KiB UnionInitNamedField: 106 items, 184 bytes each, total 19.05 KiB Panic: 102 items, 160 bytes each, total 15.94 KiB SwitchElseVar: 93 items, 168 bytes each, total 15.26 KiB ToBytes: 89 items, 168 bytes each, total 14.60 KiB IntToFloat: 78 items, 168 bytes each, total 12.80 KiB Unknown_4360: 3 items, 4360 bytes each, total 12.77 KiB ErrWrapPayload: 72 items, 168 bytes each, total 11.81 KiB FloatOp: 62 items, 176 bytes each, total 10.66 KiB FloatToInt: 47 items, 168 bytes each, total 7.71 KiB FloatCast: 46 items, 168 bytes each, total 7.55 KiB ErrToInt: 47 items, 160 bytes each, total 7.34 KiB Asm: 33 items, 216 bytes each, total 6.96 KiB ErrSetCast: 40 items, 168 bytes each, total 6.56 KiB Memcpy: 34 items, 176 bytes each, total 5.84 KiB AtomicLoad: 17 items, 184 bytes each, total 3.05 KiB AwaitSrc: 16 items, 168 bytes each, total 2.62 KiB Resume: 14 items, 160 bytes each, total 2.19 KiB AwaitGen: 12 items, 176 bytes each, total 2.06 KiB ArgType: 12 items, 168 bytes each, total 1.97 KiB AnyFrameType: 12 items, 160 bytes each, total 1.88 KiB SuspendFinish: 10 items, 160 bytes each, total 1.56 KiB SuspendBegin: 10 items, 160 bytes each, total 1.56 KiB Ctz: 9 items, 168 bytes each, total 1.48 KiB FrameHandle: 8 items, 152 bytes each, total 1.19 KiB SetEvalBranchQuota: 7 items, 160 bytes each, total 1.09 KiB AssertZero: 7 items, 160 bytes each, total 1.09 KiB UndeclaredIdent: 7 items, 160 bytes each, total 1.09 KiB CmpxchgSrc: 5 items, 216 bytes each, total 1.05 KiB CmpxchgGen: 5 items, 200 bytes each, total 1000.00 bytes IntToEnum: 4 items, 168 bytes each, total 672.00 bytes VectorType: 4 items, 168 bytes each, total 672.00 bytes ErrorReturnTrace: 2 items, 160 bytes each, total 320.00 bytes Breakpoint: 2 items, 152 bytes each, total 304.00 bytes FrameAddress: 2 items, 152 bytes each, total 304.00 bytes Unknown_4: 61 items, 4 bytes each, total 244.00 bytes VectorToArray: 1 items, 168 bytes each, total 168.00 bytes SetAlignStack: 1 items, 160 bytes each, total 160.00 bytes Unknown_12: 2 items, 12 bytes each, total 24.00 bytes ErrorTableEntry *: 0 items, 8 bytes each, total 0.00 bytes AstNode *: 0 items, 8 bytes each, total 0.00 bytes Total bytes used: 3.51 GiB ``` You can see that most of the memory is taken up by IR instructions, as well as comptime values. This points toward 2 changes which will greatly reduce memory usage: * Rework semantic analysis so that IR instructions can be freed. Currently the comptime value struct (ConstExprValue) is embedded directly into the IrInstruction struct. If this is made to be separate, at the very least pass 1 IR instructions can be freed. This includes `Const` which is the largest usage of memory currently. * Rework the ConstExprValue struct to no longer be a tagged union. For example, there's no need for an integer comptime value to be 80 bytes. From this you can also see that this eliminates some things from being the culprit. Before doing this analysis, I considered whether doing string interning would help. From the above output, you can see that all strings in the compiler account for only 18 MiB, so string interning would have been a dead end.
365 lines
8.9 KiB
C++
365 lines
8.9 KiB
C++
/*
|
|
* Copyright (c) 2015 Andrew Kelley
|
|
*
|
|
* This file is part of zig, which is MIT licensed.
|
|
* See http://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#ifndef ZIG_UTIL_HPP
|
|
#define ZIG_UTIL_HPP
|
|
|
|
#include "memory_profiling.hpp"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#include <intrin.h>
|
|
|
|
#define ATTRIBUTE_COLD __declspec(noinline)
|
|
#define ATTRIBUTE_PRINTF(a, b)
|
|
#define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
|
|
#define ATTRIBUTE_NORETURN __declspec(noreturn)
|
|
#define ATTRIBUTE_MUST_USE
|
|
|
|
#else
|
|
|
|
#define ATTRIBUTE_COLD __attribute__((cold))
|
|
#define ATTRIBUTE_PRINTF(a, b) __attribute__((format(printf, a, b)))
|
|
#define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
|
|
#define ATTRIBUTE_NORETURN __attribute__((noreturn))
|
|
#define ATTRIBUTE_MUST_USE __attribute__((warn_unused_result))
|
|
|
|
#endif
|
|
|
|
#include "softfloat.hpp"
|
|
|
|
#define BREAKPOINT __asm("int $0x03")
|
|
|
|
ATTRIBUTE_COLD
|
|
ATTRIBUTE_NORETURN
|
|
ATTRIBUTE_PRINTF(1, 2)
|
|
void zig_panic(const char *format, ...);
|
|
|
|
static inline void zig_assert(bool ok, const char *file, int line, const char *func) {
|
|
if (!ok) {
|
|
zig_panic("Assertion failed at %s:%d in %s. This is a bug in the Zig compiler.", file, line, func);
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#define __func__ __FUNCTION__
|
|
#endif
|
|
|
|
#define zig_unreachable() zig_panic("Unreachable at %s:%d in %s. This is a bug in the Zig compiler.", __FILE__, __LINE__, __func__)
|
|
|
|
// Assertions in stage1 are always on, and they call zig @panic.
|
|
#undef assert
|
|
#define assert(ok) zig_assert(ok, __FILE__, __LINE__, __func__)
|
|
|
|
#if defined(_MSC_VER)
|
|
static inline int clzll(unsigned long long mask) {
|
|
unsigned long lz;
|
|
#if defined(_WIN64)
|
|
if (_BitScanReverse64(&lz, mask))
|
|
return static_cast<int>(63 - lz);
|
|
zig_unreachable();
|
|
#else
|
|
if (_BitScanReverse(&lz, mask >> 32))
|
|
lz += 32;
|
|
else
|
|
_BitScanReverse(&lz, mask & 0xffffffff);
|
|
return 63 - lz;
|
|
#endif
|
|
}
|
|
static inline int ctzll(unsigned long long mask) {
|
|
unsigned long result;
|
|
#if defined(_WIN64)
|
|
if (_BitScanForward64(&result, mask))
|
|
return result;
|
|
zig_unreachable();
|
|
#else
|
|
if (_BitScanForward(&result, mask & 0xffffffff))
|
|
return result;
|
|
}
|
|
if (_BitScanForward(&result, mask >> 32))
|
|
return 32 + result;
|
|
zig_unreachable();
|
|
#endif
|
|
}
|
|
#else
|
|
#define clzll(x) __builtin_clzll(x)
|
|
#define ctzll(x) __builtin_ctzll(x)
|
|
#endif
|
|
|
|
|
|
template<typename T>
|
|
ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count, const char *name = nullptr) {
|
|
#ifdef ZIG_ENABLE_MEM_PROFILE
|
|
memprof_alloc(name, count, sizeof(T));
|
|
#endif
|
|
#ifndef NDEBUG
|
|
// make behavior when size == 0 portable
|
|
if (count == 0)
|
|
return nullptr;
|
|
#endif
|
|
T *ptr = reinterpret_cast<T*>(malloc(count * sizeof(T)));
|
|
if (!ptr)
|
|
zig_panic("allocation failed");
|
|
return ptr;
|
|
}
|
|
|
|
template<typename T>
|
|
ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count, const char *name = nullptr) {
|
|
#ifdef ZIG_ENABLE_MEM_PROFILE
|
|
memprof_alloc(name, count, sizeof(T));
|
|
#endif
|
|
#ifndef NDEBUG
|
|
// make behavior when size == 0 portable
|
|
if (count == 0)
|
|
return nullptr;
|
|
#endif
|
|
T *ptr = reinterpret_cast<T*>(calloc(count, sizeof(T)));
|
|
if (!ptr)
|
|
zig_panic("allocation failed");
|
|
return ptr;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T *reallocate(T *old, size_t old_count, size_t new_count, const char *name = nullptr) {
|
|
T *ptr = reallocate_nonzero(old, old_count, new_count);
|
|
if (new_count > old_count) {
|
|
memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count, const char *name = nullptr) {
|
|
#ifdef ZIG_ENABLE_MEM_PROFILE
|
|
memprof_dealloc(name, old_count, sizeof(T));
|
|
memprof_alloc(name, new_count, sizeof(T));
|
|
#endif
|
|
#ifndef NDEBUG
|
|
// make behavior when size == 0 portable
|
|
if (new_count == 0 && old == nullptr)
|
|
return nullptr;
|
|
#endif
|
|
T *ptr = reinterpret_cast<T*>(realloc(old, new_count * sizeof(T)));
|
|
if (!ptr)
|
|
zig_panic("allocation failed");
|
|
return ptr;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void deallocate(T *old, size_t count, const char *name = nullptr) {
|
|
#ifdef ZIG_ENABLE_MEM_PROFILE
|
|
memprof_dealloc(name, count, sizeof(T));
|
|
#endif
|
|
free(old);
|
|
}
|
|
|
|
template<typename T>
|
|
static inline void destroy(T *old, const char *name = nullptr) {
|
|
return deallocate(old, 1);
|
|
}
|
|
|
|
template <typename T, size_t n>
|
|
constexpr size_t array_length(const T (&)[n]) {
|
|
return n;
|
|
}
|
|
|
|
template <typename T>
|
|
static inline T max(T a, T b) {
|
|
return (a >= b) ? a : b;
|
|
}
|
|
|
|
template <typename T>
|
|
static inline T min(T a, T b) {
|
|
return (a <= b) ? a : b;
|
|
}
|
|
|
|
template<typename T>
|
|
static inline T clamp(T min_value, T value, T max_value) {
|
|
return max(min(value, max_value), min_value);
|
|
}
|
|
|
|
static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
|
|
if (a_len != b_len)
|
|
return false;
|
|
return memcmp(a_ptr, b_ptr, a_len) == 0;
|
|
}
|
|
static inline bool mem_eql_mem_ignore_case(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
|
|
if (a_len != b_len)
|
|
return false;
|
|
for (size_t i = 0; i < a_len; i += 1) {
|
|
if (tolower(a_ptr[i]) != tolower(b_ptr[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
|
|
return mem_eql_mem(mem, mem_len, str, strlen(str));
|
|
}
|
|
|
|
static inline bool is_power_of_2(uint64_t x) {
|
|
return x != 0 && ((x & (~x + 1)) == x);
|
|
}
|
|
|
|
static inline uint64_t round_to_next_power_of_2(uint64_t x) {
|
|
--x;
|
|
x |= x >> 1;
|
|
x |= x >> 2;
|
|
x |= x >> 4;
|
|
x |= x >> 8;
|
|
x |= x >> 16;
|
|
x |= x >> 32;
|
|
return x + 1;
|
|
}
|
|
|
|
uint32_t int_hash(int i);
|
|
bool int_eq(int a, int b);
|
|
uint32_t uint64_hash(uint64_t i);
|
|
bool uint64_eq(uint64_t a, uint64_t b);
|
|
uint32_t ptr_hash(const void *ptr);
|
|
bool ptr_eq(const void *a, const void *b);
|
|
|
|
static inline uint8_t log2_u64(uint64_t x) {
|
|
return (63 - clzll(x));
|
|
}
|
|
|
|
static inline float16_t zig_double_to_f16(double x) {
|
|
float64_t y;
|
|
static_assert(sizeof(x) == sizeof(y), "");
|
|
memcpy(&y, &x, sizeof(x));
|
|
return f64_to_f16(y);
|
|
}
|
|
|
|
|
|
// Return value is safe to coerce to float even when |x| is NaN or Infinity.
|
|
static inline double zig_f16_to_double(float16_t x) {
|
|
float64_t y = f16_to_f64(x);
|
|
double z;
|
|
static_assert(sizeof(y) == sizeof(z), "");
|
|
memcpy(&z, &y, sizeof(y));
|
|
return z;
|
|
}
|
|
|
|
void zig_pretty_print_bytes(FILE *f, double n);
|
|
|
|
template<typename T>
|
|
struct Optional {
|
|
T value;
|
|
bool is_some;
|
|
|
|
static inline Optional<T> some(T x) {
|
|
return {x, true};
|
|
}
|
|
|
|
static inline Optional<T> none() {
|
|
return {{}, false};
|
|
}
|
|
|
|
inline bool unwrap(T *res) {
|
|
*res = value;
|
|
return is_some;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct Slice {
|
|
T *ptr;
|
|
size_t len;
|
|
|
|
inline T &at(size_t i) {
|
|
assert(i < len);
|
|
return &ptr[i];
|
|
}
|
|
|
|
inline Slice<T> slice(size_t start, size_t end) {
|
|
assert(end <= len);
|
|
assert(end >= start);
|
|
return {
|
|
ptr + start,
|
|
end - start,
|
|
};
|
|
}
|
|
|
|
inline Slice<T> sliceFrom(size_t start) {
|
|
assert(start <= len);
|
|
return {
|
|
ptr + start,
|
|
len - start,
|
|
};
|
|
}
|
|
|
|
static inline Slice<T> alloc(size_t n) {
|
|
return {allocate_nonzero<T>(n), n};
|
|
}
|
|
};
|
|
|
|
template<typename T, size_t n>
|
|
struct Array {
|
|
static const size_t len = n;
|
|
T items[n];
|
|
|
|
inline Slice<T> slice() {
|
|
return {
|
|
&items[0],
|
|
len,
|
|
};
|
|
}
|
|
};
|
|
|
|
static inline Slice<uint8_t> str(const char *literal) {
|
|
return {(uint8_t*)(literal), strlen(literal)};
|
|
}
|
|
|
|
// Ported from std/mem.zig
|
|
template<typename T>
|
|
static inline bool memEql(Slice<T> a, Slice<T> b) {
|
|
if (a.len != b.len)
|
|
return false;
|
|
for (size_t i = 0; i < a.len; i += 1) {
|
|
if (a.ptr[i] != b.ptr[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Ported from std/mem.zig
|
|
template<typename T>
|
|
static inline bool memStartsWith(Slice<T> haystack, Slice<T> needle) {
|
|
if (needle.len > haystack.len)
|
|
return false;
|
|
return memEql(haystack.slice(0, needle.len), needle);
|
|
}
|
|
|
|
// Ported from std/mem.zig
|
|
template<typename T>
|
|
static inline void memCopy(Slice<T> dest, Slice<T> src) {
|
|
assert(dest.len >= src.len);
|
|
memcpy(dest.ptr, src.ptr, src.len * sizeof(T));
|
|
}
|
|
|
|
// Ported from std/mem.zig.
|
|
// Coordinate struct fields with memSplit function
|
|
struct SplitIterator {
|
|
size_t index;
|
|
Slice<uint8_t> buffer;
|
|
Slice<uint8_t> split_bytes;
|
|
};
|
|
|
|
bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
|
|
Optional< Slice<uint8_t> > SplitIterator_next(SplitIterator *self);
|
|
Optional< Slice<uint8_t> > SplitIterator_next_separate(SplitIterator *self);
|
|
Slice<uint8_t> SplitIterator_rest(SplitIterator *self);
|
|
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);
|
|
|
|
#endif
|