List: Added support for neg,0,pos comparer for sorting.
List: Added support for neg,0,pos comparer for sorting.

#include <cinttypes> #include <cinttypes>
#include <cstdarg> #include <cstdarg>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <cwchar> #include <cwchar>
#include <functional> #include <functional>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <random> #include <random>
#include <memory> #include <memory>
   
typedef std::wstring wstring; typedef std::wstring wstring;
typedef std::string string; typedef std::string string;
   
typedef char c8; typedef char c8;
typedef char s8; typedef char s8;
typedef unsigned char u8; typedef unsigned char u8;
typedef wchar_t c16; typedef wchar_t c16;
   
const c8* _endl = "\n"; const c8* _endl = "\n";
const c16* _wendl = L"\n"; const c16* _wendl = L"\n";
   
typedef uint16_t u16; typedef uint16_t u16;
typedef int16_t s16; typedef int16_t s16;
typedef uint32_t u32; typedef uint32_t u32;
typedef int32_t s32; typedef int32_t s32;
typedef uint64_t u64; typedef uint64_t u64;
typedef int64_t s64; typedef int64_t s64;
   
typedef float f32; typedef float f32;
typedef double f64; typedef double f64;
typedef long double f80; typedef long double f80;
   
std::mt19937 rng; std::mt19937 rng;
std::mt19937_64 rng64; std::mt19937_64 rng64;
   
