blob: 09bff6e466f6d4f8267848fd84e9ccb8dc40693f [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
// -----------------------------------------------------------------------------------------------------------------------------
// ContinuousPageStack declaration
// -----------------------------------------------------------------------------------------------------------------------------
template<const size_t InitialPageCount = 1>
class ContinuousPageStack : protected Allocator
{
protected:
class Iterator
{
protected:
size_t nextTop;
protected:
inline Iterator(const ContinuousPageStack &stack);
public:
inline size_t Position() const;
inline operator bool() const;
};
friend class Iterator;
private:
PageAllocator *const pageAllocator;
PageAllocation *pageAllocation;
size_t bufferSize;
protected:
size_t nextTop;
protected:
inline ContinuousPageStack(PageAllocator *const pageAllocator, void (*const outOfMemoryFunc)());
~ContinuousPageStack();
inline char *Buffer() const;
public:
inline bool IsEmpty() const;
inline void Clear();
inline size_t Position() const;
inline char* Push(const size_t size);
inline char* Top(const size_t size) const;
inline char* Pop(const size_t size);
inline void UnPop(const size_t size);
inline void PopTo(const size_t position);
private:
void Resize(size_t requestedSize);
};
// -----------------------------------------------------------------------------------------------------------------------------
// ContinuousPageStackOfFixedElements declaration
// -----------------------------------------------------------------------------------------------------------------------------
template<class T, const size_t InitialPageCount = 1>
class ContinuousPageStackOfFixedElements : public ContinuousPageStack<InitialPageCount>
{
public:
class Iterator : public ContinuousPageStack<InitialPageCount>::Iterator
{
private:
const ContinuousPageStackOfFixedElements &stack;
public:
inline Iterator(const ContinuousPageStackOfFixedElements &stack);
inline T &operator *() const;
inline T *operator ->() const;
inline Iterator &operator ++(); // pre-increment
inline Iterator operator ++(int); // post-increment
};
friend class Iterator;
public:
inline ContinuousPageStackOfFixedElements(PageAllocator *const pageAllocator, void (*const outOfMemoryFunc)());
public:
inline char* Push();
inline T* Top() const;
inline T* Pop();
inline void UnPop();
inline void PopTo(const size_t position);
};
// -----------------------------------------------------------------------------------------------------------------------------
// ContinuousPageStackOfVariableElements declaration
// -----------------------------------------------------------------------------------------------------------------------------
template<class T, const size_t InitialPageCount = 1>
class ContinuousPageStackOfVariableElements : public ContinuousPageStack<InitialPageCount>
{
public:
class Iterator : public ContinuousPageStack<InitialPageCount>::Iterator
{
private:
size_t topElementSize;
const ContinuousPageStackOfVariableElements &stack;
public:
inline Iterator(const ContinuousPageStackOfVariableElements &stack);
inline T &operator *() const;
inline T *operator ->() const;
inline Iterator &operator ++(); // pre-increment
inline Iterator operator ++(int); // post-increment
};
friend class Iterator;
private:
class VariableElement
{
private:
const size_t previousElementSize;
char data[0];
public:
inline VariableElement(const size_t previousElementSize);
public:
template<class ActualT> inline static size_t Size();
inline size_t PreviousElementSize() const;
inline char *Data();
};
private:
size_t topElementSize;
public:
inline ContinuousPageStackOfVariableElements(PageAllocator *const pageAllocator, void (*const outOfMemoryFunc)());
public:
template<class ActualT> inline char* Push();
inline T* Top() const;
inline T* Pop();
template<class ActualT> inline void UnPop();
inline void PopTo(const size_t position);
};
// -----------------------------------------------------------------------------------------------------------------------------
// ContinuousPageStack definition
// -----------------------------------------------------------------------------------------------------------------------------
// --------
// Iterator
// --------
template<const size_t InitialPageCount>
inline ContinuousPageStack<InitialPageCount>::Iterator::Iterator(const ContinuousPageStack &stack)
: nextTop(stack.nextTop)
{
}
template<const size_t InitialPageCount>
inline size_t ContinuousPageStack<InitialPageCount>::Iterator::Position() const
{
return nextTop;
}
template<const size_t InitialPageCount>
inline ContinuousPageStack<InitialPageCount>::Iterator::operator bool() const
{
return nextTop != 0;
}
// -------------------
// ContinuousPageStack
// -------------------
template<const size_t InitialPageCount>
inline ContinuousPageStack<InitialPageCount>::ContinuousPageStack(
PageAllocator *const pageAllocator,
void (*const outOfMemoryFunc)())
: Allocator(outOfMemoryFunc), pageAllocator(pageAllocator), bufferSize(0), nextTop(0)
{
Assert(pageAllocator);
}
template<const size_t InitialPageCount>
ContinuousPageStack<InitialPageCount>::~ContinuousPageStack()
{
if(bufferSize && !pageAllocator->IsClosed())
pageAllocator->ReleaseAllocation(pageAllocation);
}
template<const size_t InitialPageCount>
inline char *ContinuousPageStack<InitialPageCount>::Buffer() const
{
Assert(bufferSize);
return pageAllocation->GetAddress();
}
template<const size_t InitialPageCount>
inline bool ContinuousPageStack<InitialPageCount>::IsEmpty() const
{
return nextTop == 0;
}
template<const size_t InitialPageCount>
inline void ContinuousPageStack<InitialPageCount>::Clear()
{
nextTop = 0;
}
template<const size_t InitialPageCount>
inline size_t ContinuousPageStack<InitialPageCount>::Position() const
{
return nextTop;
}
template<const size_t InitialPageCount>
inline char* ContinuousPageStack<InitialPageCount>::Push(const size_t size)
{
Assert(size);
if(bufferSize - nextTop < size)
Resize(size);
char* const res = Buffer() + nextTop;
nextTop += size;
return res;
}
template<const size_t InitialPageCount>
inline char* ContinuousPageStack<InitialPageCount>::Top(const size_t size) const
{
if (nextTop == 0)
return 0;
else
{
Assert(size != 0);
Assert(size <= nextTop);
return Buffer() + (nextTop - size);
}
}
template<const size_t InitialPageCount>
inline char* ContinuousPageStack<InitialPageCount>::Pop(const size_t size)
{
if (nextTop == 0)
return 0;
else
{
Assert(size != 0);
Assert(nextTop >= size);
nextTop -= size;
return Buffer() + nextTop;
}
}
template<const size_t InitialPageCount>
inline void ContinuousPageStack<InitialPageCount>::UnPop(const size_t size)
{
Assert(size != 0);
Assert(nextTop + size <= bufferSize);
nextTop += size;
}
template<const size_t InitialPageCount>
void ContinuousPageStack<InitialPageCount>::Resize(size_t requestedSize)
{
Assert(requestedSize);
Assert(requestedSize <= InitialPageCount * AutoSystemInfo::PageSize);
if(!bufferSize)
{
pageAllocation = pageAllocator->AllocAllocation(InitialPageCount);
if (!pageAllocation)
{
outOfMemoryFunc();
AnalysisAssert(false);
}
bufferSize = pageAllocation->GetSize();
return;
}
PageAllocation *const newPageAllocation = pageAllocator->AllocAllocation(pageAllocation->GetPageCount() * 2);
if (!newPageAllocation)
{
outOfMemoryFunc();
AnalysisAssert(false);
}
js_memcpy_s(newPageAllocation->GetAddress(), newPageAllocation->GetSize(), Buffer(), nextTop);
pageAllocator->ReleaseAllocation(pageAllocation);
pageAllocation = newPageAllocation;
bufferSize = newPageAllocation->GetSize();
}
template<const size_t InitialPageCount>
inline void ContinuousPageStack<InitialPageCount>::PopTo(const size_t position)
{
Assert(position <= nextTop);
nextTop = position;
}
// -----------------------------------------------------------------------------------------------------------------------------
// ContinuousPageStackOfFixedElements definition
// -----------------------------------------------------------------------------------------------------------------------------
// --------
// Iterator
// --------
template<class T, const size_t InitialPageCount>
inline ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::Iterator(
const ContinuousPageStackOfFixedElements &stack)
: ContinuousPageStack<InitialPageCount>::Iterator(stack), stack(stack)
{
}
template<class T, const size_t InitialPageCount>
inline T &ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator *() const
{
Assert(*this);
Assert(this->nextTop <= stack.nextTop);
return *reinterpret_cast<T *>(&stack.Buffer()[this->nextTop - sizeof(T)]);
}
template<class T, const size_t InitialPageCount>
inline T *ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator ->() const
{
return &**this;
}
template<class T, const size_t InitialPageCount>
inline typename ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator &ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator ++() // pre-increment
{
Assert(*this);
this->nextTop -= sizeof(T);
return *this;
}
template<class T, const size_t InitialPageCount>
inline typename ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator ContinuousPageStackOfFixedElements<T, InitialPageCount>::Iterator::operator ++(int) // post-increment
{
Iterator it(*this);
++*this;
return it;
}
// ----------------------------------
// ContinuousPageStackOfFixedElements
// ----------------------------------
template<class T, const size_t InitialPageCount>
inline ContinuousPageStackOfFixedElements<T, InitialPageCount>::ContinuousPageStackOfFixedElements(
PageAllocator *const pageAllocator,
void (*const outOfMemoryFunc)())
: ContinuousPageStack<InitialPageCount>(pageAllocator, outOfMemoryFunc)
{
}
template<class T, const size_t InitialPageCount>
inline char* ContinuousPageStackOfFixedElements<T, InitialPageCount>::Push()
{
return ContinuousPageStack<InitialPageCount>::Push(sizeof(T));
}
template<class T, const size_t InitialPageCount>
inline T* ContinuousPageStackOfFixedElements<T, InitialPageCount>::Top() const
{
return reinterpret_cast<T*>(ContinuousPageStack<InitialPageCount>::Top(sizeof(T)));
}
template<class T, const size_t InitialPageCount>
inline T* ContinuousPageStackOfFixedElements<T, InitialPageCount>::Pop()
{
return reinterpret_cast<T*>(ContinuousPageStack<InitialPageCount>::Pop(sizeof(T)));
}
template<class T, const size_t InitialPageCount>
inline void ContinuousPageStackOfFixedElements<T, InitialPageCount>::UnPop()
{
return ContinuousPageStack<InitialPageCount>::UnPop(sizeof(T));
}
template<class T, const size_t InitialPageCount>
inline void ContinuousPageStackOfFixedElements<T, InitialPageCount>::PopTo(const size_t position)
{
ContinuousPageStack<InitialPageCount>::PopTo(position);
}
// -----------------------------------------------------------------------------------------------------------------------------
// ContinuousPageStackOfVariableElements definition
// -----------------------------------------------------------------------------------------------------------------------------
// --------
// Iterator
// --------
template<class T, const size_t InitialPageCount>
inline ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::Iterator(
const ContinuousPageStackOfVariableElements &stack)
: ContinuousPageStack<InitialPageCount>::Iterator(stack), topElementSize(stack.topElementSize), stack(stack)
{
}
template<class T, const size_t InitialPageCount>
inline T &ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator *() const
{
Assert(*this);
Assert(this->nextTop <= stack.nextTop);
return *reinterpret_cast<T*>(reinterpret_cast<VariableElement *>(&stack.Buffer()[this->nextTop - this->topElementSize])->Data());
}
template<class T, const size_t InitialPageCount>
inline T *ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator ->() const
{
return &**this;
}
template<class T, const size_t InitialPageCount>
inline typename ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator &ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator ++() // pre-increment
{
Assert(*this);
Assert(this->nextTop <= stack.nextTop);
topElementSize = reinterpret_cast<VariableElement *>(&stack.Buffer()[this->nextTop -= this->topElementSize])->PreviousElementSize();
return *this;
}
template<class T, const size_t InitialPageCount>
inline typename ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator ContinuousPageStackOfVariableElements<T, InitialPageCount>::Iterator::operator ++(int) // post-increment
{
Iterator it(*this);
++*this;
return it;
}
// ---------------
// VariableElement
// ---------------
template<class T, const size_t InitialPageCount>
inline ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::VariableElement(
const size_t previousElementSize)
: previousElementSize(previousElementSize)
{
}
template<class T, const size_t InitialPageCount>
template<class ActualT>
inline size_t ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::Size()
{
return sizeof(VariableElement) + sizeof(ActualT);
}
template<class T, const size_t InitialPageCount>
inline size_t ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::PreviousElementSize() const
{
return previousElementSize;
}
template<class T, const size_t InitialPageCount>
inline char* ContinuousPageStackOfVariableElements<T, InitialPageCount>::VariableElement::Data()
{
return data;
}
// -------------------------------------
// ContinuousPageStackOfVariableElements
// -------------------------------------
template<class T, const size_t InitialPageCount>
inline ContinuousPageStackOfVariableElements<T, InitialPageCount>::ContinuousPageStackOfVariableElements(
PageAllocator *const pageAllocator,
void (*const outOfMemoryFunc)())
: ContinuousPageStack<InitialPageCount>(pageAllocator, outOfMemoryFunc)
{
}
template<class T, const size_t InitialPageCount>
template<class ActualT>
inline char* ContinuousPageStackOfVariableElements<T, InitialPageCount>::Push()
{
TemplateParameter::SameOrDerivedFrom<ActualT, T>(); // ActualT must be the same type as, or a type derived from, T
VariableElement *const element =
new(ContinuousPageStack<InitialPageCount>::Push(VariableElement::template
Size<ActualT>())) VariableElement(topElementSize);
topElementSize = VariableElement::template Size<ActualT>();
return element->Data();
}
template<class T, const size_t InitialPageCount>
inline T* ContinuousPageStackOfVariableElements<T, InitialPageCount>::Top() const
{
VariableElement* const element = reinterpret_cast<VariableElement*>(ContinuousPageStack<InitialPageCount>::Top(topElementSize));
return element == 0 ? 0 : reinterpret_cast<T*>(element->Data());
}
template<class T, const size_t InitialPageCount>
inline T* ContinuousPageStackOfVariableElements<T, InitialPageCount>::Pop()
{
VariableElement *const element = reinterpret_cast<VariableElement*>(ContinuousPageStack<InitialPageCount>::Pop(topElementSize));
if (element == 0)
return 0;
else
{
topElementSize = element->PreviousElementSize();
return reinterpret_cast<T*>(element->Data());
}
}
template<class T, const size_t InitialPageCount>
template<class ActualT>
inline void ContinuousPageStackOfVariableElements<T, InitialPageCount>::UnPop()
{
TemplateParameter::SameOrDerivedFrom<ActualT, T>(); // ActualT must be the same type as, or a type derived from, T
ContinuousPageStack<InitialPageCount>::UnPop(VariableElement::template
Size<ActualT>());
Assert(reinterpret_cast<VariableElement*>(ContinuousPageStack<InitialPageCount>::Top(VariableElement::template
Size<ActualT>()))->PreviousElementSize() == topElementSize);
topElementSize = VariableElement::template Size<ActualT>();
}
template<class T, const size_t InitialPageCount>
inline void ContinuousPageStackOfVariableElements<T, InitialPageCount>::PopTo(const size_t position)
{
Assert(position <= this->nextTop);
if(position != this->nextTop)
{
Assert(position + sizeof(VariableElement) <= this->nextTop);
topElementSize = reinterpret_cast<VariableElement *>(&this->Buffer()[position])->PreviousElementSize();
}
ContinuousPageStack<InitialPageCount>::PopTo(position);
}