Files
snmalloc/src/ds/helpers.h
2020-03-04 16:57:44 +00:00

105 lines
2.1 KiB
C++

#pragma once
#include "bits.h"
#include "flaglock.h"
namespace snmalloc
{
/*
* In some use cases we need to run before any of the C++ runtime has been
* initialised. This singleton class is designed to not depend on the
* runtime.
*/
template<class Object, Object init() noexcept>
class Singleton
{
public:
/**
* If argument is non-null, then it is assigned the value
* true, if this is the first call to get.
* At most one call will be first.
*/
inline static Object& get(bool* first = nullptr)
{
static std::atomic_flag flag;
static std::atomic<bool> initialised;
static Object obj;
// If defined should be initially false;
SNMALLOC_ASSERT(first == nullptr || *first == false);
if (unlikely(!initialised.load(std::memory_order_acquire)))
{
FlagLock lock(flag);
if (!initialised)
{
obj = init();
initialised.store(true, std::memory_order_release);
if (first != nullptr)
*first = true;
}
}
return obj;
}
};
/**
* Wrapper for wrapping values.
*
* Wraps on read. This allows code to trust the value is in range, even when
* there is a memory corruption.
**/
template<size_t length, typename T>
class Mod
{
static_assert(
length == bits::next_pow2_const(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;
}
};
template<size_t length, typename T>
class ModArray
{
static constexpr size_t rlength = bits::next_pow2_const(length);
T array[rlength];
public:
constexpr const T& operator[](const size_t i) const
{
return array[i & (rlength - 1)];
}
constexpr T& operator[](const size_t i)
{
return array[i & (rlength - 1)];
}
};
/**
* Helper class to execute a specified function on destruction.
*/
template<void f()>
class OnDestruct
{
public:
~OnDestruct()
{
f();
}
};
} // namespace snmalloc