template<typename... params> template<typename... params>
wstring string_format( const wstring& format, params... args ) wstring string_format( const wstring& format, params... args )
{ {
size_t size = swprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' size_t size = swprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
std::unique_ptr<c16[]> buf( new c16[ size ] ); std::unique_ptr<c16[]> buf( new c16[ size ] );
swprintf( buf.get(), size, format.c_str(), args ... ); swprintf( buf.get(), size, format.c_str(), args ... );
return wstring( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside return wstring( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
} }
   
template<typename ... params> template<typename ... params>
string string_format( const std::string& format, params... args ) string string_format( const std::string& format, params... args )
{ {
size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
std::unique_ptr<c8[]> buf( new c8[ size ] ); std::unique_ptr<c8[]> buf( new c8[ size ] );
snprintf( buf.get(), size, format.c_str(), args ... ); snprintf( buf.get(), size, format.c_str(), args ... );
return string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside return string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
} }
   
void printline() { void printline() {
printf(_endl); printf(_endl);
} }
   
template<typename... params> template<typename... params>
void printline(const c8* format, params... args) { void printline(const c8* format, params... args) {
auto s = string_format(format, args ...); auto s = string_format(format, args ...);
   
std::cout << s << _endl; std::cout << s << _endl;
} }
   
template<typename... params> template<typename... params>
void printline(const c16* format, params... args) { void printline(const c16* format, params... args) {
auto s = string_format(format, args ...); auto s = string_format(format, args ...);
   
std::wcout << s << _wendl; std::wcout << s << _wendl;
} }
   
template<typename T> template<typename T>
void printline(T& arg) { void printline(T& arg) {
std::cout << arg << _endl; std::cout << arg << _endl;
} }
   
template<typename T> template<typename T>
void printline(T arg) { void printline(T arg) {
std::cout << arg << _endl; std::cout << arg << _endl;
} }
   
template<typename T> template<typename T>
void print_array(T* ar, u32 len) void print_array(T* ar, u32 len)
{ {
std::cout << "["; std::cout << "[";
for (u32 i = 0; i < len; i++) for (u32 i = 0; i < len; i++)
{ {
if (i != 0) { if (i != 0) {
std::cout << ", "; std::cout << ", ";
} }
   
std::cout << *(ar++); std::cout << *(ar++);
} }
   
std::cout << "]" << _endl; std::cout << "]" << _endl;
} }
   
template<typename... params> template<typename... params>
void die(s32 status, string message, params... args) { void die(s32 status, string message, params... args) {
if (message.length() > 0) if (message.length() > 0)
{ {
fprintf(stderr, string_format(message, args...).c_str()); fprintf(stderr, string_format(message, args...).c_str());
} }
   
exit(status); exit(status);
} }
   
template<typename... params> template<typename... params>
void die(s32 status, wstring message, params... args) { void die(s32 status, wstring message, params... args) {
if (message.length() > 0) if (message.length() > 0)
{ {
fwprintf(stderr, string_format(message, args...).c_str()); fwprintf(stderr, string_format(message, args...).c_str());
} }
   
exit(status); exit(status);
} }
   
void random_seed(u64 seed) { void random_seed(u64 seed) {
rng64.seed(seed); rng64.seed(seed);
} }
   
u64 random_long() { u64 random_long() {
return rng64(); return rng64();
} }
   
u32 random_int() { u32 random_int() {
return (u32)(rng64() >> 32); return (u32)(rng64() >> 32);
} }
   
u16 random_short() { u16 random_short() {
return (u16)(rng64() >> 48); return (u16)(rng64() >> 48);
} }
   
  u8 random_char() {
  return (u8)(rng64() >> 56);
  }
   
// Produces a random integer in the range [range_min..range_max). // Produces a random integer in the range [range_min..range_max).
s64 random_range(s64 range_min, s64 range_max) { s64 random_range(s64 range_min, s64 range_max) {
s64 width = range_max - range_min; s64 width = range_max - range_min;
   
s64 num = rng64(); s64 num = rng64();
   
num %= width; num %= width;
   
num += range_min; num += range_min;
   
if (num < range_min) { if (num < range_min) {
num += width; num += width;
} }
   
return num; return num;
} }
   
// List type valid up to 65536 members. // List type valid up to lots and lots of members.
template <typename T> template <typename T>
struct List { struct List {
private: private:
static bool gtFunc(T l, T r) {  
return l > r;  
}  
   
static bool ltFunc(T l, T r) {  
return l < r;  
}  
   
static s8 default_comparer(T l, T r) { static s8 default_comparer(T l, T r) {
if (l < r) { if (l < r) {
return -1; return -1;
} }
else if (l > r) { else if (l > r) {
return 1; return 1;
} }
else { else {
return 0; return 0;
} }
} }
   
u32 ITEMS_PER_BUCKET; u32 ITEMS_PER_BUCKET;
u32 MAX_BUCKETS; u32 MAX_BUCKETS;
   
T** buckets; T** buckets;
   
u32 bucketCount; u32 bucketCount;
u64 itemCount; u64 itemCount;
   
T** BucketPtr(u32 idx) { T** BucketPtr(u32 idx) {
if (idx >= bucketCount) { if (idx >= bucketCount) {
die(1, "Tried to access a list bucket with an index '%u' greater than the current count '%u'.", idx, bucketCount); die(1, "Tried to access a list bucket with an index '%u' greater than the current count '%u'.", idx, bucketCount);
} }
   
return buckets + idx; return buckets + idx;
} }
   
T* GetBucket(u32 idx) { T* GetBucket(u32 idx) {
return *BucketPtr(idx); return *BucketPtr(idx);
} }
   
void AddBucket() { void AddBucket() {
u32 bucketIdx = bucketCount; u32 bucketIdx = bucketCount;
bucketCount++; bucketCount++;
   
*BucketPtr(bucketIdx) = (T*)malloc(sizeof(T) * ITEMS_PER_BUCKET); *BucketPtr(bucketIdx) = (T*)malloc(sizeof(T) * ITEMS_PER_BUCKET);
} }
   
s64 qs_partition(u64 ltIdx, u64 rtIdx, u64 pvtIdx, bool (*comp_func)(T, T)) { s64 qs_partition(u64 ltIdx, u64 rtIdx, u64 pvtIdx, s8 (*comp_func)(T, T), bool reversed) {
// Fetch the value of the pivot point. // Fetch the value of the pivot point.
T pvtVal = GetItem(pvtIdx); T pvtVal = GetItem(pvtIdx);
   
T swap1, swap2; T swap1, swap2;
// Swap the pivot point to the right-most index in the partition. // Swap the pivot point to the right-most index in the partition.
swap1 = GetItem(rtIdx); swap1 = GetItem(rtIdx);
swap2 = GetItem(pvtIdx); swap2 = GetItem(pvtIdx);
   
SetItem(pvtIdx, swap1); SetItem(pvtIdx, swap1);
SetItem(rtIdx, swap2); SetItem(rtIdx, swap2);
   
// Store the left-most index in the partition; later we'll increment this as we // Store the left-most index in the partition; later we'll increment this as we
// swap values left of the pivot. // swap values left of the pivot.
u64 strIdx = ltIdx; u64 strIdx = ltIdx;
   
for (u64 idx = ltIdx; idx < rtIdx; idx++) { for (u64 idx = ltIdx; idx < rtIdx; idx++) {
// s8 result = (*comp_func)(GetItem(idx), pvtVal);
if ((*comp_func)(GetItem(idx), pvtVal)) { if ((!reversed && result < 0) || (reversed && result > 0)) {
swap1 = GetItem(strIdx); swap1 = GetItem(strIdx);
swap2 = GetItem(idx); swap2 = GetItem(idx);
   
SetItem(idx, swap1); SetItem(idx, swap1);
SetItem(strIdx, swap2); SetItem(strIdx, swap2);
   
strIdx++; strIdx++;
} }
} }
   
swap1 = GetItem(rtIdx); swap1 = GetItem(rtIdx);
swap2 = GetItem(strIdx); swap2 = GetItem(strIdx);
   
SetItem(strIdx, swap1); SetItem(strIdx, swap1);
SetItem(rtIdx, swap2); SetItem(rtIdx, swap2);
   
return strIdx; return strIdx;
} }
   
void qs_region(u64 ltIdx, u64 rtIdx, bool (*comp_func)(T, T)) { void qs_region(u64 ltIdx, u64 rtIdx, s8 (*comp_func)(T, T), bool reversed) {
if (ltIdx < rtIdx && rtIdx < Count()) { if (ltIdx < rtIdx && rtIdx < Count()) {
// Select a random pivot point between ltIdx and rtIdx. The location is not important, // Select a random pivot point between ltIdx and rtIdx. The location is not important,
// and picking randomly may provide speedup in some cases. // and picking randomly may provide speedup in some cases.
u64 pvtIdx = random_range(ltIdx, rtIdx); u64 pvtIdx = random_range(ltIdx, rtIdx);
   
// L"Sift" the array around the pivot value, and record its new location. // L"Sift" the array around the pivot value, and record its new location.
s64 newIdx = qs_partition(ltIdx, rtIdx, pvtIdx, comp_func); s64 newIdx = qs_partition(ltIdx, rtIdx, pvtIdx, comp_func, reversed);
   
// Since the L"sifted" regions are not sorted, sort them. // Since the L"sifted" regions are not sorted, sort them.
qs_region(ltIdx, newIdx - 1, comp_func); qs_region(ltIdx, newIdx - 1, comp_func, reversed);
qs_region(newIdx + 1, rtIdx, comp_func); qs_region(newIdx + 1, rtIdx, comp_func, reversed);
} }
} }
   
public: public:
static const u32 DEFAULT_ITEMS_PER_BUCKET = 256; static const u32 DEFAULT_ITEMS_PER_BUCKET = 256;
static const u32 DEFAULT_MAX_BUCKETS = 256; static const u32 DEFAULT_MAX_BUCKETS = 256;
   
bool (*comparer)(T, T); s8 (*comparer)(T, T);
   
u64 CurrentCapacity() { u64 CurrentCapacity() {
return (u64)ITEMS_PER_BUCKET * (u64)bucketCount; return (u64)ITEMS_PER_BUCKET * (u64)bucketCount;
} }
   
u64 MaxCapacity() { u64 MaxCapacity() {
return (u64)ITEMS_PER_BUCKET * (u64)MAX_BUCKETS; return (u64)ITEMS_PER_BUCKET * (u64)MAX_BUCKETS;
} }
   
u64 Count() { u64 Count() {
return itemCount; return itemCount;
} }
   
T* ItemPtr(u64 idx) { T* ItemPtr(u64 idx) {
if (idx >= MaxCapacity()) { if (idx >= MaxCapacity()) {
die(1, "Tried to access List item with index '%u' >= maximum capacity '%llu'.", idx, MaxCapacity()); die(1, "Tried to access List item with index '%u' >= maximum capacity '%llu'.", idx, MaxCapacity());
} }
if (idx >= itemCount) { if (idx >= itemCount) {
die(1, "Tried to access List item with index '%u' >= current count '%llu'.", idx, Count()); die(1, "Tried to access List item with index '%u' >= current count '%llu'.", idx, Count());
} }
   
u32 arIdx = (u32)(idx / ITEMS_PER_BUCKET); u32 arIdx = (u32)(idx / ITEMS_PER_BUCKET);
u32 lfIdx = (u32)(idx % ITEMS_PER_BUCKET); u32 lfIdx = (u32)(idx % ITEMS_PER_BUCKET);
   
return GetBucket(arIdx) + lfIdx; return GetBucket(arIdx) + lfIdx;
} }
   
T& Item(u32 idx) { T& Item(u32 idx) {
return *ItemPtr(idx); return *ItemPtr(idx);
} }
   
T GetItem(u32 idx) { T GetItem(u32 idx) {
return *ItemPtr(idx); return *ItemPtr(idx);
} }
   
T& operator[] (u32 idx) { T& operator[] (u32 idx) {
return Item(idx); return Item(idx);
} }
   
void SetItem(u32 idx, T value) { void SetItem(u32 idx, T value) {
*ItemPtr(idx) = value; *ItemPtr(idx) = value;
} }
   
void AddItem(T value) { void AddItem(T value) {
u32 idx = itemCount; u32 idx = itemCount;
itemCount++; itemCount++;
   
if (itemCount > ITEMS_PER_BUCKET * bucketCount) { if (itemCount > ITEMS_PER_BUCKET * bucketCount) {
AddBucket(); AddBucket();
} }
   
*ItemPtr(idx) = value; *ItemPtr(idx) = value;
} }
   
void RemoveAt(u32 idx) { void RemoveAt(u32 idx) {
u32* itemPtr = ItemPtr(idx); u32* itemPtr = ItemPtr(idx);
   
u32 arIdx = (u32)(idx / ITEMS_PER_BUCKET); u32 arIdx = (u32)(idx / ITEMS_PER_BUCKET);
u32 lfIdx = (u32)(idx % ITEMS_PER_BUCKET); u32 lfIdx = (u32)(idx % ITEMS_PER_BUCKET);
   
u32 rem_in_bucket = ITEMS_PER_BUCKET - lfIdx - 1; u32 rem_in_bucket = ITEMS_PER_BUCKET - lfIdx - 1;
   
// First we need to condense this bucket. // First we need to condense this bucket.
if (rem_in_bucket > 0) { if (rem_in_bucket > 0) {
memmove(itemPtr, itemPtr + 1, rem_in_bucket * sizeof(T)); memmove(itemPtr, itemPtr + 1, rem_in_bucket * sizeof(T));
} }
T* endOfLastBucket = GetBucket(arIdx) + ITEMS_PER_BUCKET - 1; T* endOfLastBucket = GetBucket(arIdx) + ITEMS_PER_BUCKET - 1;
T* startOfBucket; T* startOfBucket;
// Next, if there are any buckets left, we need to grab their first item and then // Next, if there are any buckets left, we need to grab their first item and then
// shift them to the left. // shift them to the left.
while (++arIdx < MAX_BUCKETS) { while (++arIdx < MAX_BUCKETS) {
startOfBucket = GetBucket(arIdx); startOfBucket = GetBucket(arIdx);
*endOfLastBucket = *startOfBucket; *endOfLastBucket = *startOfBucket;
memmove(startOfBucket, startOfBucket + 1, sizeof(T) * (ITEMS_PER_BUCKET - 1)); memmove(startOfBucket, startOfBucket + 1, sizeof(T) * (ITEMS_PER_BUCKET - 1));
endOfLastBucket = GetBucket(arIdx) + ITEMS_PER_BUCKET - 1; endOfLastBucket = GetBucket(arIdx) + ITEMS_PER_BUCKET - 1;
} }
itemCount--; itemCount--;
} }
   
u64 IndexOf(T item) { u64 IndexOf(T item) {
u64 idx = 0; u64 idx = 0;
do do
{ {
if (this->Item(idx) == item) { if (this->Item(idx) == item) {
break; break;
} }
} while (++idx < Count()); } while (++idx < Count());
   
return idx; return idx;
} }
   
bool TryGetIndexOf(T item, u64* idx) bool TryGetIndexOf(T item, u64* idx)
{ {
*idx = IndexOf(item); *idx = IndexOf(item);
   
return *idx < Count(); return *idx < Count();
} }
   
bool IsSorted(bool (*comp_func)(T, T)) { bool IsSorted(s8 (*comp_func)(T, T), bool reversed) {
T first = GetItem(0); T first = GetItem(0);
for (u32 idx = 1; idx < Count(); idx++) { for (u32 idx = 1; idx < Count(); idx++) {
if ((*comp_func)(GetItem(idx), first)) { s8 result = (*comp_func)(GetItem(idx), first);
  if (reversed && result > 0) {
return false; return false;
} }
  else if (!reversed && result < 0) {
  return false;
  }
} }
   
return true; return true;
} }
   
bool IsSorted(bool reversed) { bool IsSorted(bool reversed) {
if (reversed) { return IsSorted(comparer, reversed);
return IsSorted(&gtFunc);  
}  
else {  
return IsSorted(&ltFunc);  
}  
} }
   
bool IsSorted() { bool IsSorted() {
return IsSorted(false); return IsSorted(comparer, false);
} }
   
void Sort(bool (*comp_func)(T, T)) void Sort(s8 (*comp_func)(T, T), bool reversed)
{ {
qs_region(0, Count() - 1, comp_func); qs_region(0, Count() - 1, comp_func, reversed);
} }
   
void Sort(bool reversed) { void Sort(bool reversed) {
if (reversed) { Sort(comparer, reversed);
Sort(&gtFunc);  
}  
else {  
Sort(&ltFunc);  
}  
} }
   
void Sort() { void Sort() {
Sort(false); Sort(false);
} }
   
void PrintEachBucket() { void PrintEachBucket() {
u64 printed_items = 0; u64 printed_items = 0;
for (u32 idx = 0; idx < bucketCount; idx++) { for (u32 idx = 0; idx < bucketCount; idx++) {
print_array(GetBucket(idx), std::min((u64)ITEMS_PER_BUCKET, itemCount - printed_items)); print_array(GetBucket(idx), std::min((u64)ITEMS_PER_BUCKET, itemCount - printed_items));
printed_items += ITEMS_PER_BUCKET; printed_items += ITEMS_PER_BUCKET;
} }
} }
   
u64 SizeOf() { u64 SizeOf() {
return sizeof(T) * bucketCount * ITEMS_PER_BUCKET; return sizeof(T) * bucketCount * ITEMS_PER_BUCKET;
} }
   
void Clear() { void Clear() {
for (u32 bIdx = 0; bIdx < bucketCount; bIdx++) { for (u32 bIdx = 0; bIdx < bucketCount; bIdx++) {
T* bucket = GetBucket(bIdx); T* bucket = GetBucket(bIdx);
if (bucket) { if (bucket) {
free(bucket); free(bucket);
} }
} }
   
bucketCount = 0; bucketCount = 0;
itemCount = 0; itemCount = 0;
} }
   
List(u32 max_buckets, u32 items_per_bucket) : List(u32 max_buckets, u32 items_per_bucket) :
ITEMS_PER_BUCKET(items_per_bucket), ITEMS_PER_BUCKET(items_per_bucket),
MAX_BUCKETS(max_buckets), MAX_BUCKETS(max_buckets),
bucketCount(0), bucketCount(0),
itemCount(0), itemCount(0),
comparer(&ltFunc) comparer(&default_comparer)
{ {
buckets = (T**)malloc(sizeof(T*) * MAX_BUCKETS); buckets = (T**)malloc(sizeof(T*) * MAX_BUCKETS);
} }
   
List() : List(DEFAULT_MAX_BUCKETS, DEFAULT_ITEMS_PER_BUCKET) {} List() : List(DEFAULT_MAX_BUCKETS, DEFAULT_ITEMS_PER_BUCKET) {}
   
List(u64 capacity, bool contiguous_small_list) : bucketCount(0), itemCount(0), comparer(&ltFunc) { List(u64 capacity, bool contiguous_small_list) : bucketCount(0), itemCount(0), comparer(&default_comparer) {
if (capacity > 0xfffffffe00000001) if (capacity > 0xfffffffe00000001)
{ {
capacity = 0xfffffffe00000001; capacity = 0xfffffffe00000001;
} }
   
double bit_width = std::log2(capacity); double bit_width = std::log2(capacity);
   
u32 items_per_bucket, max_buckets; u32 items_per_bucket, max_buckets;
   
if (bit_width > 62) if (bit_width > 62)
{ {
max_buckets = 0xffffffff; max_buckets = 0xffffffff;
} }
else else
{ {
if (contiguous_small_list && bit_width < 32) if (contiguous_small_list && bit_width < 32)
{ {
max_buckets = 1; max_buckets = 1;
} }
else if (bit_width < 8) else if (bit_width < 8)
{ {
max_buckets = 1; max_buckets = 1;
} }
else if (bit_width < 12) else if (bit_width < 12)
{ {
max_buckets = 1 << 4; max_buckets = 1 << 4;
} }
else if (bit_width < 40) else if (bit_width < 40)
{ {
max_buckets = 1ull << 8; max_buckets = 1ull << 8;
} }
else if (bit_width < 46) else if (bit_width < 46)
{ {
max_buckets = 1ull << 14; max_buckets = 1ull << 14;
} }
else if (bit_width < 56) else if (bit_width < 56)
{ {
max_buckets = 1ull << 24; max_buckets = 1ull << 24;
} }
else else
{ {
max_buckets = 1ull << ((u64)ceil(bit_width) / 2ull); max_buckets = 1ull << ((u64)ceil(bit_width) / 2ull);
} }
} }
   
items_per_bucket = (u32)(capacity / (u64)max_buckets); items_per_bucket = (u32)(capacity / (u64)max_buckets);
   
u64 real_capacity = (u64)max_buckets * (u64)items_per_bucket; u64 real_capacity = (u64)max_buckets * (u64)items_per_bucket;
   
if (real_capacity < capacity && items_per_bucket < 0xffffffff) { if (real_capacity < capacity && items_per_bucket < 0xffffffff) {
items_per_bucket++; items_per_bucket++;
real_capacity = (u64)max_buckets * (u64)items_per_bucket; real_capacity = (u64)max_buckets * (u64)items_per_bucket;
} }
   
MAX_BUCKETS = max_buckets; MAX_BUCKETS = max_buckets;
ITEMS_PER_BUCKET = items_per_bucket; ITEMS_PER_BUCKET = items_per_bucket;
   
buckets = (T**)malloc(sizeof(T*) * MAX_BUCKETS); buckets = (T**)malloc(sizeof(T*) * MAX_BUCKETS);
   
if (contiguous_small_list && capacity < (1ull << 32)) if (contiguous_small_list && capacity < (1ull << 32))
{ {
AddBucket(); AddBucket();
itemCount = items_per_bucket; itemCount = items_per_bucket;
} }
} }
   
~List() { ~List() {
Clear(); Clear();
free(buckets); free(buckets);
} }
}; };
   
typedef std::function<void()> Callback; typedef std::function<void()> Callback;
typedef Callback* CallbackPtr; typedef Callback* CallbackPtr;
   
Callback* make_callback(Callback cb) { Callback* make_callback(Callback cb) {
return new std::function<void()> (cb); return new std::function<void()> (cb);
} }
   
struct VacuumCleaner { struct VacuumCleaner {
private: private:
List<CallbackPtr> cleanup_tasks; List<CallbackPtr> cleanup_tasks;
   
public: public:
enum FreeMethod : u8 { enum FreeMethod : u8 {
FREE, FREE,
DELETE DELETE
}; };
   
template <typename T> template <typename T>
void AddItem(T* item, FreeMethod method) { void AddItem(T* item, FreeMethod method) {
Callback* callback; Callback* callback;
   
switch(method) { switch(method) {
case DELETE: case DELETE:
callback = make_callback([item]() { callback = make_callback([item]() {
delete item; delete item;
}); });
break; break;
case FREE: case FREE:
default: default:
callback = make_callback([item]() { callback = make_callback([item]() {
free(item); free(item);
}); });
break; break;
   
} }
   
cleanup_tasks.AddItem(callback); cleanup_tasks.AddItem(callback);
} }
template<typename T> template<typename T>
void AddItem(T* item) { void AddItem(T* item) {
AddItem(item, FREE); AddItem(item, FREE);
} }
   
void Clean() { void Clean() {
for (u32 idx = 0; idx < cleanup_tasks.Count(); idx++) { for (u32 idx = 0; idx < cleanup_tasks.Count(); idx++) {
CallbackPtr cb = cleanup_tasks.GetItem(idx); CallbackPtr cb = cleanup_tasks.GetItem(idx);
   
(*cb)(); (*cb)();
if (cb) { if (cb) {
delete cb; delete cb;
} }
} }
   
cleanup_tasks.Clear(); cleanup_tasks.Clear();
} }
   
VacuumCleaner() : cleanup_tasks(List<CallbackPtr>()) {} VacuumCleaner() : cleanup_tasks(List<CallbackPtr>()) {}
   
~VacuumCleaner() { ~VacuumCleaner() {
Clean(); Clean();
} }
}; };