// Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_ARRAY2D_KERNEl_1_ #define DLIB_ARRAY2D_KERNEl_1_ #include "array2d_kernel_abstract.h" #include "../algs.h" #include "../interfaces/enumerable.h" #include "../serialize.h" #include "../geometry/rectangle.h" namespace dlib { template < typename T, typename mem_manager = default_memory_manager > class array2d_kernel_1 : public enumerable<T> { /*! INITIAL VALUE - nc_ == 0 - nr_ == 0 - data == 0 - rows == 0 - at_start_ == true - cur == 0 - last == 0 CONVENTION - nc_ == nc() - nr_ == nc() - if (data != 0) then - last == a pointer to the last element in the data array - data == pointer to an array of nc_*nr_ T objects - rows == pointer to an array of nr_ row objects - for all x < nr_: - rows[x].data == data + x*nc_ - rows[x].nc_ == nc_ - else - nc_ == 0 - nr_ == 0 - data == 0 - rows == 0 - last == 0 - nr_ * nc_ == size() - if (cur == 0) then - current_element_valid() == false - else - current_element_valid() == true - *cur == element() - at_start_ == at_start() !*/ class row_helper; public: typedef T type; typedef mem_manager mem_manager_type; // ----------------------------------- class row { /*! CONVENTION - nc_ == nc() - for all x < nc_: - (*this)[x] == data[x] !*/ friend class array2d_kernel_1; friend class row_helper; public: long nc ( ) const { return nc_; } const T& operator[] ( long column ) const { return data[column]; } T& operator[] ( long column ) { return data[column]; } private: long nc_; T* data; // restricted functions row(){} row(row&); row& operator=(row&); }; // ----------------------------------- array2d_kernel_1 ( ) : nc_(0), nr_(0), rows(0), data(0), cur(0), last(0), at_start_(true) { } virtual ~array2d_kernel_1 ( ) { clear(); } long nc ( ) const { return nc_; } long nr ( ) const { return nr_; } row& operator[] ( long row ) { return rows[row]; } const row& operator[] ( long row ) const { return rows[row]; } void swap ( array2d_kernel_1& item ) { exchange(data,item.data); exchange(rows,item.rows); exchange(nr_,item.nr_); exchange(nc_,item.nc_); exchange(at_start_,item.at_start_); exchange(cur,item.cur); exchange(last,item.last); pool.swap(item.pool); rpool.swap(item.rpool); } void clear ( ) { if (data != 0) { rpool.deallocate_array(reinterpret_cast<row_helper*>(rows)); pool.deallocate_array(data); nc_ = 0; nr_ = 0; rows = 0; data = 0; at_start_ = true; cur = 0; last = 0; } } void set_size ( long nr__, long nc__ ); bool at_start ( ) const { return at_start_; } void reset ( ) const { at_start_ = true; cur = 0; } bool current_element_valid ( ) const { return (cur != 0); } const T& element ( ) const { return *cur; } T& element ( ) { return *cur; } bool move_next ( ) const { if (cur != 0) { if (cur != last) { ++cur; return true; } cur = 0; return false; } else if (at_start_) { cur = data; at_start_ = false; return (data != 0); } else { return false; } } unsigned long size ( ) const { return static_cast<unsigned long>(nc_ * nr_); } private: // this object exists just so we can have a row type object that // has a public default constructor so the memory_manager can construct it. // I would have made rpool a friend of row but some compilers can't handle // that without crapping out. class row_helper : public row {}; typename mem_manager::template rebind<T>::other pool; typename mem_manager::template rebind<row_helper>::other rpool; long nc_; long nr_; row* rows; T* data; mutable T* cur; T* last; mutable bool at_start_; // restricted functions array2d_kernel_1(array2d_kernel_1&); // copy constructor array2d_kernel_1& operator=(array2d_kernel_1&); // assignment operator }; // ---------------------------------------------------------------------------------------- template < typename T, typename mem_manager > inline void swap ( array2d_kernel_1<T,mem_manager>& a, array2d_kernel_1<T,mem_manager>& b ) { a.swap(b); } template < typename T, typename mem_manager > void serialize ( const array2d_kernel_1<T,mem_manager>& item, std::ostream& out ) { try { serialize(item.nc(),out); serialize(item.nr(),out); item.reset(); while (item.move_next()) serialize(item.element(),out); item.reset(); } catch (serialization_error e) { throw serialization_error(e.info + "\n while serializing object of type array2d_kernel_1"); } } template < typename T > void deserialize ( array2d_kernel_1<T>& item, std::istream& in ) { try { long nc, nr; deserialize(nc,in); deserialize(nr,in); item.set_size(nr,nc); while (item.move_next()) deserialize(item.element(),in); item.reset(); } catch (serialization_error e) { item.clear(); throw serialization_error(e.info + "\n while deserializing object of type array2d_kernel_1"); } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, typename mem_manager > void array2d_kernel_1<T,mem_manager>:: set_size ( long nr__, long nc__ ) { // set the enumerator back at the start at_start_ = true; cur = 0; // don't do anything if we are already the right size. if (nc_ == nc__ && nr_ == nr__) { return; } nc_ = nc__; nr_ = nr__; // free any existing memory if (data != 0) { pool.deallocate_array(data); rpool.deallocate_array(reinterpret_cast<row_helper*>(rows)); data = 0; rows = 0; } // now setup this object to have the new size try { if (nr_ > 0) { rows = rpool.allocate_array(nr_); data = pool.allocate_array(nr_*nc_); last = data + nr_*nc_ - 1; } } catch (...) { if (rows) rpool.deallocate_array(reinterpret_cast<row_helper*>(rows)); if (data) pool.deallocate_array(data); rows = 0; data = 0; nc_ = 0; nr_ = 0; last = 0; throw; } // now set up all the rows for (long i = 0; i < nr_; ++i) { rows[i].nc_ = nc_; rows[i].data = data + i*nc_; } } // ---------------------------------------------------------------------------------------- } #endif // DLIB_ARRAY2D_KERNEl_1_