mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-07-31 13:11:48 +02:00
Initial revision of the buffer implementation.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Base/Buffer.hpp"
|
||||
#include "sqrat/sqratUtil.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstdlib>
|
||||
@@ -30,7 +31,7 @@ inline unsigned int NextPow2(unsigned int num)
|
||||
void ThrowMemExcept(const char * msg, ...)
|
||||
{
|
||||
// Exception messages should be concise
|
||||
char buffer[128];
|
||||
char buffer[256];
|
||||
// Variable arguments structure
|
||||
va_list args;
|
||||
// Get the specified arguments
|
||||
@@ -40,10 +41,10 @@ void ThrowMemExcept(const char * msg, ...)
|
||||
// Check for formatting errors
|
||||
if (ret < 0)
|
||||
{
|
||||
throw std::runtime_error("Unknown memory error");
|
||||
throw Sqrat::Exception("Unknown memory error");
|
||||
}
|
||||
// Throw the actual exception
|
||||
throw std::runtime_error(buffer);
|
||||
throw Sqrat::Exception(buffer);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#define _BASE_BUFFER_HPP_
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
|
||||
@@ -214,6 +215,14 @@ private:
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Round a size value.
|
||||
*/
|
||||
template < typename T > static inline SzType RoundSz(T n)
|
||||
{
|
||||
return static_cast< SzType >(floor(n));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -380,7 +389,15 @@ public:
|
||||
*/
|
||||
operator bool () const
|
||||
{
|
||||
return m_Ptr;
|
||||
return (m_Ptr != nullptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Negation operator.
|
||||
*/
|
||||
operator ! () const
|
||||
{
|
||||
return (!m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -420,8 +437,20 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & At(SzType n)
|
||||
{
|
||||
assert(n < static_cast< SzType >(m_Cap / sizeof(T)));
|
||||
return reinterpret_cast< T * >(m_Ptr)[n];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Make sure that the specified element is withing buffer range
|
||||
else if (n > (m_Cap - sizeof(T)))
|
||||
{
|
||||
ThrowMemExcept("Element of size (%d) at index (%u) is out of buffer capacity (%u)",
|
||||
sizeof(T), n, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + n);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -429,8 +458,20 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & At(SzType n) const
|
||||
{
|
||||
assert(n < static_cast< SzType >(m_Cap / sizeof(T)));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[n];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Make sure that the specified element is withing buffer range
|
||||
else if (n > (m_Cap - sizeof(T)))
|
||||
{
|
||||
ThrowMemExcept("Element of size (%d) at index (%u) is out of buffer capacity (%u)",
|
||||
sizeof(T), n, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + n);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -470,8 +511,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & Front()
|
||||
{
|
||||
assert(m_Cap >= sizeof(T));
|
||||
return reinterpret_cast< T * >(m_Ptr)[0];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -479,8 +526,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & Front() const
|
||||
{
|
||||
assert(m_Cap >= sizeof(T));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[0];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -488,8 +541,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & Next()
|
||||
{
|
||||
assert(m_Cap >= (sizeof(T) * 2));
|
||||
return reinterpret_cast< T * >(m_Ptr)[1];
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -497,8 +556,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & Next() const
|
||||
{
|
||||
assert(m_Cap >= (sizeof(T) * 2));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[1];
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -506,8 +571,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & Back()
|
||||
{
|
||||
assert(m_Cap >= sizeof(T));
|
||||
return reinterpret_cast< T * >(m_Ptr)[(m_Cap / sizeof(T))-1];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + (m_Cap - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -515,8 +586,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & Back() const
|
||||
{
|
||||
assert(m_Cap >= sizeof(T));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[(m_Cap / sizeof(T))-1];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + (m_Cap - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -524,8 +601,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & Prev()
|
||||
{
|
||||
assert(m_Cap >= (sizeof(T) * 2));
|
||||
return reinterpret_cast< T * >(m_Ptr)[(m_Cap / sizeof(T))-2];
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + (m_Cap - (sizeof(T) * 2)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -533,8 +616,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & Prev() const
|
||||
{
|
||||
assert(m_Cap >= (sizeof(T) * 2));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[(m_Cap / sizeof(T))-2];
|
||||
// Make sure that the buffer can host at least two elements of this type
|
||||
if (m_Cap < (sizeof(T) * 2))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host two elements of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + (m_Cap - (sizeof(T) * 2)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -543,7 +632,7 @@ public:
|
||||
template < typename T = Value > void Advance(SzType n)
|
||||
{
|
||||
// Do we need to scale the buffer?
|
||||
if ((m_Cur + (n * sizeof(T))) >= m_Cap)
|
||||
if ((m_Cur + (n * sizeof(T))) > m_Cap)
|
||||
{
|
||||
Grow(m_Cur + (n * sizeof(T)));
|
||||
}
|
||||
@@ -574,7 +663,7 @@ public:
|
||||
template < typename T = Value > void Move(SzType n)
|
||||
{
|
||||
// Do we need to scale the buffer?
|
||||
if ((n * sizeof(T)) >= m_Cap)
|
||||
if ((n * sizeof(T)) > m_Cap)
|
||||
{
|
||||
Grow(n * sizeof(T));
|
||||
}
|
||||
@@ -588,12 +677,12 @@ public:
|
||||
template < typename T = Value > void Push(T v)
|
||||
{
|
||||
// Do we need to scale the buffer?
|
||||
if ((m_Cur + sizeof(T)) >= m_Cap)
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
Grow(m_Cap + sizeof(T));
|
||||
}
|
||||
// Assign the specified value
|
||||
reinterpret_cast< T * >(m_Ptr)[m_Cur] = v;
|
||||
*reinterpret_cast< T * >(m_Ptr + m_Cur) = v;
|
||||
// Move to the next element
|
||||
m_Cur += sizeof(T);
|
||||
}
|
||||
@@ -603,8 +692,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & Cursor()
|
||||
{
|
||||
assert((m_Cur / sizeof(T)) < (m_Cap / sizeof(T)));
|
||||
return reinterpret_cast< T * >(m_Ptr)[m_Cur];
|
||||
// Make sure that at least one element of this type exists after the cursor
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + m_Cur);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -612,8 +707,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & Cursor() const
|
||||
{
|
||||
assert((m_Cur / sizeof(T)) < (m_Cap / sizeof(T)));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[m_Cur];
|
||||
// Make sure that at least one element of this type exists after the cursor
|
||||
if ((m_Cur + sizeof(T)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur, m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + m_Cur);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -621,8 +722,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & Before()
|
||||
{
|
||||
assert(m_Cur >= sizeof(T));
|
||||
return reinterpret_cast< T * >(m_Ptr)[(m_Cur / sizeof(T))-1];
|
||||
// The cursor must have at least one element of this type behind
|
||||
if (m_Cur < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Cannot read an element of size (%u) before the cursor at (%u)",
|
||||
sizeof(T), m_Cur);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + (m_Cur - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -630,8 +737,14 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & Before() const
|
||||
{
|
||||
assert(m_Cur >= sizeof(T));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[(m_Cur / sizeof(T))-1];
|
||||
// The cursor must have at least one element of this type behind
|
||||
if (m_Cur < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Cannot read an element of size (%u) before the cursor at (%u)",
|
||||
sizeof(T), m_Cur);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + (m_Cur - sizeof(T)));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -639,8 +752,20 @@ public:
|
||||
*/
|
||||
template < typename T = Value > T & After()
|
||||
{
|
||||
assert(m_Cap >= sizeof(T) && (m_Cur + sizeof(T)) <= (m_Cap - sizeof(T)));
|
||||
return reinterpret_cast< T * >(m_Ptr)[(m_Cur / sizeof(T))+1];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// There must be buffer left for at least two elements of this type after the cursor
|
||||
else if ((m_Cur + (sizeof(T) * 2)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< T * >(m_Ptr + m_Cur + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -648,8 +773,20 @@ public:
|
||||
*/
|
||||
template < typename T = Value > const T & After() const
|
||||
{
|
||||
assert(m_Cap >= sizeof(T) && (m_Cur + sizeof(T)) <= (m_Cap - sizeof(T)));
|
||||
return reinterpret_cast< const T * >(m_Ptr)[(m_Cur / sizeof(T))+1];
|
||||
// Make sure that the buffer can host at least one element of this type
|
||||
if (m_Cap < sizeof(T))
|
||||
{
|
||||
ThrowMemExcept("Buffer capacity of (%u) is unable to host an element of size (%u)",
|
||||
m_Cap, sizeof(T));
|
||||
}
|
||||
// There must be buffer left for at least two elements of this type after the cursor
|
||||
else if ((m_Cur + (sizeof(T) * 2)) > m_Cap)
|
||||
{
|
||||
ThrowMemExcept("Element of size (%u) starting at (%u) exceeds buffer capacity (%u)",
|
||||
sizeof(T), m_Cur + sizeof(T), m_Cap);
|
||||
}
|
||||
// Return the requested element
|
||||
return *reinterpret_cast< const T * >(m_Ptr + m_Cur + sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
@@ -676,10 +813,26 @@ public:
|
||||
return m_Cap;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current buffer capacity in byte count.
|
||||
*/
|
||||
template < typename T = Value > SzType CapacityAs() const
|
||||
{
|
||||
return static_cast< SzType >(m_Cap / sizeof(T));
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current position of the cursor in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SzType Position() const
|
||||
SzType Position() const
|
||||
{
|
||||
return m_Cur;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the current position of the cursor in the buffer.
|
||||
*/
|
||||
template < typename T = Value > SzType PositionAs() const
|
||||
{
|
||||
return static_cast< SzType >(m_Cur / sizeof(T));
|
||||
}
|
||||
@@ -687,9 +840,9 @@ public:
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Retrieve the amount of unused buffer after the edit cursor.
|
||||
*/
|
||||
template < typename T = Value > SzType Remaining() const
|
||||
SzType Remaining() const
|
||||
{
|
||||
return static_cast< SzType >((m_Cap - m_Cur) / sizeof(T));
|
||||
return m_Cap - m_Cur;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user