From c1e57c829c1b1279716fcffc22d5543e6f67bb66 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 18 Jun 2013 21:07:53 +0200 Subject: [PATCH] Added experimental implementation of ByteArrays Former-commit-id: c95729bb45059c199344471a61042d98090034c8 --- include/Nazara/Core/ByteArray.hpp | 47 +-- src/Nazara/Core/ByteArray.cpp | 468 +++++++++++++++++++++--------- 2 files changed, 363 insertions(+), 152 deletions(-) diff --git a/include/Nazara/Core/ByteArray.hpp b/include/Nazara/Core/ByteArray.hpp index 7797ade76..f48fc0599 100644 --- a/include/Nazara/Core/ByteArray.hpp +++ b/include/Nazara/Core/ByteArray.hpp @@ -10,12 +10,7 @@ #include #include #include - -#if NAZARA_CORE_THREADSAFE && NAZARA_THREADSAFETY_BYTEARRAY -#include -#else -#include -#endif +#include class NzAbstractHash; class NzHashDigest; @@ -26,45 +21,49 @@ class NAZARA_API NzByteArray : public NzHashable struct SharedArray; NzByteArray(); - NzByteArray(const nzUInt8* buffer, unsigned int bufferLength); + NzByteArray(const nzUInt8* buffer, unsigned int length); NzByteArray(const NzByteArray& buffer); NzByteArray(NzByteArray&& buffer) noexcept; NzByteArray(SharedArray* sharedArray); ~NzByteArray(); + NzByteArray& Append(nzUInt8 byte); + NzByteArray& Append(const nzUInt8* buffer, unsigned int length); NzByteArray& Append(const NzByteArray& byteArray); - void Clear(); + void Clear(bool keepBuffer = false); nzUInt8* GetBuffer(); unsigned int GetCapacity() const; const nzUInt8* GetConstBuffer() const; unsigned int GetSize() const; - NzByteArray& Insert(int pos, const nzUInt8* buffer, unsigned int bufferLength); - NzByteArray& Insert(int pos, const NzByteArray& byteArray); + NzByteArray& Insert(int pos, nzUInt8 byte); + NzByteArray& Insert(int pos, const nzUInt8* buffer, unsigned int length); + NzByteArray& Insert(int pos, const NzByteArray& array); bool IsEmpty() const; + NzByteArray& Prepend(nzUInt8 byte); + NzByteArray& Prepend(const nzUInt8* buffer, unsigned int length); + NzByteArray& Prepend(const NzByteArray& array); + void Reserve(unsigned int bufferSize); NzByteArray& Resize(int size, nzUInt8 byte = 0); NzByteArray Resized(int size, nzUInt8 byte = 0) const; - NzByteArray Subarray(int startPos, int endPos = -1) const; + NzByteArray SubArray(int startPos, int endPos = -1) const; - void Swap(NzByteArray& byteArray); - - NzByteArray& Trim(nzUInt8 byte = '\0'); - NzByteArray Trimmed(nzUInt8 byte = '\0') const; + void Swap(NzByteArray& array); // Méthodes compatibles STD nzUInt8* begin(); const nzUInt8* begin() const; nzUInt8* end(); const nzUInt8* end() const; - void push_front(nzUInt8 c); - void push_back(nzUInt8 c); + void push_front(nzUInt8 byte); + void push_back(nzUInt8 byte); /*nzUInt8* rbegin(); const nzUInt8* rbegin() const; nzUInt8* rend(); @@ -82,29 +81,33 @@ class NAZARA_API NzByteArray : public NzHashable NzByteArray& operator=(const NzByteArray& byteArray); NzByteArray& operator=(NzByteArray&& byteArray) noexcept; + NzByteArray operator+(nzUInt8 byte) const; NzByteArray operator+(const NzByteArray& byteArray) const; + NzByteArray& operator+=(nzUInt8 byte); NzByteArray& operator+=(const NzByteArray& byteArray); static int Compare(const NzByteArray& first, const NzByteArray& second); struct NAZARA_API SharedArray { - SharedArray() = default; + SharedArray() : + refCount(1) + { + } SharedArray(unsigned short referenceCount, unsigned int bufferSize, unsigned int arraySize, nzUInt8* ptr) : capacity(bufferSize), size(arraySize), - refCount(referenceCount), - buffer(ptr) + buffer(ptr), + refCount(referenceCount) { } unsigned int capacity; unsigned int size; - unsigned short refCount = 1; nzUInt8* buffer; - NazaraMutex(mutex) + std::atomic_ushort refCount; }; static SharedArray emptyArray; diff --git a/src/Nazara/Core/ByteArray.cpp b/src/Nazara/Core/ByteArray.cpp index dfa074270..f85123019 100644 --- a/src/Nazara/Core/ByteArray.cpp +++ b/src/Nazara/Core/ByteArray.cpp @@ -2,21 +2,14 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp -/* #include +#include +#include #include #include +#include #include -inline unsigned int nzPow2(unsigned int n) -{ - unsigned int x = 1; - - while(x <= n) - x <<= 1; - - return x; -} // Cet algorithme est inspiré de la documentation de Qt inline unsigned int nzGetNewSize(unsigned int newSize) { @@ -25,7 +18,7 @@ inline unsigned int nzGetNewSize(unsigned int newSize) else { if (newSize < (1 << 12)-12) - return nzPow2(newSize << 1)-12; + return NzGetNearestPowerOfTwo(newSize << 1)-12; else return newSize + (1 << 11); } @@ -36,15 +29,15 @@ m_sharedArray(&emptyArray) { } -NzByteArray::NzByteArray(const nzUInt8* buffer, unsigned int bufferLength) +NzByteArray::NzByteArray(const nzUInt8* buffer, unsigned int length) { - if (bufferLength > 0) + if (length > 0) { m_sharedArray = new SharedArray; - m_sharedArray->buffer = new nzUInt8[bufferLength]; - m_sharedArray->capacity = bufferLength; - m_sharedArray->size = bufferLength; - std::memcpy(m_sharedArray->buffer, buffer, bufferLength); + m_sharedArray->buffer = new nzUInt8[length]; + m_sharedArray->capacity = length; + m_sharedArray->size = length; + std::memcpy(m_sharedArray->buffer, buffer, length); } else m_sharedArray = &emptyArray; @@ -54,11 +47,7 @@ NzByteArray::NzByteArray(const NzByteArray& buffer) : m_sharedArray(buffer.m_sharedArray) { if (m_sharedArray != &emptyArray) - { - NazaraMutexLock(m_sharedArray->mutex); m_sharedArray->refCount++; - NazaraMutexUnlock(m_sharedArray->mutex); - } } NzByteArray::NzByteArray(NzByteArray&& buffer) noexcept : @@ -77,43 +66,30 @@ NzByteArray::~NzByteArray() ReleaseArray(); } -NzByteArray& NzByteArray::Append(const NzByteArray& byteArray) +NzByteArray& NzByteArray::Append(nzUInt8 byte) { - if (byteArray.m_sharedArray->size == 0) - return *this; - - if (m_sharedArray->size == 0 && m_sharedArray->capacity < byteArray.m_sharedArray->size) - return operator=(byteArray); - - if (m_sharedArray->capacity >= m_sharedArray->size + byteArray.m_sharedArray->size) - { - EnsureOwnership(); - - std::memcpy(&m_sharedArray->buffer[m_sharedArray->size], byteArray.m_sharedArray->buffer, byteArray.m_sharedArray->size); - m_sharedArray->size += byteArray.m_sharedArray->size; - } - else - { - unsigned int newSize = m_sharedArray->size + byteArray.m_sharedArray->size; - unsigned int bufferSize = nzGetNewSize(newSize); - - nzUInt8* buffer = new nzUInt8[bufferSize+1]; - std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size); - std::memcpy(&buffer[m_sharedArray->size], byteArray.m_sharedArray->buffer, byteArray.m_sharedArray->size); - - ReleaseArray(); - m_sharedArray = new SharedArray; - m_sharedArray->buffer = buffer; - m_sharedArray->capacity = bufferSize; - m_sharedArray->size = newSize; - } - - return *this; + return Insert(m_sharedArray->size, byte); } -void NzByteArray::Clear() +NzByteArray& NzByteArray::Append(const nzUInt8* buffer, unsigned int length) { - ReleaseArray(); + return Insert(m_sharedArray->size, buffer, length); +} + +NzByteArray& NzByteArray::Append(const NzByteArray& array) +{ + return Insert(m_sharedArray->size, array); +} + +void NzByteArray::Clear(bool keepBuffer) +{ + if (keepBuffer) + { + EnsureOwnership(); + m_sharedArray->size = 0; + } + else + ReleaseArray(); } nzUInt8* NzByteArray::GetBuffer() @@ -138,13 +114,15 @@ unsigned int NzByteArray::GetSize() const return m_sharedArray->size; } -NzByteArray& NzByteArray::Insert(int pos, const nzUInt8* buffer, unsigned int bufferLength) +NzByteArray& NzByteArray::Insert(int pos, nzUInt8 byte) { - if (bufferLength == 0) - return *this; + return Insert(pos, &byte, 1); +} - if (m_sharedArray->size == 0) - return operator=(string); +NzByteArray& NzByteArray::Insert(int pos, const nzUInt8* buffer, unsigned int length) +{ + if (length == 0) + return *this; if (pos < 0) pos = std::max(static_cast(m_sharedArray->size + pos), 0); @@ -152,89 +130,49 @@ NzByteArray& NzByteArray::Insert(int pos, const nzUInt8* buffer, unsigned int bu unsigned int start = std::min(static_cast(pos), m_sharedArray->size); // Si le buffer est déjà suffisamment grand - if (m_sharedArray->capacity >= m_sharedArray->size + bufferLength) + if (m_sharedArray->capacity >= m_sharedArray->size + length) { EnsureOwnership(); - std::memmove(&m_sharedArray->buffer[start+bufferLength], &m_sharedArray->buffer[start], m_sharedArray->size); - std::memcpy(&m_sharedArray->buffer[start], buffer, bufferLength); + std::memmove(&m_sharedArray->buffer[start+length], &m_sharedArray->buffer[start], m_sharedArray->size); + std::memcpy(&m_sharedArray->buffer[start], buffer, length); - m_sharedArray->size += bufferLength; + m_sharedArray->size += length; } else { - unsigned int newSize = m_sharedArray->size+bufferLength; - nzUInt8* newBuffer = new nzUInt8[newSize+1]; + unsigned int newSize = m_sharedArray->size + length; + nzUInt8* newBuffer = new nzUInt8[newSize]; nzUInt8* ptr = newBuffer; - const nzUInt8* s = m_sharedArray->buffer; - while (ptr != &newBuffer[start]) - *ptr++ = *s++; + if (start > 0) + { + std::memcpy(ptr, m_sharedArray->buffer, start*sizeof(nzUInt8)); + ptr += start; + } - while (ptr != &newBuffer[start+bufferLength]) - *ptr++ = *buffer++; + std::memcpy(ptr, buffer, length*sizeof(nzUInt8)); + ptr += length; - std::strcpy(ptr, s); + if (m_sharedArray->size > 0) + std::memcpy(ptr, &m_sharedArray->buffer[start], m_sharedArray->size - start); - ReleaseString(); - m_sharedArray = new SharedString; - m_sharedArray->allocatedSize = newSize; + ReleaseArray(); + m_sharedArray = new SharedArray; m_sharedArray->buffer = newBuffer; + m_sharedArray->capacity = newSize; m_sharedArray->size = newSize; } return *this; + + return *this; } -NzByteArray& NzByteArray::Insert(int pos, const NzByteArray& byteArray) +NzByteArray& NzByteArray::Insert(int pos, const NzByteArray& array) { - if (string.m_sharedArray->size == 0) - return *this; - - if (m_sharedArray->size == 0 && m_sharedArray->capacity < string.m_sharedArray->size) - return operator=(string); - - if (pos < 0) - pos = std::max(static_cast(m_sharedArray->size + pos), 0); - - unsigned int start = std::min(static_cast(pos), m_sharedArray->size); - - // Si le buffer est déjà suffisamment grand - if (m_sharedArray->capacity >= m_sharedArray->size + string.m_sharedArray->size) - { - EnsureOwnership(); - - std::memmove(&m_sharedArray->string[start+string.m_sharedArray->size], &m_sharedArray->string[start], m_sharedArray->size*sizeof(char)); - std::memcpy(&m_sharedArray->string[start], string.m_sharedArray->string, string.m_sharedArray->size*sizeof(char)); - - m_sharedArray->size += string.m_sharedArray->size; - } - else - { - unsigned int newSize = m_sharedArray->size+string.m_sharedArray->size; - char* newString = new char[newSize+1]; - - char* ptr = newString; - const char* s = m_sharedArray->string; - - while (ptr != &newString[start]) - *ptr++ = *s++; - - const char* p = string.m_sharedArray->string; - while (ptr != &newString[start+string.m_sharedArray->size]) - *ptr++ = *p++; - - std::strcpy(ptr, s); - - ReleaseString(); - m_sharedArray = new SharedString; - m_sharedArray->capacity = newSize; - m_sharedArray->size = newSize; - m_sharedArray->string = newString; - } - - return *this; + return Insert(pos, array.m_sharedArray->buffer, array.m_sharedArray->size); } bool NzByteArray::IsEmpty() const @@ -242,24 +180,294 @@ bool NzByteArray::IsEmpty() const return m_sharedArray->size == 0; } +NzByteArray& NzByteArray::Prepend(nzUInt8 byte) +{ + return Insert(0, byte); +} + +NzByteArray& NzByteArray::Prepend(const nzUInt8* buffer, unsigned int length) +{ + return Insert(0, buffer, length); +} + +NzByteArray& NzByteArray::Prepend(const NzByteArray& array) +{ + return Insert(0, array); +} + void NzByteArray::Reserve(unsigned int bufferSize) { - if (m_sharedArray->allocatedSize >= bufferSize) + if (m_sharedArray->capacity >= bufferSize) return; - nzUInt8* ptr = new nzUInt8[bufferSize+1]; + nzUInt8* newBuffer = new nzUInt8[bufferSize]; if (m_sharedArray->size > 0) - std::memcpy(ptr, m_sharedArray->buffer, m_sharedArray->size); + std::memcpy(newBuffer, m_sharedArray->buffer, m_sharedArray->size); unsigned int size = m_sharedArray->size; ReleaseArray(); - m_sharedArray = new SharedString; - m_sharedArray->allocatedSize = bufferSize; - m_sharedArray->buffer = ptr; + m_sharedArray = new SharedArray; + m_sharedArray->buffer = newBuffer; + m_sharedArray->capacity = bufferSize; m_sharedArray->size = size; } -NzByteArray::SharedString NzByteArray::emptyArray(0, 0, 0, nullptr); -unsigned int NzByteArray::npos(static_cast(-1)); -*/ +NzByteArray& NzByteArray::Resize(int size, nzUInt8 byte) +{ + if (size == 0) + { + Clear(true); + return *this; + } + + if (size < 0) + size = std::max(static_cast(m_sharedArray->size + size), 0); + + unsigned int newSize = static_cast(size); + + if (m_sharedArray->capacity >= newSize) + { + EnsureOwnership(); + + // Nous avons déjà la place requise, contentons-nous de remplir le buffer + if (newSize > m_sharedArray->size) + std::memset(&m_sharedArray->buffer[m_sharedArray->size], byte, newSize-m_sharedArray->size); + + m_sharedArray->size = newSize; + } + else // On veut forcément agrandir la chaine + { + nzUInt8* newBuffer = new nzUInt8[newSize]; + if (m_sharedArray->size != 0) + std::memcpy(newBuffer, m_sharedArray->buffer, newSize); + + std::memset(&newBuffer[m_sharedArray->size], byte, newSize-m_sharedArray->size); + + ReleaseArray(); + m_sharedArray = new SharedArray; + m_sharedArray->buffer = newBuffer; + m_sharedArray->capacity = newSize; + m_sharedArray->size = newSize; + } + + return *this; +} + +NzByteArray NzByteArray::Resized(int size, nzUInt8 byte) const +{ + if (size < 0) + size = m_sharedArray->size + size; + + if (size <= 0) + return NzByteArray(); + + unsigned int newSize = static_cast(size); + if (newSize == m_sharedArray->size) + return *this; + + nzUInt8* buffer = new nzUInt8[newSize]; + if (newSize > m_sharedArray->size) + { + std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size); + std::memset(&buffer[m_sharedArray->size], byte, newSize - m_sharedArray->size); + } + else + std::memcpy(buffer, m_sharedArray->buffer, newSize); + + return NzByteArray(new SharedArray(1, newSize, newSize, buffer)); +} + +NzByteArray NzByteArray::SubArray(int startPos, int endPos) const +{ + if (startPos < 0) + startPos = std::max(m_sharedArray->size+startPos, 0U); + + unsigned int start = static_cast(startPos); + + if (endPos < 0) + { + endPos = m_sharedArray->size + endPos; + if (endPos < 0) + return NzByteArray(); + } + + unsigned int minEnd = std::min(static_cast(endPos), m_sharedArray->size-1); + + if (start > minEnd || start >= m_sharedArray->size) + return NzByteArray(); + + unsigned int size = minEnd - start + 1; + nzUInt8* buffer = new nzUInt8[size]; + std::memcpy(buffer, &m_sharedArray->buffer[start], size); + + return NzByteArray(new SharedArray(1, size, size, buffer)); +} + +void NzByteArray::Swap(NzByteArray& array) +{ + std::swap(m_sharedArray, array.m_sharedArray); +} + +nzUInt8* NzByteArray::begin() +{ + return m_sharedArray->buffer; +} + +const nzUInt8* NzByteArray::begin() const +{ + return m_sharedArray->buffer; +} + +nzUInt8* NzByteArray::end() +{ + return &m_sharedArray->buffer[m_sharedArray->size]; +} + +const nzUInt8* NzByteArray::end() const +{ + return &m_sharedArray->buffer[m_sharedArray->size]; +} + +void NzByteArray::push_front(nzUInt8 byte) +{ + Prepend(byte); +} + +void NzByteArray::push_back(nzUInt8 byte) +{ + Append(byte); +} + +nzUInt8& NzByteArray::operator[](unsigned int pos) +{ + EnsureOwnership(); + + if (pos >= m_sharedArray->size) + Resize(pos+1); + + return m_sharedArray->buffer[pos]; +} + +nzUInt8 NzByteArray::operator[](unsigned int pos) const +{ + #if NAZARA_CORE_SAFE + if (pos >= m_sharedArray->size) + { + NazaraError("Index out of range (" + NzString::Number(pos) + " >= " + NzString::Number(m_sharedArray->size) + ')'); + return 0; + } + #endif + + return m_sharedArray->buffer[pos]; +} + +NzByteArray& NzByteArray::operator=(const NzByteArray& array) +{ + ReleaseArray(); + + m_sharedArray = array.m_sharedArray; + if (m_sharedArray != &emptyArray) + m_sharedArray->refCount++; + + return *this; +} + +NzByteArray& NzByteArray::operator=(NzByteArray&& array) noexcept +{ + std::swap(m_sharedArray, array.m_sharedArray); + + return *this; +} + +NzByteArray NzByteArray::operator+(nzUInt8 byte) const +{ + if (m_sharedArray->size == 0) + return NzByteArray(&byte, 1); + + unsigned int totalSize = m_sharedArray->size + 1; + nzUInt8* buffer = new nzUInt8[totalSize]; + std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size); + buffer[m_sharedArray->size] = byte; + + return NzByteArray(new SharedArray(1, totalSize, totalSize, buffer)); +} + +NzByteArray NzByteArray::operator+(const NzByteArray& array) const +{ + if (array.m_sharedArray->size == 0) + return *this; + + if (m_sharedArray->size == 0) + return array; + + unsigned int totalSize = m_sharedArray->size + array.m_sharedArray->size; + nzUInt8* buffer = new nzUInt8[totalSize]; + std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size); + std::memcpy(&buffer[m_sharedArray->size], array.m_sharedArray->buffer, array.m_sharedArray->size); + + return NzByteArray(new SharedArray(1, totalSize, totalSize, buffer)); +} + +NzByteArray& NzByteArray::operator+=(nzUInt8 byte) +{ + return Append(byte); +} + +NzByteArray& NzByteArray::operator+=(const NzByteArray& array) +{ + return Append(array); +} + +int NzByteArray::Compare(const NzByteArray& first, const NzByteArray& second) +{ + return std::memcmp(first.m_sharedArray->buffer, second.m_sharedArray->buffer, std::min(first.m_sharedArray->size, second.m_sharedArray->size)); +} + +void NzByteArray::EnsureOwnership() +{ + if (m_sharedArray == &emptyArray) + return; + + if (m_sharedArray->refCount > 1) + { + m_sharedArray->refCount--; + + nzUInt8* buffer = new nzUInt8[m_sharedArray->capacity]; + std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size); + + m_sharedArray = new SharedArray(1, m_sharedArray->capacity, m_sharedArray->size, buffer); + } +} + +bool NzByteArray::FillHash(NzAbstractHash* hazh) const +{ + hazh->Append(m_sharedArray->buffer, m_sharedArray->size); + + return true; +} + +void NzByteArray::ReleaseArray() +{ + if (m_sharedArray == &emptyArray) + return; + + if (--m_sharedArray->refCount == 0) + { + delete[] m_sharedArray->buffer; + delete m_sharedArray; + } + + m_sharedArray = &emptyArray; +} + +NzByteArray::SharedArray NzByteArray::emptyArray(0, 0, 0, nullptr); +unsigned int NzByteArray::npos(std::numeric_limits::max()); + +namespace std +{ + void swap(NzByteArray& lhs, NzByteArray& rhs) + { + lhs.Swap(rhs); + } +}