#pragma once
#include "bits.h"
#include "snmalloc/ds_core/defines.h"
#include "snmalloc/stl/array.h"
#include "snmalloc/stl/type_traits.h"
#include "snmalloc/stl/utility.h"
#include <stddef.h>
namespace snmalloc
{
template<size_t length, typename T>
class Mod
{
static_assert(bits::is_pow2(length), "Must be a power of two.");
private:
T value = 0;
public:
operator T()
{
return static_cast<T>(value & (length - 1));
}
Mod& operator=(const T v)
{
value = v;
return *this;
}
};
#ifdef SNMALLOC_CHECK_CLIENT
template<size_t length, typename T>
class ModArray
{
struct alignas(bits::next_pow2_const(sizeof(T))) TWrap
{
T v;
};
static constexpr size_t rlength = bits::next_pow2_const(length);
stl::Array<TWrap, rlength> array;
public:
constexpr const T& operator[](const size_t i) const
{
return array[i & (rlength - 1)].v;
}
constexpr T& operator[](const size_t i)
{
return array[i & (rlength - 1)].v;
}
};
#else
template<size_t length, typename T>
using ModArray = stl::Array<T, length>;
#endif
template<typename F>
class OnDestruct
{
F f;
public:
OnDestruct(F f) : f(f) {}
~OnDestruct()
{
f();
}
};
template<size_t BufferSize>
class MessageBuilder
{
stl::Array<char, BufferSize> buffer;
static constexpr size_t SafeLength = BufferSize - 1;
size_t insert = 0;
void append_char(char c)
{
if (insert < SafeLength)
{
buffer[insert++] = c;
}
}
template<size_t N>
void append(const char (&s)[N])
{
for (size_t i = 0; i < N - 1; i++)
{
append_char(s[i]);
}
}
#ifdef __CHERI_PURE_CAPABILITY__
void append(intptr_t v)
{
append(reinterpret_cast<void*>(v));
}
void append(uintptr_t v)
{
append(reinterpret_cast<void*>(v));
}
#endif
void append(decltype(nullptr))
{
append("(nullptr)");
}
void append(void* ptr)
{
if (ptr == nullptr)
{
append(nullptr);
return;
}
append(static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(ptr)));
}
void append(const char* ptr)
{
if (ptr == nullptr)
{
append(nullptr);
return;
}
while (char data = *ptr++)
{
append_char(data);
}
}
void append(long long s)
{
if (s < 0)
{
append_char('-');
s = 0 - s;
}
stl::Array<char, 20> buf{{0}};
const char digits[] = "0123456789";
for (long i = static_cast<long>(buf.size() - 1); i >= 0; i--)
{
buf[static_cast<size_t>(i)] = digits[s % 10];
s /= 10;
}
bool skipZero = true;
for (auto c : buf)
{
if (skipZero && (c == '0'))
{
continue;
}
skipZero = false;
append_char(c);
}
if (skipZero)
{
append_char('0');
}
}
void append(unsigned long long s)
{
append_char('0');
append_char('x');
stl::Array<char, 16> buf{{0}};
const char hexdigits[] = "0123456789abcdef";
static_assert(sizeof(hexdigits) == 0x11);
for (long i = static_cast<long>(buf.size() - 1); i >= 0; i--)
{
buf[static_cast<size_t>(i)] = hexdigits[s & 0xf];
s >>= 4;
}
bool skipZero = true;
for (auto c : buf)
{
if (skipZero && (c == '0'))
{
continue;
}
skipZero = false;
append_char(c);
}
if (skipZero)
{
append_char('0');
}
}
void append(long x)
{
append(static_cast<long long>(x));
}
void append(unsigned long x)
{
append(static_cast<unsigned long long>(x));
}
void append(int x)
{
append(static_cast<long long>(x));
}
void append(unsigned int x)
{
append(static_cast<unsigned long long>(x));
}
template<typename Head, typename... Tail>
SNMALLOC_FAST_PATH_INLINE void
append(const char* fmt, Head&& head, Tail&&... tail)
{
for (;;)
{
if (fmt[0] == '\0')
{
error("Internal error: format string missing `{}`!");
}
if (fmt[0] == '{' && fmt[1] == '}')
{
append(stl::forward<Head>(head));
return append(fmt + 2, stl::forward<Tail>(tail)...);
}
append_char(*fmt);
fmt++;
}
}
public:
template<typename... Args>
SNMALLOC_FAST_PATH MessageBuilder(const char* fmt, Args&&... args)
{
buffer[SafeLength] = 0;
append(fmt, stl::forward<Args>(args)...);
append_char('\0');
}
const char* get_message()
{
return buffer.data();
}
};
struct Empty
{};
}