#pragma once namespace pfc { template class t_alloc = alloc_standard> class array_t; //! Special simplififed version of array class that avoids stepping on landmines with classes without public copy operators/constructors. template class array_staticsize_t { public: typedef _t_item t_item; private: typedef array_staticsize_t t_self; public: array_staticsize_t() : m_array(NULL), m_size(0) {} array_staticsize_t(t_size p_size) : m_array(new t_item[p_size]), m_size(p_size) {} ~array_staticsize_t() {release_();} //! Copy constructor nonfunctional when data type is not copyable. array_staticsize_t(const t_self & p_source) : m_size(0), m_array(NULL) { *this = p_source; } array_staticsize_t(t_self && p_source) { move_(p_source); } //! Copy operator nonfunctional when data type is not copyable. const t_self & operator=(const t_self & p_source) { release_(); const t_size newsize = p_source.get_size(); if (newsize > 0) { m_array = new t_item[newsize]; m_size = newsize; for(t_size n = 0; n < newsize; n++) m_array[n] = p_source[n]; } return *this; } //! Move operator. const t_self & operator=(t_self && p_source) { release_(); move_(p_source); return *this; } void set_size_discard(t_size p_size) { release_(); if (p_size > 0) { m_array = new t_item[p_size]; m_size = p_size; } } template void set_data_fromptr(const t_source * p_buffer,t_size p_count) { if (p_count == m_size) { pfc::copy_array_loop_t(*this,p_buffer,p_count); } else { t_item * arr = new t_item[p_count]; try { pfc::copy_array_loop_t(arr, p_buffer, p_count); } catch(...) { delete[] arr; throw; } delete[] m_array; m_array = arr; m_size = p_count; } } template void assign(t_source const * items, size_t count) { set_data_fromptr( items, count ); } t_size get_size() const {return m_size;} t_size size() const {return m_size;} // std compat const t_item * get_ptr() const {return m_array;} t_item * get_ptr() {return m_array;} const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < get_size());return m_array[p_index];} t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < get_size());return m_array[p_index];} template bool is_owned(const t_source & p_item) {return pfc::is_pointer_in_range(get_ptr(),get_size(),&p_item);} template void enumerate(t_out & out) const { for(t_size walk = 0; walk < m_size; ++walk) out(m_array[walk]); } private: void release_() { m_size = 0; delete[] pfc::replace_null_t(m_array); } void move_(t_self & from) { m_size = from.m_size; m_array = from.m_array; from.m_size = 0; from.m_array = NULL; } t_item * m_array; t_size m_size; }; template void copy_array_t(t_to & p_to,const t_from & p_from) { const t_size size = array_size_t(p_from); if (p_to.has_owned_items(p_from)) {//avoid landmines with actual array data overlapping, or p_from being same as p_to array_staticsize_t temp; temp.set_size_discard(size); pfc::copy_array_loop_t(temp,p_from,size); p_to.set_size(size); pfc::copy_array_loop_t(p_to,temp,size); } else { p_to.set_size(size); pfc::copy_array_loop_t(p_to,p_from,size); } } template void fill_array_t(t_array & p_array,const t_value & p_value) { const t_size size = array_size_t(p_array); for(t_size n=0;n class t_alloc> class array_t { public: typedef _t_item t_item; private: typedef array_t t_self; public: array_t() {} array_t(const t_self & p_source) {copy_array_t(*this,p_source);} template array_t(const t_source & p_source) {copy_array_t(*this,p_source);} const t_self & operator=(const t_self & p_source) {copy_array_t(*this,p_source); return *this;} template const t_self & operator=(const t_source & p_source) {copy_array_t(*this,p_source); return *this;} array_t(t_self && p_source) {move_from(p_source);} const t_self & operator=(t_self && p_source) {move_from(p_source); return *this;} void set_size(t_size p_size) {m_alloc.set_size(p_size);} void resize( size_t s ) { set_size(s); } // std compat template void set_size_fill(size_t p_size, fill_t const & filler) { size_t before = get_size(); set_size( p_size ); for(size_t w = before; w < p_size; ++w) this->get_ptr()[w] = filler; } void set_size_in_range(size_t minSize, size_t maxSize) { if (minSize >= maxSize) { set_size( minSize); return; } size_t walk = maxSize; for(;;) { try { set_size(walk); return; } catch(std::bad_alloc) { if (walk <= minSize) throw; // go on } walk >>= 1; if (walk < minSize) walk = minSize; } } void set_size_discard(t_size p_size) {m_alloc.set_size(p_size);} void set_count(t_size p_count) {m_alloc.set_size(p_count);} t_size get_size() const {return m_alloc.get_size();} size_t size() const {return m_alloc.get_size();} // std compat t_size get_count() const {return m_alloc.get_size();} void force_reset() {m_alloc.force_reset();} const t_item & operator[](t_size p_index) const {PFC_ASSERT(p_index < get_size());return m_alloc[p_index];} t_item & operator[](t_size p_index) {PFC_ASSERT(p_index < get_size());return m_alloc[p_index];} //! Warning: buffer pointer must not point to buffer allocated by this array (fixme). template void set_data_fromptr(const t_source * p_buffer,t_size p_count) { set_size(p_count); pfc::copy_array_loop_t(*this,p_buffer,p_count); } template void append(const t_array & p_source) { if (has_owned_items(p_source)) append(array_t(p_source)); else { const t_size source_size = array_size_t(p_source); const t_size base = get_size(); increase_size(source_size); for(t_size n=0;n void insert_multi(const t_insert & value, t_size base, t_size count) { const t_size oldSize = get_size(); if (base > oldSize) base = oldSize; increase_size(count); pfc::memmove_t(get_ptr() + base + count, get_ptr() + base, oldSize - base); pfc::fill_ptr_t(get_ptr() + base, count, value); } template void append_multi(const t_append & value, t_size count) {insert_multi(value,~0,count);} //! Warning: buffer pointer must not point to buffer allocated by this array (fixme). template void append_fromptr(const t_append * p_buffer,t_size p_count) { PFC_ASSERT( !is_owned(&p_buffer[0]) ); t_size base = get_size(); increase_size(p_count); for(t_size n=0;n void add_item( item_t && item ) { const t_size base = get_size(); increase_size(1); m_alloc[base] = std::forward( item ); } template void append_single_val( item_t && item ) { const t_size base = get_size(); increase_size(1); m_alloc[base] = std::forward( item ); } template void append_single(const t_append & p_item) { if (is_owned(p_item)) append_single(t_append(p_item)); else { const t_size base = get_size(); increase_size(1); m_alloc[base] = p_item; } } template void fill(const t_filler & p_filler) { const t_size max = get_size(); for(t_size n=0;n get_size()) set_size(p_size); } //not supported by some allocs const t_item * get_ptr() const {return m_alloc.get_ptr();} t_item * get_ptr() {return m_alloc.get_ptr();} void prealloc(t_size p_size) {m_alloc.prealloc(p_size);} template bool has_owned_items(const t_array & p_source) { if (array_size_t(p_source) == 0) return false; //how the hell would we properly check if any of source items is owned by us, in case source array implements some weird mixing of references of items from different sources? //the most obvious way means evil bottleneck here (whether it matters or not from caller's point of view which does something O(n) already is another question) //at least this will work fine with all standard classes which don't crossreference anyhow and always use own storage //perhaps we'll traitify this someday later return is_owned(p_source[0]); } template bool is_owned(const t_source & p_item) { return m_alloc.is_ptr_owned(&p_item); } template void set_single(const t_item & p_item) { set_size(1); (*this)[0] = p_item; } template void enumerate(t_callback & p_callback) const { for(t_size n = 0; n < get_size(); n++ ) { p_callback((*this)[n]); } } void move_from(t_self & other) { m_alloc.move_from(other.m_alloc); } private: t_alloc m_alloc; }; template class t_alloc = alloc_standard > class array_hybrid_t : public array_t::template alloc > {}; template class traits_t > : public traits_default_movable {}; template class t_alloc> class traits_t > : public pfc::traits_t > {}; template class comparator_array { public: template static int compare(const t_array1 & p_array1, const t_array2 & p_array2) { t_size walk = 0; for(;;) { if (walk >= p_array1.get_size() && walk >= p_array2.get_size()) return 0; else if (walk >= p_array1.get_size()) return -1; else if (walk >= p_array2.get_size()) return 1; else { int state = t_comparator::compare(p_array1[walk],p_array2[walk]); if (state != 0) return state; } ++walk; } } }; template static bool array_equals(const t_a1 & arr1, const t_a2 & arr2) { const t_size s = array_size_t(arr1); if (s != array_size_t(arr2)) return false; for(t_size walk = 0; walk < s; ++walk) { if (arr1[walk] != arr2[walk]) return false; } return true; } template class t_alloc = alloc_standard> class array_2d_t { public: array_2d_t() : m_d1(), m_d2() {} void set_size(t_size d1, t_size d2) { m_content.set_size(pfc::mul_safe_t(d1, d2)); m_d1 = d1; m_d2 = d2; } t_size get_dim1() const {return m_d1;} t_size get_dim2() const {return m_d2;} t_item & at(t_size i1, t_size i2) { return * _transformPtr(m_content.get_ptr(), i1, i2); } const t_item & at(t_size i1, t_size i2) const { return * _transformPtr(m_content.get_ptr(), i1, i2); } template void fill(const t_filler & p_filler) {m_content.fill(p_filler);} void fill_null() {m_content.fill_null();} t_item * rowPtr(t_size i1) {return _transformPtr(m_content.get_ptr(), i1, 0);} const t_item * rowPtr(t_size i1) const {return _transformPtr(m_content.get_ptr(), i1, 0);} const t_item * operator[](t_size i1) const {return rowPtr(i1);} t_item * operator[](t_size i1) {return rowPtr(i1);} private: template t_ptr _transformPtr(t_ptr ptr, t_size i1, t_size i2) const { PFC_ASSERT( i1 < m_d1 ); PFC_ASSERT( i2 < m_d2 ); return ptr + i1 * m_d2 + i2; } pfc::array_t m_content; t_size m_d1, m_d2; }; }