#ifndef HOARD_GEOMETRIC_SIZECLASS_H
#define HOARD_GEOMETRIC_SIZECLASS_H
#include <cmath>
#include <cstdlib>
#include <cassert>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wself-assign"
#endif
#include <heaplayers.h>
namespace Hoard {
template <size_t BaseNumerator,
size_t BaseDenominator,
size_t Value>
class ilog;
template <size_t BaseNumerator, size_t BaseDenominator>
class ilog<BaseNumerator, BaseDenominator, 1> {
public:
enum { VALUE = 0 };
};
template <size_t BaseNumerator,
size_t BaseDenominator,
size_t Value>
class ilog {
public:
enum { VALUE = 1 + ilog<BaseNumerator,
BaseDenominator,
(Value * BaseDenominator) / BaseNumerator>::VALUE };
};
template <size_t MaxOverhead = 20, size_t Alignment = 16> class GeometricSizeClass {
public:
GeometricSizeClass()
{
assert (test());
}
static int constexpr size2class (const size_t sz) {
int left = 0;
int right = NUM_SIZECLASSES - 1;
while (left < right) {
int mid = (left + right)/2;
if (c2s(mid) < sz) {
left = mid + 1;
} else {
right = mid;
}
}
assert (c2s(left) >= sz);
assert ((left == 0) || (c2s(left-1) < sz));
return left;
}
static size_t constexpr class2size (const int cl) {
return c2s (cl);
}
#if defined(__LP64__) || defined(_LP64) || defined(_WIN64) || defined(__x86_64__)
enum { MaxObjectSize = (1UL << 31) };
#else
enum { MaxObjectSize = (1UL << 25) };
#endif
private:
static bool constexpr test() {
for (size_t sz = Alignment; sz < 1048576; sz += Alignment) {
int cl = size2class (sz);
if (sz > class2size(cl)) {
assert (sz <= class2size(cl));
return false;
}
}
for (int cl = 0; cl < NUM_SIZECLASSES; cl++) {
size_t sz = class2size (cl);
if (cl != size2class(sz)) {
assert (cl == size2class(sz));
return false;
}
}
return true;
}
enum { NUM_SIZECLASSES = ilog<100+MaxOverhead,
100,
MaxObjectSize>::VALUE };
static unsigned long c2s (int cl) {
static size_t sizes[NUM_SIZECLASSES];
static bool init = createTable ((size_t *) sizes);
init = init;
return sizes[cl];
}
static bool createTable (size_t * sizes)
{
const double base =
(1.0 + (double) MaxOverhead / (double) 100.0);
size_t sz = Alignment;
for (int i = 0; i < NUM_SIZECLASSES; i++) {
sizes[i] = sz;
size_t newSz = (size_t) (floor ((double) base * (double) sz));
newSz = newSz - (HL::Modulo<Alignment>::mod (newSz));
while ((double) newSz / (double) sz < base) {
newSz += Alignment;
}
sz = newSz;
}
return true;
}
};
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif