mirror of
https://gitcode.com/gh_mirrors/ope/OpenFace.git
synced 2026-03-09 14:40:17 +00:00
523 lines
13 KiB
C++
523 lines
13 KiB
C++
// 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 : public enumerable<T>
|
|
{
|
|
|
|
/*!
|
|
INITIAL VALUE
|
|
- nc_ == 0
|
|
- nr_ == 0
|
|
- data == 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
|
|
- else
|
|
- nc_ == 0
|
|
- nr_ == 0
|
|
- data == 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:
|
|
|
|
// These typedefs are here for backwards compatibility with older versions of dlib.
|
|
typedef array2d kernel_1a;
|
|
typedef array2d kernel_1a_c;
|
|
|
|
typedef T type;
|
|
typedef mem_manager mem_manager_type;
|
|
typedef T* iterator;
|
|
typedef const T* const_iterator;
|
|
|
|
|
|
// -----------------------------------
|
|
|
|
class row
|
|
{
|
|
/*!
|
|
CONVENTION
|
|
- nc_ == nc()
|
|
- for all x < nc_:
|
|
- (*this)[x] == data[x]
|
|
!*/
|
|
|
|
friend class array2d<T,mem_manager>;
|
|
friend class row_helper;
|
|
|
|
public:
|
|
long nc (
|
|
) const { return nc_; }
|
|
|
|
const T& operator[] (
|
|
long column
|
|
) const
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(column < nc() && column >= 0,
|
|
"\tconst T& array2d::operator[](long column) const"
|
|
<< "\n\tThe column index given must be less than the number of columns."
|
|
<< "\n\tthis: " << this
|
|
<< "\n\tcolumn: " << column
|
|
<< "\n\tnc(): " << nc()
|
|
);
|
|
|
|
return data[column];
|
|
}
|
|
|
|
T& operator[] (
|
|
long column
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(column < nc() && column >= 0,
|
|
"\tT& array2d::operator[](long column)"
|
|
<< "\n\tThe column index given must be less than the number of columns."
|
|
<< "\n\tthis: " << this
|
|
<< "\n\tcolumn: " << column
|
|
<< "\n\tnc(): " << nc()
|
|
);
|
|
|
|
return data[column];
|
|
}
|
|
|
|
private:
|
|
|
|
row(T* data_, long cols) : data(data_), nc_(cols) {}
|
|
|
|
T* data;
|
|
long nc_;
|
|
|
|
|
|
// restricted functions
|
|
row(){}
|
|
row& operator=(row&);
|
|
};
|
|
|
|
// -----------------------------------
|
|
|
|
array2d (
|
|
) :
|
|
data(0),
|
|
nc_(0),
|
|
nr_(0),
|
|
cur(0),
|
|
last(0),
|
|
at_start_(true)
|
|
{
|
|
}
|
|
|
|
array2d(
|
|
long rows,
|
|
long cols
|
|
) :
|
|
data(0),
|
|
nc_(0),
|
|
nr_(0),
|
|
cur(0),
|
|
last(0),
|
|
at_start_(true)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT((cols >= 0 && rows >= 0),
|
|
"\t array2d::array2d(long rows, long cols)"
|
|
<< "\n\t The array2d can't have negative rows or columns."
|
|
<< "\n\t this: " << this
|
|
<< "\n\t cols: " << cols
|
|
<< "\n\t rows: " << rows
|
|
);
|
|
|
|
set_size(rows,cols);
|
|
}
|
|
|
|
array2d(const array2d&) = delete; // copy constructor
|
|
array2d& operator=(const array2d&) = delete; // assignment operator
|
|
|
|
#ifdef DLIB_HAS_RVALUE_REFERENCES
|
|
array2d(array2d&& item) : array2d()
|
|
{
|
|
swap(item);
|
|
}
|
|
|
|
array2d& operator= (
|
|
array2d&& rhs
|
|
)
|
|
{
|
|
swap(rhs);
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
virtual ~array2d (
|
|
) { clear(); }
|
|
|
|
long nc (
|
|
) const { return nc_; }
|
|
|
|
long nr (
|
|
) const { return nr_; }
|
|
|
|
row operator[] (
|
|
long row_
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(row_ < nr() && row_ >= 0,
|
|
"\trow array2d::operator[](long row_)"
|
|
<< "\n\tThe row index given must be less than the number of rows."
|
|
<< "\n\tthis: " << this
|
|
<< "\n\trow_: " << row_
|
|
<< "\n\tnr(): " << nr()
|
|
);
|
|
|
|
return row(data+row_*nc_, nc_);
|
|
}
|
|
|
|
const row operator[] (
|
|
long row_
|
|
) const
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(row_ < nr() && row_ >= 0,
|
|
"\tconst row array2d::operator[](long row_) const"
|
|
<< "\n\tThe row index given must be less than the number of rows."
|
|
<< "\n\tthis: " << this
|
|
<< "\n\trow_: " << row_
|
|
<< "\n\tnr(): " << nr()
|
|
);
|
|
|
|
return row(data+row_*nc_, nc_);
|
|
}
|
|
|
|
void swap (
|
|
array2d& item
|
|
)
|
|
{
|
|
exchange(data,item.data);
|
|
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);
|
|
}
|
|
|
|
void clear (
|
|
)
|
|
{
|
|
if (data != 0)
|
|
{
|
|
pool.deallocate_array(data);
|
|
nc_ = 0;
|
|
nr_ = 0;
|
|
data = 0;
|
|
at_start_ = true;
|
|
cur = 0;
|
|
last = 0;
|
|
}
|
|
}
|
|
|
|
void set_size (
|
|
long rows,
|
|
long cols
|
|
);
|
|
|
|
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
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(current_element_valid() == true,
|
|
"\tconst T& array2d::element()()"
|
|
<< "\n\tYou can only call element() when you are at a valid one."
|
|
<< "\n\tthis: " << this
|
|
);
|
|
|
|
return *cur;
|
|
}
|
|
|
|
T& element (
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT(current_element_valid() == true,
|
|
"\tT& array2d::element()()"
|
|
<< "\n\tYou can only call element() when you are at a valid one."
|
|
<< "\n\tthis: " << this
|
|
);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
size_t size (
|
|
) const { return static_cast<size_t>(nc_) * static_cast<size_t>(nr_); }
|
|
|
|
long width_step (
|
|
) const
|
|
{
|
|
return nc_*sizeof(T);
|
|
}
|
|
|
|
iterator begin()
|
|
{
|
|
return data;
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
return data+size();
|
|
}
|
|
|
|
const_iterator begin() const
|
|
{
|
|
return data;
|
|
}
|
|
|
|
const_iterator end() const
|
|
{
|
|
return data+size();
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
|
|
T* data;
|
|
long nc_;
|
|
long nr_;
|
|
|
|
typename mem_manager::template rebind<T>::other pool;
|
|
mutable T* cur;
|
|
T* last;
|
|
mutable bool at_start_;
|
|
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
inline void swap (
|
|
array2d<T,mem_manager>& a,
|
|
array2d<T,mem_manager>& b
|
|
) { a.swap(b); }
|
|
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void serialize (
|
|
const array2d<T,mem_manager>& item,
|
|
std::ostream& out
|
|
)
|
|
{
|
|
try
|
|
{
|
|
// The reason the serialization is a little funny is because we are trying to
|
|
// maintain backwards compatibility with an older serialization format used by
|
|
// dlib while also encoding things in a way that lets the array2d and matrix
|
|
// objects have compatible serialization formats.
|
|
serialize(-item.nr(),out);
|
|
serialize(-item.nc(),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");
|
|
}
|
|
}
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void deserialize (
|
|
array2d<T,mem_manager>& item,
|
|
std::istream& in
|
|
)
|
|
{
|
|
try
|
|
{
|
|
long nr, nc;
|
|
deserialize(nr,in);
|
|
deserialize(nc,in);
|
|
|
|
// this is the newer serialization format
|
|
if (nr < 0 || nc < 0)
|
|
{
|
|
nr *= -1;
|
|
nc *= -1;
|
|
}
|
|
else
|
|
{
|
|
std::swap(nr,nc);
|
|
}
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// member function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T,
|
|
typename mem_manager
|
|
>
|
|
void array2d<T,mem_manager>::
|
|
set_size (
|
|
long rows,
|
|
long cols
|
|
)
|
|
{
|
|
// make sure requires clause is not broken
|
|
DLIB_ASSERT((cols >= 0 && rows >= 0) ,
|
|
"\tvoid array2d::set_size(long rows, long cols)"
|
|
<< "\n\tThe array2d can't have negative rows or columns."
|
|
<< "\n\tthis: " << this
|
|
<< "\n\tcols: " << cols
|
|
<< "\n\trows: " << rows
|
|
);
|
|
|
|
// 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_ == cols && nr_ == rows)
|
|
{
|
|
return;
|
|
}
|
|
|
|
nc_ = cols;
|
|
nr_ = rows;
|
|
|
|
// free any existing memory
|
|
if (data != 0)
|
|
{
|
|
pool.deallocate_array(data);
|
|
data = 0;
|
|
}
|
|
|
|
// now setup this object to have the new size
|
|
try
|
|
{
|
|
if (nr_ > 0)
|
|
{
|
|
data = pool.allocate_array(nr_*nc_);
|
|
last = data + nr_*nc_ - 1;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
if (data)
|
|
pool.deallocate_array(data);
|
|
|
|
data = 0;
|
|
nc_ = 0;
|
|
nr_ = 0;
|
|
last = 0;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename T, typename MM>
|
|
struct is_array2d <array2d<T,MM> >
|
|
{
|
|
const static bool value = true;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_ARRAY2D_KERNEl_1_
|
|
|