mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-31 11:17:01 -07:00 
			
		
		
		
	
		
			
				
	
	
		
			1328 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1328 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //----------------------------------------------------------------------------
 | |
| // Anti-Grain Geometry - Version 2.4
 | |
| // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
 | |
| //
 | |
| // Permission to copy, use, modify, sell and distribute this software
 | |
| // is granted provided this copyright notice appears in all copies.
 | |
| // This software is provided "as is" without express or implied
 | |
| // warranty, and with no claim as to its suitability for any purpose.
 | |
| //
 | |
| //----------------------------------------------------------------------------
 | |
| // Contact: mcseem@antigrain.com
 | |
| //          mcseemagg@yahoo.com
 | |
| //          http://www.antigrain.com
 | |
| //----------------------------------------------------------------------------
 | |
| #ifndef AGG_ARRAY_INCLUDED
 | |
| #define AGG_ARRAY_INCLUDED
 | |
| 
 | |
| #include <cstddef>
 | |
| #include <cstring>
 | |
| #include "agg_basics.h"
 | |
| 
 | |
| namespace agg
 | |
| {
 | |
| 
 | |
|     //-------------------------------------------------------pod_array_adaptor
 | |
|     template <class T>
 | |
|     class pod_array_adaptor
 | |
|     {
 | |
|     public:
 | |
|         typedef T value_type;
 | |
|         pod_array_adaptor(T* array, unsigned size): m_array(array), m_size(size)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         unsigned size() const
 | |
|         {
 | |
|             return m_size;
 | |
|         }
 | |
|         const T& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& operator[](unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         const T& at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& at(unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T value_at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         T* m_array;
 | |
|         unsigned m_size;
 | |
|     };
 | |
| 
 | |
|     //---------------------------------------------------------pod_auto_array
 | |
|     template <class T, unsigned Size>
 | |
|     class pod_auto_array
 | |
|     {
 | |
|     public:
 | |
|         typedef T value_type;
 | |
|         typedef pod_auto_array<T, Size> self_type;
 | |
| 
 | |
|         pod_auto_array() {}
 | |
|         explicit pod_auto_array(const T* c)
 | |
|         {
 | |
|             std::memcpy(m_array, c, sizeof(T) * Size);
 | |
|         }
 | |
| 
 | |
|         const self_type& operator=(const T* c)
 | |
|         {
 | |
|             std::memcpy(m_array, c, sizeof(T) * Size);
 | |
|             return *this;
 | |
|         }
 | |
| 
 | |
|         static unsigned size()
 | |
|         {
 | |
|             return Size;
 | |
|         }
 | |
|         const T& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& operator[](unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         const T& at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& at(unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T value_at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         T m_array[Size];
 | |
|     };
 | |
| 
 | |
|     //--------------------------------------------------------pod_auto_vector
 | |
|     template <class T, unsigned Size>
 | |
|     class pod_auto_vector
 | |
|     {
 | |
|     public:
 | |
|         typedef T value_type;
 | |
|         typedef pod_auto_vector<T, Size> self_type;
 | |
| 
 | |
|         pod_auto_vector(): m_size(0) {}
 | |
| 
 | |
|         void remove_all()
 | |
|         {
 | |
|             m_size = 0;
 | |
|         }
 | |
|         void clear()
 | |
|         {
 | |
|             m_size = 0;
 | |
|         }
 | |
|         void add(const T& v)
 | |
|         {
 | |
|             m_array[m_size++] = v;
 | |
|         }
 | |
|         void push_back(const T& v)
 | |
|         {
 | |
|             m_array[m_size++] = v;
 | |
|         }
 | |
|         void inc_size(unsigned size)
 | |
|         {
 | |
|             m_size += size;
 | |
|         }
 | |
| 
 | |
|         unsigned size() const
 | |
|         {
 | |
|             return m_size;
 | |
|         }
 | |
|         const T& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& operator[](unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         const T& at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& at(unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T value_at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         T m_array[Size];
 | |
|         unsigned m_size;
 | |
|     };
 | |
| 
 | |
|     //---------------------------------------------------------------pod_array
 | |
|     template <class T>
 | |
|     class pod_array
 | |
|     {
 | |
|     public:
 | |
|         typedef T value_type;
 | |
|         typedef pod_array<T> self_type;
 | |
| 
 | |
|         ~pod_array()
 | |
|         {
 | |
|             pod_allocator<T>::deallocate(m_array, m_size);
 | |
|         }
 | |
|         pod_array(): m_array(0), m_size(0) {}
 | |
| 
 | |
|         pod_array(unsigned size):
 | |
|             m_array(pod_allocator<T>::allocate(size)),
 | |
|             m_size(size)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         pod_array(const self_type& v):
 | |
|             m_array(pod_allocator<T>::allocate(v.m_size)),
 | |
|             m_size(v.m_size)
 | |
|         {
 | |
|             std::memcpy(m_array, v.m_array, sizeof(T) * m_size);
 | |
|         }
 | |
| 
 | |
|         void resize(unsigned size)
 | |
|         {
 | |
|             if (size != m_size)
 | |
|             {
 | |
|                 pod_allocator<T>::deallocate(m_array, m_size);
 | |
|                 m_array = pod_allocator<T>::allocate(m_size = size);
 | |
|             }
 | |
|         }
 | |
|         const self_type& operator=(const self_type& v)
 | |
|         {
 | |
|             resize(v.size());
 | |
|             std::memcpy(m_array, v.m_array, sizeof(T) * m_size);
 | |
|             return *this;
 | |
|         }
 | |
| 
 | |
|         unsigned size() const
 | |
|         {
 | |
|             return m_size;
 | |
|         }
 | |
|         const T& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& operator[](unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         const T& at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& at(unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T value_at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
| 
 | |
|         const T* data() const
 | |
|         {
 | |
|             return m_array;
 | |
|         }
 | |
|         T* data()
 | |
|         {
 | |
|             return m_array;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         T* m_array;
 | |
|         unsigned m_size;
 | |
|     };
 | |
| 
 | |
|     //--------------------------------------------------------------pod_vector
 | |
|     // A simple class template to store Plain Old Data, a vector
 | |
|     // of a fixed size. The data is continous in memory
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     class pod_vector
 | |
|     {
 | |
|     public:
 | |
|         typedef T value_type;
 | |
| 
 | |
|         ~pod_vector()
 | |
|         {
 | |
|             pod_allocator<T>::deallocate(m_array, m_capacity);
 | |
|         }
 | |
|         pod_vector(): m_size(0), m_capacity(0), m_array(0) {}
 | |
|         pod_vector(unsigned cap, unsigned extra_tail = 0);
 | |
| 
 | |
|         // Copying
 | |
|         pod_vector(const pod_vector<T>&);
 | |
|         const pod_vector<T>& operator=(const pod_vector<T>&);
 | |
| 
 | |
|         // Set new capacity. All data is lost, size is set to zero.
 | |
|         void capacity(unsigned cap, unsigned extra_tail = 0);
 | |
|         unsigned capacity() const
 | |
|         {
 | |
|             return m_capacity;
 | |
|         }
 | |
| 
 | |
|         // Allocate n elements. All data is lost,
 | |
|         // but elements can be accessed in range 0...size-1.
 | |
|         void allocate(unsigned size, unsigned extra_tail = 0);
 | |
| 
 | |
|         // Resize keeping the content.
 | |
|         void resize(unsigned new_size);
 | |
| 
 | |
|         void zero()
 | |
|         {
 | |
|             std::memset(m_array, 0, sizeof(T) * m_size);
 | |
|         }
 | |
| 
 | |
|         void add(const T& v)
 | |
|         {
 | |
|             m_array[m_size++] = v;
 | |
|         }
 | |
|         void push_back(const T& v)
 | |
|         {
 | |
|             m_array[m_size++] = v;
 | |
|         }
 | |
|         void insert_at(unsigned pos, const T& val);
 | |
|         void inc_size(unsigned size)
 | |
|         {
 | |
|             m_size += size;
 | |
|         }
 | |
|         unsigned size() const
 | |
|         {
 | |
|             return m_size;
 | |
|         }
 | |
|         unsigned byte_size() const
 | |
|         {
 | |
|             return m_size * sizeof(T);
 | |
|         }
 | |
|         void serialize(int8u* ptr) const;
 | |
|         void deserialize(const int8u* data, unsigned byte_size);
 | |
|         const T& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& operator[](unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         const T& at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T& at(unsigned i)
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
|         T value_at(unsigned i) const
 | |
|         {
 | |
|             return m_array[i];
 | |
|         }
 | |
| 
 | |
|         const T* data() const
 | |
|         {
 | |
|             return m_array;
 | |
|         }
 | |
|         T* data()
 | |
|         {
 | |
|             return m_array;
 | |
|         }
 | |
| 
 | |
|         void remove_all()
 | |
|         {
 | |
|             m_size = 0;
 | |
|         }
 | |
|         void clear()
 | |
|         {
 | |
|             m_size = 0;
 | |
|         }
 | |
|         void cut_at(unsigned num)
 | |
|         {
 | |
|             if (num < m_size)
 | |
|                 m_size = num;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         unsigned m_size;
 | |
|         unsigned m_capacity;
 | |
|         T* m_array;
 | |
|     };
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     void pod_vector<T>::capacity(unsigned cap, unsigned extra_tail)
 | |
|     {
 | |
|         m_size = 0;
 | |
|         if (cap > m_capacity)
 | |
|         {
 | |
|             pod_allocator<T>::deallocate(m_array, m_capacity);
 | |
|             m_capacity = cap + extra_tail;
 | |
|             m_array = m_capacity ? pod_allocator<T>::allocate(m_capacity) : 0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     void pod_vector<T>::allocate(unsigned size, unsigned extra_tail)
 | |
|     {
 | |
|         capacity(size, extra_tail);
 | |
|         m_size = size;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     void pod_vector<T>::resize(unsigned new_size)
 | |
|     {
 | |
|         if (new_size > m_size)
 | |
|         {
 | |
|             if (new_size > m_capacity)
 | |
|             {
 | |
|                 T* data = pod_allocator<T>::allocate(new_size);
 | |
|                 std::memcpy(data, m_array, m_size * sizeof(T));
 | |
|                 pod_allocator<T>::deallocate(m_array, m_capacity);
 | |
|                 m_array = data;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             m_size = new_size;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     pod_vector<T>::pod_vector(unsigned cap, unsigned extra_tail):
 | |
|         m_size(0),
 | |
|         m_capacity(cap + extra_tail),
 | |
|         m_array(pod_allocator<T>::allocate(m_capacity))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     pod_vector<T>::pod_vector(const pod_vector<T>& v):
 | |
|         m_size(v.m_size),
 | |
|         m_capacity(v.m_capacity),
 | |
|         m_array(v.m_capacity ? pod_allocator<T>::allocate(v.m_capacity) : 0)
 | |
|     {
 | |
|         std::memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     const pod_vector<T>& pod_vector<T>::operator=(const pod_vector<T>& v)
 | |
|     {
 | |
|         allocate(v.m_size);
 | |
|         if (v.m_size)
 | |
|             std::memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     void pod_vector<T>::serialize(int8u* ptr) const
 | |
|     {
 | |
|         if (m_size)
 | |
|             std::memcpy(ptr, m_array, m_size * sizeof(T));
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     void pod_vector<T>::deserialize(const int8u* data, unsigned byte_size)
 | |
|     {
 | |
|         byte_size /= sizeof(T);
 | |
|         allocate(byte_size);
 | |
|         if (byte_size)
 | |
|             std::memcpy(m_array, data, byte_size * sizeof(T));
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T>
 | |
|     void pod_vector<T>::insert_at(unsigned pos, const T& val)
 | |
|     {
 | |
|         if (pos >= m_size)
 | |
|         {
 | |
|             m_array[m_size] = val;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             std::memmove(
 | |
|                 m_array + pos + 1, m_array + pos, (m_size - pos) * sizeof(T));
 | |
|             m_array[pos] = val;
 | |
|         }
 | |
|         ++m_size;
 | |
|     }
 | |
| 
 | |
|     //---------------------------------------------------------------pod_bvector
 | |
|     // A simple class template to store Plain Old Data, similar to std::deque
 | |
|     // It doesn't reallocate memory but instead, uses blocks of data of size
 | |
|     // of (1 << S), that is, power of two. The data is NOT contiguous in memory,
 | |
|     // so the only valid access method is operator [] or curr(), prev(), next()
 | |
|     //
 | |
|     // There reallocs occure only when the pool of pointers to blocks needs
 | |
|     // to be extended (it happens very rarely). You can control the value
 | |
|     // of increment to reallocate the pointer buffer. See the second
 | |
|     // constructor. By default, the incremeent value equals (1 << S), i.e., the
 | |
|     // block size.
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S = 6>
 | |
|     class pod_bvector
 | |
|     {
 | |
|     public:
 | |
|         enum block_scale_e
 | |
|         {
 | |
|             block_shift = S,
 | |
|             block_size = 1 << block_shift,
 | |
|             block_mask = block_size - 1
 | |
|         };
 | |
| 
 | |
|         typedef T value_type;
 | |
| 
 | |
|         ~pod_bvector();
 | |
|         pod_bvector();
 | |
|         pod_bvector(unsigned block_ptr_inc);
 | |
| 
 | |
|         // Copying
 | |
|         pod_bvector(const pod_bvector<T, S>& v);
 | |
|         const pod_bvector<T, S>& operator=(const pod_bvector<T, S>& v);
 | |
| 
 | |
|         void remove_all()
 | |
|         {
 | |
|             m_size = 0;
 | |
|         }
 | |
|         void clear()
 | |
|         {
 | |
|             m_size = 0;
 | |
|         }
 | |
|         void free_all()
 | |
|         {
 | |
|             free_tail(0);
 | |
|         }
 | |
|         void free_tail(unsigned size);
 | |
|         void add(const T& val);
 | |
|         void push_back(const T& val)
 | |
|         {
 | |
|             add(val);
 | |
|         }
 | |
|         void modify_last(const T& val);
 | |
|         void remove_last();
 | |
| 
 | |
|         int allocate_continuous_block(unsigned num_elements);
 | |
| 
 | |
|         void add_array(const T* ptr, unsigned num_elem)
 | |
|         {
 | |
|             while (num_elem--)
 | |
|             {
 | |
|                 add(*ptr++);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         template <class DataAccessor>
 | |
|         void add_data(DataAccessor& data)
 | |
|         {
 | |
|             while (data.size())
 | |
|             {
 | |
|                 add(*data);
 | |
|                 ++data;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void cut_at(unsigned size)
 | |
|         {
 | |
|             if (size < m_size)
 | |
|                 m_size = size;
 | |
|         }
 | |
| 
 | |
|         unsigned size() const
 | |
|         {
 | |
|             return m_size;
 | |
|         }
 | |
| 
 | |
|         const T& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_blocks[i >> block_shift][i & block_mask];
 | |
|         }
 | |
| 
 | |
|         T& operator[](unsigned i)
 | |
|         {
 | |
|             return m_blocks[i >> block_shift][i & block_mask];
 | |
|         }
 | |
| 
 | |
|         const T& at(unsigned i) const
 | |
|         {
 | |
|             return m_blocks[i >> block_shift][i & block_mask];
 | |
|         }
 | |
| 
 | |
|         T& at(unsigned i)
 | |
|         {
 | |
|             return m_blocks[i >> block_shift][i & block_mask];
 | |
|         }
 | |
| 
 | |
|         T value_at(unsigned i) const
 | |
|         {
 | |
|             return m_blocks[i >> block_shift][i & block_mask];
 | |
|         }
 | |
| 
 | |
|         const T& curr(unsigned idx) const
 | |
|         {
 | |
|             return (*this)[idx];
 | |
|         }
 | |
| 
 | |
|         T& curr(unsigned idx)
 | |
|         {
 | |
|             return (*this)[idx];
 | |
|         }
 | |
| 
 | |
|         const T& prev(unsigned idx) const
 | |
|         {
 | |
|             return (*this)[(idx + m_size - 1) % m_size];
 | |
|         }
 | |
| 
 | |
|         T& prev(unsigned idx)
 | |
|         {
 | |
|             return (*this)[(idx + m_size - 1) % m_size];
 | |
|         }
 | |
| 
 | |
|         const T& next(unsigned idx) const
 | |
|         {
 | |
|             return (*this)[(idx + 1) % m_size];
 | |
|         }
 | |
| 
 | |
|         T& next(unsigned idx)
 | |
|         {
 | |
|             return (*this)[(idx + 1) % m_size];
 | |
|         }
 | |
| 
 | |
|         const T& last() const
 | |
|         {
 | |
|             return (*this)[m_size - 1];
 | |
|         }
 | |
| 
 | |
|         T& last()
 | |
|         {
 | |
|             return (*this)[m_size - 1];
 | |
|         }
 | |
| 
 | |
|         unsigned byte_size() const;
 | |
|         void serialize(int8u* ptr) const;
 | |
|         void deserialize(const int8u* data, unsigned byte_size);
 | |
|         void deserialize(unsigned start,
 | |
|             const T& empty_val,
 | |
|             const int8u* data,
 | |
|             unsigned byte_size);
 | |
| 
 | |
|         template <class ByteAccessor>
 | |
|         void deserialize(ByteAccessor data)
 | |
|         {
 | |
|             remove_all();
 | |
|             unsigned elem_size = data.size() / sizeof(T);
 | |
| 
 | |
|             for (unsigned i = 0; i < elem_size; ++i)
 | |
|             {
 | |
|                 int8u* ptr = (int8u*)data_ptr();
 | |
|                 for (unsigned j = 0; j < sizeof(T); ++j)
 | |
|                 {
 | |
|                     *ptr++ = *data;
 | |
|                     ++data;
 | |
|                 }
 | |
|                 ++m_size;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         template <class ByteAccessor>
 | |
|         void deserialize(unsigned start, const T& empty_val, ByteAccessor data)
 | |
|         {
 | |
|             while (m_size < start)
 | |
|             {
 | |
|                 add(empty_val);
 | |
|             }
 | |
| 
 | |
|             unsigned elem_size = data.size() / sizeof(T);
 | |
|             for (unsigned i = 0; i < elem_size; ++i)
 | |
|             {
 | |
|                 int8u* ptr;
 | |
|                 if (start + i < m_size)
 | |
|                 {
 | |
|                     ptr = (int8u*)(&((*this)[start + i]));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     ptr = (int8u*)data_ptr();
 | |
|                     ++m_size;
 | |
|                 }
 | |
|                 for (unsigned j = 0; j < sizeof(T); ++j)
 | |
|                 {
 | |
|                     *ptr++ = *data;
 | |
|                     ++data;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         const T* block(unsigned nb) const
 | |
|         {
 | |
|             return m_blocks[nb];
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         void allocate_block(unsigned nb);
 | |
|         T* data_ptr();
 | |
| 
 | |
|         unsigned m_size;
 | |
|         unsigned m_num_blocks;
 | |
|         unsigned m_max_blocks;
 | |
|         T** m_blocks;
 | |
|         unsigned m_block_ptr_inc;
 | |
|     };
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     pod_bvector<T, S>::~pod_bvector()
 | |
|     {
 | |
|         if (m_num_blocks)
 | |
|         {
 | |
|             T** blk = m_blocks + m_num_blocks - 1;
 | |
|             while (m_num_blocks--)
 | |
|             {
 | |
|                 pod_allocator<T>::deallocate(*blk, block_size);
 | |
|                 --blk;
 | |
|             }
 | |
|         }
 | |
|         pod_allocator<T*>::deallocate(m_blocks, m_max_blocks);
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     void pod_bvector<T, S>::free_tail(unsigned size)
 | |
|     {
 | |
|         if (size < m_size)
 | |
|         {
 | |
|             unsigned nb = (size + block_mask) >> block_shift;
 | |
|             while (m_num_blocks > nb)
 | |
|             {
 | |
|                 pod_allocator<T>::deallocate(
 | |
|                     m_blocks[--m_num_blocks], block_size);
 | |
|             }
 | |
|             if (m_num_blocks == 0)
 | |
|             {
 | |
|                 pod_allocator<T*>::deallocate(m_blocks, m_max_blocks);
 | |
|                 m_blocks = 0;
 | |
|                 m_max_blocks = 0;
 | |
|             }
 | |
|             m_size = size;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     pod_bvector<T, S>::pod_bvector():
 | |
|         m_size(0),
 | |
|         m_num_blocks(0),
 | |
|         m_max_blocks(0),
 | |
|         m_blocks(0),
 | |
|         m_block_ptr_inc(block_size)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     pod_bvector<T, S>::pod_bvector(unsigned block_ptr_inc):
 | |
|         m_size(0),
 | |
|         m_num_blocks(0),
 | |
|         m_max_blocks(0),
 | |
|         m_blocks(0),
 | |
|         m_block_ptr_inc(block_ptr_inc)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     pod_bvector<T, S>::pod_bvector(const pod_bvector<T, S>& v):
 | |
|         m_size(v.m_size),
 | |
|         m_num_blocks(v.m_num_blocks),
 | |
|         m_max_blocks(v.m_max_blocks),
 | |
|         m_blocks(
 | |
|             v.m_max_blocks ? pod_allocator<T*>::allocate(v.m_max_blocks) : 0),
 | |
|         m_block_ptr_inc(v.m_block_ptr_inc)
 | |
|     {
 | |
|         unsigned i;
 | |
|         for (i = 0; i < v.m_num_blocks; ++i)
 | |
|         {
 | |
|             m_blocks[i] = pod_allocator<T>::allocate(block_size);
 | |
|             std::memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     const pod_bvector<T, S>& pod_bvector<T, S>::operator=(
 | |
|         const pod_bvector<T, S>& v)
 | |
|     {
 | |
|         unsigned i;
 | |
|         for (i = m_num_blocks; i < v.m_num_blocks; ++i)
 | |
|         {
 | |
|             allocate_block(i);
 | |
|         }
 | |
|         for (i = 0; i < v.m_num_blocks; ++i)
 | |
|         {
 | |
|             std::memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
 | |
|         }
 | |
|         m_size = v.m_size;
 | |
|         return *this;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     void pod_bvector<T, S>::allocate_block(unsigned nb)
 | |
|     {
 | |
|         if (nb >= m_max_blocks)
 | |
|         {
 | |
|             T** new_blocks =
 | |
|                 pod_allocator<T*>::allocate(m_max_blocks + m_block_ptr_inc);
 | |
| 
 | |
|             if (m_blocks)
 | |
|             {
 | |
|                 std::memcpy(new_blocks, m_blocks, m_num_blocks * sizeof(T*));
 | |
| 
 | |
|                 pod_allocator<T*>::deallocate(m_blocks, m_max_blocks);
 | |
|             }
 | |
|             m_blocks = new_blocks;
 | |
|             m_max_blocks += m_block_ptr_inc;
 | |
|         }
 | |
|         m_blocks[nb] = pod_allocator<T>::allocate(block_size);
 | |
|         m_num_blocks++;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     inline T* pod_bvector<T, S>::data_ptr()
 | |
|     {
 | |
|         unsigned nb = m_size >> block_shift;
 | |
|         if (nb >= m_num_blocks)
 | |
|         {
 | |
|             allocate_block(nb);
 | |
|         }
 | |
|         return m_blocks[nb] + (m_size & block_mask);
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     inline void pod_bvector<T, S>::add(const T& val)
 | |
|     {
 | |
|         *data_ptr() = val;
 | |
|         ++m_size;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     inline void pod_bvector<T, S>::remove_last()
 | |
|     {
 | |
|         if (m_size)
 | |
|             --m_size;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     void pod_bvector<T, S>::modify_last(const T& val)
 | |
|     {
 | |
|         remove_last();
 | |
|         add(val);
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     int pod_bvector<T, S>::allocate_continuous_block(unsigned num_elements)
 | |
|     {
 | |
|         if (num_elements < block_size)
 | |
|         {
 | |
|             data_ptr(); // Allocate initial block if necessary
 | |
|             unsigned rest = block_size - (m_size & block_mask);
 | |
|             unsigned index;
 | |
|             if (num_elements <= rest)
 | |
|             {
 | |
|                 // The rest of the block is good, we can use it
 | |
|                 //-----------------
 | |
|                 index = m_size;
 | |
|                 m_size += num_elements;
 | |
|                 return index;
 | |
|             }
 | |
| 
 | |
|             // New block
 | |
|             //---------------
 | |
|             m_size += rest;
 | |
|             data_ptr();
 | |
|             index = m_size;
 | |
|             m_size += num_elements;
 | |
|             return index;
 | |
|         }
 | |
|         return -1; // Impossible to allocate
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     unsigned pod_bvector<T, S>::byte_size() const
 | |
|     {
 | |
|         return m_size * sizeof(T);
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     void pod_bvector<T, S>::serialize(int8u* ptr) const
 | |
|     {
 | |
|         unsigned i;
 | |
|         for (i = 0; i < m_size; i++)
 | |
|         {
 | |
|             std::memcpy(ptr, &(*this)[i], sizeof(T));
 | |
|             ptr += sizeof(T);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     void pod_bvector<T, S>::deserialize(const int8u* data, unsigned byte_size)
 | |
|     {
 | |
|         remove_all();
 | |
|         byte_size /= sizeof(T);
 | |
|         for (unsigned i = 0; i < byte_size; ++i)
 | |
|         {
 | |
|             T* ptr = data_ptr();
 | |
|             std::memcpy(ptr, data, sizeof(T));
 | |
|             ++m_size;
 | |
|             data += sizeof(T);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Replace or add a number of elements starting from "start" position
 | |
|     //------------------------------------------------------------------------
 | |
|     template <class T, unsigned S>
 | |
|     void pod_bvector<T, S>::deserialize(unsigned start,
 | |
|         const T& empty_val,
 | |
|         const int8u* data,
 | |
|         unsigned byte_size)
 | |
|     {
 | |
|         while (m_size < start)
 | |
|         {
 | |
|             add(empty_val);
 | |
|         }
 | |
| 
 | |
|         byte_size /= sizeof(T);
 | |
|         for (unsigned i = 0; i < byte_size; ++i)
 | |
|         {
 | |
|             if (start + i < m_size)
 | |
|             {
 | |
|                 std::memcpy(&((*this)[start + i]), data, sizeof(T));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 T* ptr = data_ptr();
 | |
|                 std::memcpy(ptr, data, sizeof(T));
 | |
|                 ++m_size;
 | |
|             }
 | |
|             data += sizeof(T);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //---------------------------------------------------------block_allocator
 | |
|     // Allocator for arbitrary POD data. Most usable in different cache
 | |
|     // systems for efficient memory allocations.
 | |
|     // Memory is allocated with blocks of fixed size ("block_size" in
 | |
|     // the constructor). If required size exceeds the block size the allocator
 | |
|     // creates a new block of the required size. However, the most efficient
 | |
|     // use is when the average reqired size is much less than the block size.
 | |
|     //------------------------------------------------------------------------
 | |
|     class block_allocator
 | |
|     {
 | |
|         struct block_type
 | |
|         {
 | |
|             int8u* data;
 | |
|             unsigned size;
 | |
|         };
 | |
| 
 | |
|     public:
 | |
|         void remove_all()
 | |
|         {
 | |
|             if (m_num_blocks)
 | |
|             {
 | |
|                 block_type* blk = m_blocks + m_num_blocks - 1;
 | |
|                 while (m_num_blocks--)
 | |
|                 {
 | |
|                     pod_allocator<int8u>::deallocate(blk->data, blk->size);
 | |
|                     --blk;
 | |
|                 }
 | |
|                 pod_allocator<block_type>::deallocate(m_blocks, m_max_blocks);
 | |
|             }
 | |
|             m_num_blocks = 0;
 | |
|             m_max_blocks = 0;
 | |
|             m_blocks = 0;
 | |
|             m_buf_ptr = 0;
 | |
|             m_rest = 0;
 | |
|         }
 | |
| 
 | |
|         ~block_allocator()
 | |
|         {
 | |
|             remove_all();
 | |
|         }
 | |
| 
 | |
|         block_allocator(unsigned block_size, unsigned block_ptr_inc = 256 - 8):
 | |
|             m_block_size(block_size),
 | |
|             m_block_ptr_inc(block_ptr_inc),
 | |
|             m_num_blocks(0),
 | |
|             m_max_blocks(0),
 | |
|             m_blocks(0),
 | |
|             m_buf_ptr(0),
 | |
|             m_rest(0)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         int8u* allocate(unsigned size, unsigned alignment = 1)
 | |
|         {
 | |
|             if (size == 0)
 | |
|                 return 0;
 | |
|             if (size <= m_rest)
 | |
|             {
 | |
|                 int8u* ptr = m_buf_ptr;
 | |
|                 if (alignment > 1)
 | |
|                 {
 | |
|                     unsigned align =
 | |
|                         (alignment - unsigned((std::size_t)ptr) % alignment) %
 | |
|                         alignment;
 | |
| 
 | |
|                     size += align;
 | |
|                     ptr += align;
 | |
|                     if (size <= m_rest)
 | |
|                     {
 | |
|                         m_rest -= size;
 | |
|                         m_buf_ptr += size;
 | |
|                         return ptr;
 | |
|                     }
 | |
|                     allocate_block(size);
 | |
|                     return allocate(size - align, alignment);
 | |
|                 }
 | |
|                 m_rest -= size;
 | |
|                 m_buf_ptr += size;
 | |
|                 return ptr;
 | |
|             }
 | |
|             allocate_block(size + alignment - 1);
 | |
|             return allocate(size, alignment);
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         void allocate_block(unsigned size)
 | |
|         {
 | |
|             if (size < m_block_size)
 | |
|                 size = m_block_size;
 | |
|             if (m_num_blocks >= m_max_blocks)
 | |
|             {
 | |
|                 block_type* new_blocks = pod_allocator<block_type>::allocate(
 | |
|                     m_max_blocks + m_block_ptr_inc);
 | |
| 
 | |
|                 if (m_blocks)
 | |
|                 {
 | |
|                     std::memcpy(new_blocks,
 | |
|                         m_blocks,
 | |
|                         m_num_blocks * sizeof(block_type));
 | |
|                     pod_allocator<block_type>::deallocate(
 | |
|                         m_blocks, m_max_blocks);
 | |
|                 }
 | |
|                 m_blocks = new_blocks;
 | |
|                 m_max_blocks += m_block_ptr_inc;
 | |
|             }
 | |
| 
 | |
|             m_blocks[m_num_blocks].size = size;
 | |
|             m_blocks[m_num_blocks].data = m_buf_ptr =
 | |
|                 pod_allocator<int8u>::allocate(size);
 | |
| 
 | |
|             m_num_blocks++;
 | |
|             m_rest = size;
 | |
|         }
 | |
| 
 | |
|         unsigned m_block_size;
 | |
|         unsigned m_block_ptr_inc;
 | |
|         unsigned m_num_blocks;
 | |
|         unsigned m_max_blocks;
 | |
|         block_type* m_blocks;
 | |
|         int8u* m_buf_ptr;
 | |
|         unsigned m_rest;
 | |
|     };
 | |
| 
 | |
|     //------------------------------------------------------------------------
 | |
|     enum quick_sort_threshold_e
 | |
|     {
 | |
|         quick_sort_threshold = 9
 | |
|     };
 | |
| 
 | |
|     //-----------------------------------------------------------swap_elements
 | |
|     template <class T>
 | |
|     inline void swap_elements(T& a, T& b)
 | |
|     {
 | |
|         T temp = a;
 | |
|         a = b;
 | |
|         b = temp;
 | |
|     }
 | |
| 
 | |
|     //--------------------------------------------------------------quick_sort
 | |
|     template <class Array, class Less>
 | |
|     void quick_sort(Array& arr, Less less)
 | |
|     {
 | |
|         if (arr.size() < 2)
 | |
|             return;
 | |
| 
 | |
|         typename Array::value_type* e1;
 | |
|         typename Array::value_type* e2;
 | |
| 
 | |
|         int stack[80];
 | |
|         int* top = stack;
 | |
|         int limit = arr.size();
 | |
|         int base = 0;
 | |
| 
 | |
|         for (;;)
 | |
|         {
 | |
|             int len = limit - base;
 | |
| 
 | |
|             int i;
 | |
|             int j;
 | |
|             int pivot;
 | |
| 
 | |
|             if (len > quick_sort_threshold)
 | |
|             {
 | |
|                 // we use base + len/2 as the pivot
 | |
|                 pivot = base + len / 2;
 | |
|                 swap_elements(arr[base], arr[pivot]);
 | |
| 
 | |
|                 i = base + 1;
 | |
|                 j = limit - 1;
 | |
| 
 | |
|                 // now ensure that *i <= *base <= *j
 | |
|                 e1 = &(arr[j]);
 | |
|                 e2 = &(arr[i]);
 | |
|                 if (less(*e1, *e2))
 | |
|                     swap_elements(*e1, *e2);
 | |
| 
 | |
|                 e1 = &(arr[base]);
 | |
|                 e2 = &(arr[i]);
 | |
|                 if (less(*e1, *e2))
 | |
|                     swap_elements(*e1, *e2);
 | |
| 
 | |
|                 e1 = &(arr[j]);
 | |
|                 e2 = &(arr[base]);
 | |
|                 if (less(*e1, *e2))
 | |
|                     swap_elements(*e1, *e2);
 | |
| 
 | |
|                 for (;;)
 | |
|                 {
 | |
|                     do
 | |
|                         i++;
 | |
|                     while (less(arr[i], arr[base]));
 | |
|                     do
 | |
|                         j--;
 | |
|                     while (less(arr[base], arr[j]));
 | |
| 
 | |
|                     if (i > j)
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     swap_elements(arr[i], arr[j]);
 | |
|                 }
 | |
| 
 | |
|                 swap_elements(arr[base], arr[j]);
 | |
| 
 | |
|                 // now, push the largest sub-array
 | |
|                 if (j - base > limit - i)
 | |
|                 {
 | |
|                     top[0] = base;
 | |
|                     top[1] = j;
 | |
|                     base = i;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     top[0] = i;
 | |
|                     top[1] = limit;
 | |
|                     limit = j;
 | |
|                 }
 | |
|                 top += 2;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // the sub-array is small, perform insertion sort
 | |
|                 j = base;
 | |
|                 i = j + 1;
 | |
| 
 | |
|                 for (; i < limit; j = i, i++)
 | |
|                 {
 | |
|                     for (; less(*(e1 = &(arr[j + 1])), *(e2 = &(arr[j]))); j--)
 | |
|                     {
 | |
|                         swap_elements(*e1, *e2);
 | |
|                         if (j == base)
 | |
|                         {
 | |
|                             break;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 if (top > stack)
 | |
|                 {
 | |
|                     top -= 2;
 | |
|                     base = top[0];
 | |
|                     limit = top[1];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------remove_duplicates
 | |
|     // Remove duplicates from a sorted array. It doesn't cut the
 | |
|     // tail of the array, it just returns the number of remaining elements.
 | |
|     //-----------------------------------------------------------------------
 | |
|     template <class Array, class Equal>
 | |
|     unsigned remove_duplicates(Array& arr, Equal equal)
 | |
|     {
 | |
|         if (arr.size() < 2)
 | |
|             return arr.size();
 | |
| 
 | |
|         unsigned i, j;
 | |
|         for (i = 1, j = 1; i < arr.size(); i++)
 | |
|         {
 | |
|             typename Array::value_type& e = arr[i];
 | |
|             if (!equal(e, arr[i - 1]))
 | |
|             {
 | |
|                 arr[j++] = e;
 | |
|             }
 | |
|         }
 | |
|         return j;
 | |
|     }
 | |
| 
 | |
|     //--------------------------------------------------------invert_container
 | |
|     template <class Array>
 | |
|     void invert_container(Array& arr)
 | |
|     {
 | |
|         int i = 0;
 | |
|         int j = arr.size() - 1;
 | |
|         while (i < j)
 | |
|         {
 | |
|             swap_elements(arr[i++], arr[j--]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------binary_search_pos
 | |
|     template <class Array, class Value, class Less>
 | |
|     unsigned binary_search_pos(const Array& arr, const Value& val, Less less)
 | |
|     {
 | |
|         if (arr.size() == 0)
 | |
|             return 0;
 | |
| 
 | |
|         unsigned beg = 0;
 | |
|         unsigned end = arr.size() - 1;
 | |
| 
 | |
|         if (less(val, arr[0]))
 | |
|             return 0;
 | |
|         if (less(arr[end], val))
 | |
|             return end + 1;
 | |
| 
 | |
|         while (end - beg > 1)
 | |
|         {
 | |
|             unsigned mid = (end + beg) >> 1;
 | |
|             if (less(val, arr[mid]))
 | |
|                 end = mid;
 | |
|             else
 | |
|                 beg = mid;
 | |
|         }
 | |
| 
 | |
|         // if(beg <= 0 && less(val, arr[0])) return 0;
 | |
|         // if(end >= arr.size() - 1 && less(arr[end], val)) ++end;
 | |
| 
 | |
|         return end;
 | |
|     }
 | |
| 
 | |
|     //----------------------------------------------------------range_adaptor
 | |
|     template <class Array>
 | |
|     class range_adaptor
 | |
|     {
 | |
|     public:
 | |
|         typedef typename Array::value_type value_type;
 | |
| 
 | |
|         range_adaptor(Array& array, unsigned start, unsigned size):
 | |
|             m_array(array),
 | |
|             m_start(start),
 | |
|             m_size(size)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         unsigned size() const
 | |
|         {
 | |
|             return m_size;
 | |
|         }
 | |
|         const value_type& operator[](unsigned i) const
 | |
|         {
 | |
|             return m_array[m_start + i];
 | |
|         }
 | |
|         value_type& operator[](unsigned i)
 | |
|         {
 | |
|             return m_array[m_start + i];
 | |
|         }
 | |
|         const value_type& at(unsigned i) const
 | |
|         {
 | |
|             return m_array[m_start + i];
 | |
|         }
 | |
|         value_type& at(unsigned i)
 | |
|         {
 | |
|             return m_array[m_start + i];
 | |
|         }
 | |
|         value_type value_at(unsigned i) const
 | |
|         {
 | |
|             return m_array[m_start + i];
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         Array& m_array;
 | |
|         unsigned m_start;
 | |
|         unsigned m_size;
 | |
|     };
 | |
| 
 | |
|     //---------------------------------------------------------------int_less
 | |
|     inline bool int_less(int a, int b)
 | |
|     {
 | |
|         return a < b;
 | |
|     }
 | |
| 
 | |
|     //------------------------------------------------------------int_greater
 | |
|     inline bool int_greater(int a, int b)
 | |
|     {
 | |
|         return a > b;
 | |
|     }
 | |
| 
 | |
|     //----------------------------------------------------------unsigned_less
 | |
|     inline bool unsigned_less(unsigned a, unsigned b)
 | |
|     {
 | |
|         return a < b;
 | |
|     }
 | |
| 
 | |
|     //-------------------------------------------------------unsigned_greater
 | |
|     inline bool unsigned_greater(unsigned a, unsigned b)
 | |
|     {
 | |
|         return a > b;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif
 |