#ifndef HOARD_THRESHOLDHEAP_H
#define HOARD_THRESHOLDHEAP_H
#include <map>
#include <list>
#include "debugprint.h"
#include "heaplayers.h"
#include "mmapalloc.h"
using namespace std;
namespace Hoard {
template <int ThresholdMinWaste,
int ThresholdNumerator,
int ThresholdDenominator,
class SuperHeap>
class ThresholdHeap : public SuperHeap {
public:
enum { Alignment = SuperHeap::Alignment };
ThresholdHeap()
: _inUse (0),
_allocated (0),
_maxAllocated (0)
{}
inline void * malloc (size_t sz) {
void * ptr = _cache.remove(sz);
if (ptr == nullptr) {
ptr = SuperHeap::malloc (sz);
_allocated += SuperHeap::getSize(ptr);
if (_allocated > _maxAllocated) {
_maxAllocated = _allocated;
}
}
_inUse += SuperHeap::getSize(ptr);
assert (SuperHeap::getSize(ptr) >= sz);
assert ((size_t) ptr % Alignment == 0);
return ptr;
}
inline void free (void * ptr) {
size_t sz = SuperHeap::getSize(ptr);
DEBUG_PRINT3("freeing an object of size %d: inUse = %d, allocated = %d\n", sz, _inUse, _allocated);
_inUse -= sz;
_cache.add (sz, ptr);
while ((ThresholdMinWaste < (_allocated - _inUse)) &&
(ThresholdDenominator * (_allocated - _inUse) > ThresholdNumerator * _maxAllocated)) {
DEBUG_PRINT3("crossing threshold: inUse = %d, allocated = %d, max allocated = %d\n", _inUse, _allocated, _maxAllocated);
void * obj = _cache.removeLargest();
if (!obj) {
break;
}
size_t objSz = SuperHeap::getSize (obj);
DEBUG_PRINT1("found a big object in the cache of size %lu.\n", objSz);
DEBUG_PRINT3("Freeing %d: inUse = %d, allocated = %d\n", objSz, _inUse, _allocated);
_allocated -= objSz;
SuperHeap::free (obj);
}
DEBUG_PRINT("Threshold done.\n");
}
private:
class TopHeap : public SizeHeap<BumpAlloc<65536, MmapAlloc> > {
public:
#if 0#endif
};
class LocalHeap :
public ExactlyOneHeap<KingsleyHeap<AdaptHeap<DLList, TopHeap>, TopHeap> > {};
template <class K, class V>
class CacheHelper {
private:
typedef list<V, STLAllocator<V, LocalHeap> > listType;
typedef pair<const K, listType> mapObject;
typedef map<K, listType, less<K>, STLAllocator<mapObject, LocalHeap> > mapType;
mapType theMap;
public:
void add (K sz, V ptr) {
theMap[sz].push_front (ptr);
}
V remove (K sz) {
typename mapType::iterator i = theMap.find (sz);
if (i != theMap.end()) {
V ptr = theMap[sz].front();
theMap[sz].pop_front();
if (theMap[sz].empty()) {
theMap.erase (sz);
}
return ptr;
}
for (i = theMap.begin();
i != theMap.end();
++i) {
K key = (*i).first;
listType& theList = (*i).second;
if (key >= sz) {
V ptr = theList.front();
theList.pop_front();
if (theList.empty()) {
theMap.erase (key);
}
return ptr;
}
}
return nullptr;
}
V removeLargest() {
typename mapType::reverse_iterator i;
i = theMap.rbegin();
if (i != theMap.rend()) {
K key = (*i).first;
listType& theList = (*i).second;
V ptr = theList.front();
theList.pop_front();
if (theList.empty()) {
theMap.erase (key);
}
return ptr;
}
return nullptr;
}
};
class Cache : public CacheHelper<size_t, void *> {};
unsigned long _inUse;
unsigned long _allocated;
unsigned long _maxAllocated;
Cache _cache;
};
}
#endif