2021-10-29 16:25:12 -04:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "Luau/Common.h"
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
void* pagedAllocate(size_t size);
|
|
|
|
void pagedDeallocate(void* ptr);
|
|
|
|
void pagedFreeze(void* ptr, size_t size);
|
|
|
|
void pagedUnfreeze(void* ptr, size_t size);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class TypedAllocator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TypedAllocator()
|
|
|
|
{
|
2022-02-03 18:09:37 -05:00
|
|
|
currentBlockSize = kBlockSize;
|
2021-10-29 16:25:12 -04:00
|
|
|
}
|
|
|
|
|
2022-06-03 16:32:20 -04:00
|
|
|
TypedAllocator(const TypedAllocator&) = delete;
|
|
|
|
TypedAllocator& operator=(const TypedAllocator&) = delete;
|
|
|
|
|
|
|
|
TypedAllocator(TypedAllocator&&) = default;
|
|
|
|
TypedAllocator& operator=(TypedAllocator&&) = default;
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
~TypedAllocator()
|
|
|
|
{
|
|
|
|
if (frozen)
|
|
|
|
unfreeze();
|
|
|
|
free();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
T* allocate(Args&&... args)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(!frozen);
|
|
|
|
|
|
|
|
if (currentBlockSize >= kBlockSize)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(currentBlockSize == kBlockSize);
|
|
|
|
appendBlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
T* block = stuff.back();
|
|
|
|
T* res = block + currentBlockSize;
|
|
|
|
new (res) T(std::forward<Args&&...>(args...));
|
|
|
|
++currentBlockSize;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool contains(const T* ptr) const
|
|
|
|
{
|
|
|
|
for (T* block : stuff)
|
|
|
|
if (ptr >= block && ptr < block + kBlockSize)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const
|
|
|
|
{
|
2022-02-03 18:09:37 -05:00
|
|
|
return stuff.empty();
|
2021-10-29 16:25:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const
|
|
|
|
{
|
2022-02-03 18:09:37 -05:00
|
|
|
return stuff.empty() ? 0 : kBlockSize * (stuff.size() - 1) + currentBlockSize;
|
2021-10-29 16:25:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
if (frozen)
|
|
|
|
unfreeze();
|
|
|
|
free();
|
2022-01-06 17:10:07 -05:00
|
|
|
|
2022-02-03 18:09:37 -05:00
|
|
|
currentBlockSize = kBlockSize;
|
2021-10-29 16:25:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void freeze()
|
|
|
|
{
|
|
|
|
for (T* block : stuff)
|
|
|
|
pagedFreeze(block, kBlockSizeBytes);
|
|
|
|
frozen = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void unfreeze()
|
|
|
|
{
|
|
|
|
for (T* block : stuff)
|
|
|
|
pagedUnfreeze(block, kBlockSizeBytes);
|
|
|
|
frozen = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isFrozen()
|
|
|
|
{
|
|
|
|
return frozen;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void free()
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(!frozen);
|
|
|
|
|
|
|
|
for (T* block : stuff)
|
|
|
|
{
|
|
|
|
size_t blockSize = (block == stuff.back()) ? currentBlockSize : kBlockSize;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < blockSize; ++i)
|
|
|
|
block[i].~T();
|
|
|
|
|
|
|
|
pagedDeallocate(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
stuff.clear();
|
|
|
|
currentBlockSize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void appendBlock()
|
|
|
|
{
|
|
|
|
void* block = pagedAllocate(kBlockSizeBytes);
|
|
|
|
if (!block)
|
|
|
|
throw std::bad_alloc();
|
|
|
|
|
|
|
|
stuff.emplace_back(static_cast<T*>(block));
|
|
|
|
currentBlockSize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool frozen = false;
|
|
|
|
std::vector<T*> stuff;
|
|
|
|
size_t currentBlockSize = 0;
|
|
|
|
|
|
|
|
static constexpr size_t kBlockSizeBytes = 32768;
|
|
|
|
static constexpr size_t kBlockSize = kBlockSizeBytes / sizeof(T);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace Luau
|