/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __NARRAY__ #define __NARRAY__ #include "alloc/ialloc.h" #include "memory/memory.h" #include "assert/nassert.h" namespace GS { /*! @short Managed array. @author Emmanuel Julien (ejulien@gsworks.fr) */ template class Array { uint count; T *data; #if __ENABLE_ALLOCATION_STAT__ Alloc::System system; #endif public: inline operator T *() const { return data; } inline T *c_ptr() const { return data; } inline T &operator [] (int n) const { return data[n]; } inline T &operator [] (uint n) const { return data[n]; } void operator = (Array &o) ///< Transfer assignation. { Transfer(o); } inline T *Start() const { return data; } inline T *End() const { return &data[count]; } inline bool IsValid() const { return data ? true : false; } inline bool IsNull() const { return data ? false : true; } /// Return the number of elements of type T in the buffer. inline uint GetCount() const { return count; } /// Return the buffer size in bytes. inline size_t GetSize() const { return count * sizeof(T); } void Free() { if (data) __NSTAT_DELETE(count * sizeof(T), system); // _safe_delete_array(data); delete[] data; data = 0; count = 0; } /// Reallocate buffer elements. bool Reallocate(uint new_count) { if (new_count == count) return true; if (T *new_data = new T[new_count]) { __NSTAT_ALLOC(new_count * sizeof(T), system); Memory::Copy(new_data, data, GetSize()); if (data) __NSTAT_DELETE(count * sizeof(T), system); // _safe_delete_array(data); delete[] data; data = 0; data = new_data; count = new_count; } else return false; return true; } /// Allocate buffer elements. bool Allocate(uint _count) { /// @note We could add a small tolerance here to potentially reduce fragmentation? if (_count == count) return true; Free(); if (_count && ((data = new T[_count]) == 0)) return false; __NSTAT_ALLOC(_count * sizeof(T), system); count = _count; return true; } /// Relinquish ownership of the managed memory block. T *Detach() { T *r = data; data = 0; count = 0; return r; } /// Take ownership of a managed memory block. void Attach(uint _count, T *_data) { Free(); count = _count; data = _data; } /// Transfer data buffer. void Transfer(Array &b) { Free(); count = b.GetCount(); data = b.Detach(); #if __ENABLE_ALLOCATION_STAT__ __NSTAT_DELETE(count * sizeof(T), b.system); __NSTAT_ALLOC(count * sizeof(T), system); #endif } /// Clone data buffer. bool Clone(const Array &b) { Free(); if (!Allocate(b.GetCount())) return false; for (uint n = 0; n < GetCount(); ++n) data[n] = b[n]; return true; } /// Fill data buffer. void Fill(const T &v, uint from = 0, uint to = 0) { if (to <= 0) to = count + to; __ASSERT__(from <= count); __ASSERT__(to <= count); for (uint n = from; n < to; ++n) data[n] = v; } /// Swap two data buffer. static void Swap(Array &a, Array &b) { uint count_a = a.GetCount(), count_b = b.GetCount(); T *data_a = a.Detach(), *data_b = b.Detach(); a.Attach(count_b, data_b); b.Attach(count_a, data_a); } Array(uint _count, Alloc::System sys = Alloc::General) { data = 0; count = 0; #if __ENABLE_ALLOCATION_STAT__ system = sys; #endif Allocate(_count); } Array(uint _count, const T *_data, Alloc::System sys = Alloc::General) { data = 0; count = 0; #if __ENABLE_ALLOCATION_STAT__ system = sys; #endif if (Allocate(_count)) Memory::Copy(data, _data, sizeof(T) * _count); } Array(const Array &array, Alloc::System sys = Alloc::General) ///< Copy constructor. { data = 0; count = 0; #if __ENABLE_ALLOCATION_STAT__ system = sys; #endif Allocate(array.GetCount()); Memory::Copy(data, array.c_ptr(), array.GetSize()); } Array(Alloc::System sys = Alloc::General) { data = 0; count = 0; #if __ENABLE_ALLOCATION_STAT__ system = sys; #endif } ~Array() { Free(); } }; } // GS #endif // __NARRAY__