open source pkg v1

This commit is contained in:
Vijay Yadev
2020-08-04 19:12:31 -04:00
parent bef213dba9
commit c389fc2c47
3708 changed files with 1624220 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_
#define DLIB_AnY_
#include "any/any.h"
#include "any/any_trainer.h"
#include "any/any_decision_function.h"
#include "any/any_function.h"
#endif // DLIB_AnY_

View File

@@ -0,0 +1,183 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_H_
#define DLIB_AnY_H_
#include "any_abstract.h"
#include "../algs.h"
#include <memory>
#include <typeinfo>
namespace dlib
{
// ----------------------------------------------------------------------------------------
class bad_any_cast : public std::bad_cast
{
public:
virtual const char * what() const throw()
{
return "bad_any_cast";
}
};
// ----------------------------------------------------------------------------------------
class any
{
public:
any()
{
}
any (
const any& item
)
{
if (item.data)
{
item.data->copy_to(data);
}
}
template <typename T>
any (
const T& item
)
{
typedef typename basic_type<T>::type U;
data.reset(new derived<U>(item));
}
void clear (
)
{
data.reset();
}
template <typename T>
bool contains (
) const
{
typedef typename basic_type<T>::type U;
return dynamic_cast<derived<U>*>(data.get()) != 0;
}
bool is_empty(
) const
{
return data.get() == 0;
}
template <typename T>
T& cast_to(
)
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
const T& cast_to(
) const
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
T& get(
)
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
d = new derived<U>();
data.reset(d);
}
return d->item;
}
any& operator= (
const any& item
)
{
any(item).swap(*this);
return *this;
}
void swap (
any& item
)
{
data.swap(item.data);
}
private:
struct base
{
virtual ~base() {}
virtual void copy_to (
std::unique_ptr<base>& dest
) const = 0;
};
template <typename T>
struct derived : public base
{
T item;
derived() {}
derived(const T& val) : item(val) {}
virtual void copy_to (
std::unique_ptr<base>& dest
) const
{
dest.reset(new derived<T>(item));
}
};
std::unique_ptr<base> data;
};
// ----------------------------------------------------------------------------------------
inline void swap (
any& a,
any& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <typename T> T& any_cast(any& a) { return a.cast_to<T>(); }
template <typename T> const T& any_cast(const any& a) { return a.cast_to<T>(); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_H_

View File

@@ -0,0 +1,210 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_ABSTRACT_H_
#ifdef DLIB_AnY_ABSTRACT_H_
#include <typeinfo>
namespace dlib
{
// ----------------------------------------------------------------------------------------
class bad_any_cast : public std::bad_cast
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is the exception class used by the any object.
It is used to indicate when someone attempts to cast an any
object into a type which isn't contained in the any object.
!*/
public:
virtual const char* what() const throw() { return "bad_any_cast"; }
};
// ----------------------------------------------------------------------------------------
class any
{
/*!
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is basically a type-safe version of a void*. In particular,
it is a container which can contain only one object but the object may
be of any type.
It is somewhat like the type_safe_union except you don't have to declare
the set of possible content types beforehand. So in some sense this is
like a less type-strict version of the type_safe_union.
!*/
public:
any(
);
/*!
ensures
- this object is properly initialized
!*/
any (
const any& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
template < typename T >
any (
const T& item
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. a copy of item will be stored in *this)
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any& operator= (
const any& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
void swap (
any& item
);
/*!
ensures
- swaps *this and item
- does not invalidate pointers or references to the object contained
inside *this or item. Moreover, a pointer or reference to the object in
*this will now refer to the contents of #item and vice versa.
!*/
};
// ----------------------------------------------------------------------------------------
inline void swap (
any& a,
any& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// ----------------------------------------------------------------------------------------
template <
typename T
>
T& any_cast(
any& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T
>
const T& any_cast(
const any& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_ABSTRACT_H_

View File

@@ -0,0 +1,209 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_DECISION_FUNCTION_Hh_
#define DLIB_AnY_DECISION_FUNCTION_Hh_
#include "any.h"
#include "any_decision_function_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename sample_type_,
typename result_type_ = double
>
class any_decision_function
{
public:
typedef sample_type_ sample_type;
typedef result_type_ result_type;
typedef default_memory_manager mem_manager_type;
any_decision_function()
{
}
any_decision_function (
const any_decision_function& item
)
{
if (item.data)
{
item.data->copy_to(data);
}
}
template <typename T>
any_decision_function (
const T& item
)
{
typedef typename basic_type<T>::type U;
data.reset(new derived<U>(item));
}
void clear (
)
{
data.reset();
}
template <typename T>
bool contains (
) const
{
typedef typename basic_type<T>::type U;
return dynamic_cast<derived<U>*>(data.get()) != 0;
}
bool is_empty(
) const
{
return data.get() == 0;
}
result_type operator() (
const sample_type& item
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(is_empty() == false,
"\t result_type any_decision_function::operator()"
<< "\n\t You can't call operator() on an empty any_decision_function"
<< "\n\t this: " << this
);
return data->evaluate(item);
}
template <typename T>
T& cast_to(
)
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
const T& cast_to(
) const
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
T& get(
)
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
d = new derived<U>();
data.reset(d);
}
return d->item;
}
any_decision_function& operator= (
const any_decision_function& item
)
{
any_decision_function(item).swap(*this);
return *this;
}
void swap (
any_decision_function& item
)
{
data.swap(item.data);
}
private:
struct base
{
virtual ~base() {}
virtual void copy_to (
std::unique_ptr<base>& dest
) const = 0;
virtual result_type evaluate (
const sample_type& samp
) const = 0;
};
template <typename T>
struct derived : public base
{
T item;
derived() {}
derived(const T& val) : item(val) {}
virtual void copy_to (
std::unique_ptr<base>& dest
) const
{
dest.reset(new derived<T>(item));
}
virtual result_type evaluate (
const sample_type& samp
) const
{
return item(samp);
}
};
std::unique_ptr<base> data;
};
// ----------------------------------------------------------------------------------------
template <
typename sample_type,
typename result_type
>
inline void swap (
any_decision_function<sample_type, result_type>& a,
any_decision_function<sample_type, result_type>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <typename T, typename U, typename V>
T& any_cast(any_decision_function<U,V>& a) { return a.template cast_to<T>(); }
template <typename T, typename U, typename V>
const T& any_cast(const any_decision_function<U,V>& a) { return a.template cast_to<T>(); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_DECISION_FUNCTION_Hh_

View File

@@ -0,0 +1,224 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_
#ifdef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_
#include "any_abstract.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename sample_type_,
typename result_type_ = double
>
class any_decision_function
{
/*!
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is a version of dlib::any that is restricted to containing
elements which are some kind of function object with an operator() with
the following signature:
result_type operator()(const sample_type&) const
It is intended to be used to contain dlib::decision_function objects and
other types which represent learned decision functions. It allows you
to write code which contains and processes these decision functions
without needing to know the specific types of decision functions used.
!*/
public:
typedef sample_type_ sample_type;
typedef result_type_ result_type;
typedef default_memory_manager mem_manager_type;
any_decision_function(
);
/*!
ensures
- this object is properly initialized
!*/
any_decision_function (
const any_decision_function& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
template < typename T >
any_decision_function (
const T& item
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. a copy of item will be stored in *this)
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
result_type operator() (
const sample_type& item
) const;
/*!
requires
- is_empty() == false
ensures
- Let F denote the function object contained within *this. Then
this function performs:
return F(item)
!*/
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any_decision_function object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any_decision_function& operator= (
const any_decision_function& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
void swap (
any_decision_function& item
);
/*!
ensures
- swaps *this and item
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename sample_type,
typename result_type
>
inline void swap (
any_decision_function<sample_type,result_type>& a,
any_decision_function<sample_type,result_type>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename sample_type,
typename result_type
>
T& any_cast(
any_decision_function<sample_type,result_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename sample_type,
typename result_type
>
const T& any_cast(
const any_decision_function<sample_type,result_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_

View File

@@ -0,0 +1,885 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_FUNCTION_Hh_
#define DLIB_AnY_FUNCTION_Hh_
#include "any.h"
#include "any_function_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <typename T>
struct sig_traits {};
template <
typename T
>
struct sig_traits<T ()>
{
typedef T result_type;
typedef void arg1_type;
typedef void arg2_type;
typedef void arg3_type;
typedef void arg4_type;
typedef void arg5_type;
typedef void arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 0;
};
template <
typename T,
typename A1
>
struct sig_traits<T (A1)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef void arg2_type;
typedef void arg3_type;
typedef void arg4_type;
typedef void arg5_type;
typedef void arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 1;
};
template <
typename T,
typename A1, typename A2
>
struct sig_traits<T (A1,A2)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef void arg3_type;
typedef void arg4_type;
typedef void arg5_type;
typedef void arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 2;
};
template <
typename T,
typename A1, typename A2, typename A3
>
struct sig_traits<T (A1,A2,A3)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef void arg4_type;
typedef void arg5_type;
typedef void arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 3;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4
>
struct sig_traits<T (A1,A2,A3,A4)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef void arg5_type;
typedef void arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 4;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5
>
struct sig_traits<T (A1,A2,A3,A4,A5)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef void arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 5;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef void arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 6;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef void arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 7;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef void arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 8;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef void arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 9;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef void arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 10;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef void arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 11;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef void arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 12;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef void arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 13;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef void arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 14;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14,
typename A15
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef A15 arg15_type;
typedef void arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 15;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14,
typename A15,
typename A16
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef A15 arg15_type;
typedef A16 arg16_type;
typedef void arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 16;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14,
typename A15,
typename A16,
typename A17
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef A15 arg15_type;
typedef A16 arg16_type;
typedef A17 arg17_type;
typedef void arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 17;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14,
typename A15,
typename A16,
typename A17,
typename A18
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef A15 arg15_type;
typedef A16 arg16_type;
typedef A17 arg17_type;
typedef A18 arg18_type;
typedef void arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 18;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14,
typename A15,
typename A16,
typename A17,
typename A18,
typename A19
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef A15 arg15_type;
typedef A16 arg16_type;
typedef A17 arg17_type;
typedef A18 arg18_type;
typedef A19 arg19_type;
typedef void arg20_type;
const static unsigned long num_args = 19;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10,
typename A11,
typename A12,
typename A13,
typename A14,
typename A15,
typename A16,
typename A17,
typename A18,
typename A19,
typename A20
>
struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19,A20)>
{
typedef T result_type;
typedef A1 arg1_type;
typedef A2 arg2_type;
typedef A3 arg3_type;
typedef A4 arg4_type;
typedef A5 arg5_type;
typedef A6 arg6_type;
typedef A7 arg7_type;
typedef A8 arg8_type;
typedef A9 arg9_type;
typedef A10 arg10_type;
typedef A11 arg11_type;
typedef A12 arg12_type;
typedef A13 arg13_type;
typedef A14 arg14_type;
typedef A15 arg15_type;
typedef A16 arg16_type;
typedef A17 arg17_type;
typedef A18 arg18_type;
typedef A19 arg19_type;
typedef A20 arg20_type;
const static unsigned long num_args = 20;
};
// ----------------------------------------------------------------------------------------
template <
typename function_type,
// These arguments are used to control the overloading. A user should
// not mess with them.
typename Enabled = void,
unsigned long Num_args = sig_traits<function_type>::num_args
>
class any_function
{
private:
any_function() {}
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
An error on this line means you are trying to use a function signature
with more than the supported number of arguments. The current version
of dlib only supports up to 10 arguments.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
// The following preprocessor commands build the various overloaded versions
// of any_function for different numbers of commands and void vs. non-void return
// types.
// 0 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST
#define DLIB_ANY_FUNCTION_ARGS
#define DLIB_ANY_FUNCTION_NUM_ARGS 0
#include "any_function_impl2.h"
// 1 argument
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1
#define DLIB_ANY_FUNCTION_ARGS a1
#define DLIB_ANY_FUNCTION_NUM_ARGS 1
#include "any_function_impl2.h"
// 2 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2
#define DLIB_ANY_FUNCTION_ARGS a1,a2
#define DLIB_ANY_FUNCTION_NUM_ARGS 2
#include "any_function_impl2.h"
// 3 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3
#define DLIB_ANY_FUNCTION_NUM_ARGS 3
#include "any_function_impl2.h"
// 4 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4
#define DLIB_ANY_FUNCTION_NUM_ARGS 4
#include "any_function_impl2.h"
// 5 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
arg5_type a5
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5
#define DLIB_ANY_FUNCTION_NUM_ARGS 5
#include "any_function_impl2.h"
// 6 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
arg5_type a5, arg6_type a6
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6
#define DLIB_ANY_FUNCTION_NUM_ARGS 6
#include "any_function_impl2.h"
// 7 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
arg5_type a5, arg6_type a6, arg7_type a7
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7
#define DLIB_ANY_FUNCTION_NUM_ARGS 7
#include "any_function_impl2.h"
// 8 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7,a8
#define DLIB_ANY_FUNCTION_NUM_ARGS 8
#include "any_function_impl2.h"
// 9 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8, \
arg9_type a9
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7,a8,a9
#define DLIB_ANY_FUNCTION_NUM_ARGS 9
#include "any_function_impl2.h"
// 10 arguments
#define DLIB_ANY_FUNCTION_ARG_LIST arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, \
arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8, \
arg9_type a9, arg10_type a10
#define DLIB_ANY_FUNCTION_ARGS a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
#define DLIB_ANY_FUNCTION_NUM_ARGS 10
#include "any_function_impl2.h"
// ----------------------------------------------------------------------------------------
template <typename function_type>
inline void swap (
any_function<function_type>& a,
any_function<function_type>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <typename T, typename function_type>
T& any_cast(any_function<function_type>& a) { return a.template cast_to<T>(); }
template <typename T, typename function_type>
const T& any_cast(const any_function<function_type>& a) { return a.template cast_to<T>(); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_FUNCTION_Hh_

View File

@@ -0,0 +1,292 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_FUNCTION_ABSTRACT_H_
#ifdef DLIB_AnY_FUNCTION_ABSTRACT_H_
#include "any_abstract.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename function_type
>
class any_function
{
/*!
REQUIREMENTS ON function_type
This type should be a function signature. Some examples are:
void (int,int) // a function returning nothing and taking two ints
void () // a function returning nothing and taking no arguments
char (double&) // a function returning a char and taking a reference to a double
The number of arguments in the function must be no greater than 10.
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is a version of dlib::any that is restricted to containing
elements which are some kind of function object with an operator() which
matches the function signature defined by function_type.
Here is an example:
#include <iostream>
#include <string>
#include "dlib/any.h"
using namespace std;
void print_message(string str) { cout << str << endl; }
int main()
{
dlib::any_function<void(string)> f;
f = print_message;
f("hello world"); // calls print_message("hello world")
}
Note that any_function objects can be used to store general function
objects (i.e. defined by a class with an overloaded operator()) in
addition to regular global functions.
!*/
public:
// This is the type of object returned by function_type functions.
typedef result_type_for_function_type result_type;
// Typedefs defining the argument types. If an argument does not exist
// then it is set to void.
typedef type_of_first_argument_in_funct_type arg1_type;
typedef type_of_second_argument_in_funct_type arg2_type;
...
typedef type_of_last_argument_in_funct_type arg10_type;
const static unsigned long num_args = total_number_of_non_void_arguments;
any_function(
);
/*!
ensures
- this object is properly initialized
!*/
any_function (
const any_function& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
template < typename T >
any_function (
const T& item
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. a copy of item will be stored in *this)
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
bool is_set (
) const;
/*!
ensures
- returns !is_empty()
!*/
result_type operator() (
) const;
/*!
requires
- is_empty() == false
- the signature defined by function_type takes no arguments
ensures
- Let F denote the function object contained within *this. Then
this function performs:
return F()
or if result_type is void then this function performs:
F()
!*/
result_type operator() (
const arg1_type& a1
) const;
/*!
requires
- is_empty() == false
- the signature defined by function_type takes one argument
ensures
- Let F denote the function object contained within *this. Then
this function performs:
return F(a1)
or if result_type is void then this function performs:
F(a1)
!*/
result_type operator() (
const arg1_type& a1,
const arg2_type& a2
) const;
/*!
requires
- is_empty() == false
- the signature defined by function_type takes two arguments
ensures
- Let F denote the function object contained within *this. Then
this function performs:
return F(a1,a2)
or if result_type is void then this function performs:
F(a1,a2)
!*/
/* !!!!!!!!! NOTE !!!!!!!!!
In addition to the above, operator() is defined for up to 10 arguments.
They are not listed here because it would clutter the documentation.
!!!!!!!!! NOTE !!!!!!!!! */
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any_function object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any_function& operator= (
const any_function& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
void swap (
any_function& item
);
/*!
ensures
- swaps *this and item
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename function_type
>
inline void swap (
any_function<function_type>& a,
any_function<function_type>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename function_type
>
T& any_cast(
any_function<function_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename function_type
>
const T& any_cast(
const any_function<function_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_FUNCTION_ABSTRACT_H_

View File

@@ -0,0 +1,516 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ANY_FUNCTION_RETURN
#error "You aren't supposed to directly #include this file. #include <dlib/any.h> instead."
#endif
#ifdef _MSC_VER
// When using visual studio 2012, disable the warning "warning C4180: qualifier applied to function type has no meaning; ignored"
// that you get about some template expansions applying & to function types.
#pragma warning(disable : 4180)
#endif
#ifdef DLIB_ANY_FUNCTION_RETURN
// This file contains the body of the any_function class. We use the
// preprocessor to generate many different versions. There are
// versions which return a value and those which return void. For
// each of these types there are versions with differing numbers
// of arguments.
public:
typedef typename sig_traits<function_type>::result_type result_type;
typedef typename sig_traits<function_type>::arg1_type arg1_type;
typedef typename sig_traits<function_type>::arg2_type arg2_type;
typedef typename sig_traits<function_type>::arg3_type arg3_type;
typedef typename sig_traits<function_type>::arg4_type arg4_type;
typedef typename sig_traits<function_type>::arg5_type arg5_type;
typedef typename sig_traits<function_type>::arg6_type arg6_type;
typedef typename sig_traits<function_type>::arg7_type arg7_type;
typedef typename sig_traits<function_type>::arg8_type arg8_type;
typedef typename sig_traits<function_type>::arg9_type arg9_type;
typedef typename sig_traits<function_type>::arg10_type arg10_type;
const static unsigned long num_args = sig_traits<function_type>::num_args;
any_function()
{
}
any_function (
const any_function& item
)
{
if (item.data)
{
item.data->copy_to(data);
}
}
template <typename T>
any_function (
const T& item
)
{
typedef typename basic_type<T>::type U;
data.reset(new derived<U,function_type>(item));
}
void clear (
)
{
data.reset();
}
template <typename T>
bool contains (
) const
{
typedef typename basic_type<T>::type U;
return dynamic_cast<derived<U,function_type>*>(data.get()) != 0;
}
bool is_empty(
) const
{
return data.get() == 0;
}
bool is_set(
) const
{
return !is_empty();
}
template <typename T>
T& cast_to(
)
{
typedef typename basic_type<T>::type U;
derived<U,function_type>* d = dynamic_cast<derived<U,function_type>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
const T& cast_to(
) const
{
typedef typename basic_type<T>::type U;
derived<U,function_type>* d = dynamic_cast<derived<U,function_type>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
T& get(
)
{
typedef typename basic_type<T>::type U;
derived<U,function_type>* d = dynamic_cast<derived<U,function_type>*>(data.get());
if (d == 0)
{
d = new derived<U,function_type>();
data.reset(d);
}
return d->item;
}
any_function& operator= (
const any_function& item
)
{
any_function(item).swap(*this);
return *this;
}
void swap (
any_function& item
)
{
data.swap(item.data);
}
result_type operator()(DLIB_ANY_FUNCTION_ARG_LIST) const
{ validate(); DLIB_ANY_FUNCTION_RETURN data->evaluate(DLIB_ANY_FUNCTION_ARGS); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to call a dlib::any_function but you have supplied
arguments which don't match the function signature used by the
dlib::any_function.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
private:
void validate () const
{
// make sure requires clause is not broken
DLIB_ASSERT(is_empty() == false,
"\t result_type any_function::operator()"
<< "\n\t You can't call operator() on an empty any_function"
<< "\n\t this: " << this
);
}
template <typename FT>
struct Tbase
{
virtual ~Tbase() {}
virtual result_type evaluate () const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1
>
struct Tbase<T (A1)>
{
virtual ~Tbase() {}
virtual T evaluate ( A1) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2
>
struct Tbase<T (A1,A2)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3
>
struct Tbase<T (A1,A2,A3)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4
>
struct Tbase<T (A1,A2,A3,A4)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5
>
struct Tbase<T (A1,A2,A3,A4,A5)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4,A5) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6
>
struct Tbase<T (A1,A2,A3,A4,A5,A6)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4,A5,A6) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7
>
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4,A5,A6,A7) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8
>
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7,A8)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9
>
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7,A8,A9)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8,A9) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
template <
typename T,
typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10
>
struct Tbase<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)>
{
virtual ~Tbase() {}
virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) const = 0;
virtual void copy_to ( std::unique_ptr<Tbase>& dest) const = 0;
};
typedef Tbase<function_type> base;
// -----------------------------------------------
// Some templates to help deal with the weirdness of storing C function types (rather than pointer to functions).
// Basically, we make sure things always get turned into function pointers even if the user gives a function reference.
template <typename T, typename enabled = void>
struct funct_type { typedef T type; };
template <typename T>
struct funct_type<T, typename enable_if<is_function<T> >::type> { typedef T* type; };
template <typename T>
static typename enable_if<is_function<T>,const T*>::type copy (const T& item) { return &item; }
template <typename T>
static typename disable_if<is_function<T>,const T&>::type copy (const T& item) { return item; }
template <typename T, typename U>
static typename enable_if<is_function<T>,const T&>::type deref (const U& item) { return *item; }
template <typename T, typename U>
static typename disable_if<is_function<T>,const T&>::type deref (const U& item) { return item; }
// -----------------------------------------------
#define DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE \
typename funct_type<T>::type item; \
derived() {} \
derived(const T& val) : item(copy(val)) {} \
virtual void copy_to ( std::unique_ptr<base>& dest) const \
{ dest.reset(new derived(deref<T>(item))); }
template <typename T, typename FT>
struct derived : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
) const { DLIB_ANY_FUNCTION_RETURN item(); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1>
struct derived<T,result_type (A1)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1
) const { DLIB_ANY_FUNCTION_RETURN item(a1); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2>
struct derived<T,result_type (A1,A2)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3>
struct derived<T,result_type (A1,A2,A3)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4>
struct derived<T,result_type (A1,A2,A3,A4)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4, typename A5>
struct derived<T,result_type (A1,A2,A3,A4,A5)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7,A8)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7,a8); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7,A8,A9)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7,a8,a9); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
template <typename T, typename A1, typename A2, typename A3,
typename A4, typename A5, typename A6,
typename A7, typename A8, typename A9,
typename A10>
struct derived<T,result_type (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)> : public base
{
DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
virtual result_type evaluate (
A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10
) const { DLIB_ANY_FUNCTION_RETURN item(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); }
/* !!!!!!!! ERRORS ON THE ABOVE LINE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you are getting an error on the above line then it means you
have attempted to assign a function or function object to a
dlib::any_function but the signatures of the source and
destination functions don't match.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
};
std::unique_ptr<base> data;
#undef DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE
#endif // DLIB_ANY_FUNCTION_RETURN

View File

@@ -0,0 +1,44 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ANY_FUNCTION_ARG_LIST
#error "You aren't supposed to directly #include this file. #include <dlib/any.h> instead."
#endif
#ifdef DLIB_ANY_FUNCTION_ARG_LIST
// The case where function_type has a non-void return type
template <typename function_type, typename Enabled>
class any_function<function_type, Enabled, DLIB_ANY_FUNCTION_NUM_ARGS>
{
#define DLIB_ANY_FUNCTION_RETURN return
#include "any_function_impl.h"
#undef DLIB_ANY_FUNCTION_RETURN
private:
// You get a compiler error about this function being private if you try to assign
// or copy between any_functions with different types. You must only copy between
// any_functions that represent functions with the same signature.
template <typename T, typename U> any_function(const any_function<T,U>&);
};
// The case where function_type has a void return type
template <typename function_type>
class any_function<function_type, typename sig_traits<function_type>::type, DLIB_ANY_FUNCTION_NUM_ARGS>
{
#define DLIB_ANY_FUNCTION_RETURN
#include "any_function_impl.h"
#undef DLIB_ANY_FUNCTION_RETURN
private:
// You get a compiler error about this function being private if you try to assign
// or copy between any_functions with different types. You must only copy between
// any_functions that represent functions with the same signature.
template <typename T> any_function(const any_function<T>&);
};
#undef DLIB_ANY_FUNCTION_ARG_LIST
#undef DLIB_ANY_FUNCTION_ARGS
#undef DLIB_ANY_FUNCTION_NUM_ARGS
#endif // DLIB_ANY_FUNCTION_ARG_LIST

View File

@@ -0,0 +1,217 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_TRAINER_H_
#define DLIB_AnY_TRAINER_H_
#include "any.h"
#include "any_decision_function.h"
#include "any_trainer_abstract.h"
#include <vector>
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename sample_type_,
typename scalar_type_ = double
>
class any_trainer
{
public:
typedef sample_type_ sample_type;
typedef scalar_type_ scalar_type;
typedef default_memory_manager mem_manager_type;
typedef any_decision_function<sample_type, scalar_type> trained_function_type;
any_trainer()
{
}
any_trainer (
const any_trainer& item
)
{
if (item.data)
{
item.data->copy_to(data);
}
}
template <typename T>
any_trainer (
const T& item
)
{
typedef typename basic_type<T>::type U;
data.reset(new derived<U>(item));
}
void clear (
)
{
data.reset();
}
template <typename T>
bool contains (
) const
{
typedef typename basic_type<T>::type U;
return dynamic_cast<derived<U>*>(data.get()) != 0;
}
bool is_empty(
) const
{
return data.get() == 0;
}
trained_function_type train (
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(is_empty() == false,
"\t trained_function_type any_trainer::train()"
<< "\n\t You can't call train() on an empty any_trainer"
<< "\n\t this: " << this
);
return data->train(samples, labels);
}
template <typename T>
T& cast_to(
)
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
const T& cast_to(
) const
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
throw bad_any_cast();
}
return d->item;
}
template <typename T>
T& get(
)
{
typedef typename basic_type<T>::type U;
derived<U>* d = dynamic_cast<derived<U>*>(data.get());
if (d == 0)
{
d = new derived<U>();
data.reset(d);
}
return d->item;
}
any_trainer& operator= (
const any_trainer& item
)
{
any_trainer(item).swap(*this);
return *this;
}
void swap (
any_trainer& item
)
{
data.swap(item.data);
}
private:
struct base
{
virtual ~base() {}
virtual trained_function_type train (
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const = 0;
virtual void copy_to (
std::unique_ptr<base>& dest
) const = 0;
};
template <typename T>
struct derived : public base
{
T item;
derived() {}
derived(const T& val) : item(val) {}
virtual void copy_to (
std::unique_ptr<base>& dest
) const
{
dest.reset(new derived<T>(item));
}
virtual trained_function_type train (
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
{
return item.train(samples, labels);
}
};
std::unique_ptr<base> data;
};
// ----------------------------------------------------------------------------------------
template <
typename sample_type,
typename scalar_type
>
inline void swap (
any_trainer<sample_type,scalar_type>& a,
any_trainer<sample_type,scalar_type>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <typename T, typename U, typename V>
T& any_cast(any_trainer<U,V>& a) { return a.template cast_to<T>(); }
template <typename T, typename U, typename V>
const T& any_cast(const any_trainer<U,V>& a) { return a.template cast_to<T>(); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_TRAINER_H_

View File

@@ -0,0 +1,234 @@
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_TRAINER_ABSTRACT_H_
#ifdef DLIB_AnY_TRAINER_ABSTRACT_H_
#include "any_abstract.h"
#include "../algs.h"
#include "any_decision_function_abstract.h"
#include <vector>
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename sample_type_,
typename scalar_type_ = double
>
class any_trainer
{
/*!
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is a version of dlib::any that is restricted to containing
elements which are some kind of object with a .train() method compatible
with the following signature:
decision_function train(
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
Where decision_function is a type capable of being stored in an
any_decision_function<sample_type,scalar_type> object.
any_trainer is intended to be used to contain objects such as the svm_nu_trainer
and other similar types which represent supervised machine learning algorithms.
It allows you to write code which contains and processes these trainer objects
without needing to know the specific types of trainer objects used.
!*/
public:
typedef sample_type_ sample_type;
typedef scalar_type_ scalar_type;
typedef default_memory_manager mem_manager_type;
typedef any_decision_function<sample_type, scalar_type> trained_function_type;
any_trainer(
);
/*!
ensures
- this object is properly initialized
!*/
any_trainer (
const any_trainer& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
template < typename T >
any_trainer (
const T& item
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. a copy of item will be stored in *this)
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
trained_function_type train (
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
/*!
requires
- is_empty() == false
ensures
- Let TRAINER denote the object contained within *this. Then
this function performs:
return TRAINER.train(samples, labels)
!*/
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any_trainer object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any_trainer& operator= (
const any_trainer& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
void swap (
any_trainer& item
);
/*!
ensures
- swaps *this and item
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename sample_type,
typename scalar_type
>
inline void swap (
any_trainer<sample_type,scalar_type>& a,
any_trainer<sample_type,scalar_type>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename sample_type,
typename scalar_type
>
T& any_cast(
any_trainer<sample_type,scalar_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename sample_type,
typename scalar_type
>
const T& any_cast(
const any_trainer<sample_type,scalar_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_TRAINER_ABSTRACT_H_

View File

@@ -0,0 +1,10 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ARRAy_
#define DLIB_ARRAy_
#include "array/array_kernel.h"
#include "array/array_tools.h"
#endif // DLIB_ARRAy_

View File

@@ -0,0 +1,809 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY_KERNEl_2_
#define DLIB_ARRAY_KERNEl_2_
#include "array_kernel_abstract.h"
#include "../interfaces/enumerable.h"
#include "../algs.h"
#include "../serialize.h"
#include "../sort.h"
#include "../is_kind.h"
namespace dlib
{
template <
typename T,
typename mem_manager = default_memory_manager
>
class array : public enumerable<T>
{
/*!
INITIAL VALUE
- array_size == 0
- max_array_size == 0
- array_elements == 0
- pos == 0
- last_pos == 0
- _at_start == true
CONVENTION
- array_size == size()
- max_array_size == max_size()
- if (max_array_size > 0)
- array_elements == pointer to max_array_size elements of type T
- else
- array_elements == 0
- if (array_size > 0)
- last_pos == array_elements + array_size - 1
- else
- last_pos == 0
- at_start() == _at_start
- current_element_valid() == pos != 0
- if (current_element_valid()) then
- *pos == element()
!*/
public:
// These typedefs are here for backwards compatibility with old versions of dlib.
typedef array kernel_1a;
typedef array kernel_1a_c;
typedef array kernel_2a;
typedef array kernel_2a_c;
typedef array sort_1a;
typedef array sort_1a_c;
typedef array sort_1b;
typedef array sort_1b_c;
typedef array sort_2a;
typedef array sort_2a_c;
typedef array sort_2b;
typedef array sort_2b_c;
typedef array expand_1a;
typedef array expand_1a_c;
typedef array expand_1b;
typedef array expand_1b_c;
typedef array expand_1c;
typedef array expand_1c_c;
typedef array expand_1d;
typedef array expand_1d_c;
typedef T type;
typedef T value_type;
typedef mem_manager mem_manager_type;
array (
) :
array_size(0),
max_array_size(0),
array_elements(0),
pos(0),
last_pos(0),
_at_start(true)
{}
array(const array&) = delete;
array& operator=(array&) = delete;
array(
array&& item
) : array()
{
swap(item);
}
array& operator=(
array&& item
)
{
swap(item);
return *this;
}
explicit array (
size_t new_size
) :
array_size(0),
max_array_size(0),
array_elements(0),
pos(0),
last_pos(0),
_at_start(true)
{
resize(new_size);
}
~array (
);
void clear (
);
inline const T& operator[] (
size_t pos
) const;
inline T& operator[] (
size_t pos
);
void set_size (
size_t size
);
inline size_t max_size(
) const;
void set_max_size(
size_t max
);
void swap (
array& item
);
// functions from the enumerable interface
inline size_t size (
) const;
inline bool at_start (
) const;
inline void reset (
) const;
bool current_element_valid (
) const;
inline const T& element (
) const;
inline T& element (
);
bool move_next (
) const;
void sort (
);
void resize (
size_t new_size
);
const T& back (
) const;
T& back (
);
void pop_back (
);
void pop_back (
T& item
);
void push_back (
T& item
);
void push_back (
T&& item
);
typedef T* iterator;
typedef const T* const_iterator;
iterator begin() { return array_elements; }
const_iterator begin() const { return array_elements; }
iterator end() { return array_elements+array_size; }
const_iterator end() const { return array_elements+array_size; }
private:
typename mem_manager::template rebind<T>::other pool;
// data members
size_t array_size;
size_t max_array_size;
T* array_elements;
mutable T* pos;
T* last_pos;
mutable bool _at_start;
};
template <
typename T,
typename mem_manager
>
inline void swap (
array<T,mem_manager>& a,
array<T,mem_manager>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void serialize (
const array<T,mem_manager>& item,
std::ostream& out
)
{
try
{
serialize(item.max_size(),out);
serialize(item.size(),out);
for (size_t i = 0; i < item.size(); ++i)
serialize(item[i],out);
}
catch (serialization_error e)
{
throw serialization_error(e.info + "\n while serializing object of type array");
}
}
template <
typename T,
typename mem_manager
>
void deserialize (
array<T,mem_manager>& item,
std::istream& in
)
{
try
{
size_t max_size, size;
deserialize(max_size,in);
deserialize(size,in);
item.set_max_size(max_size);
item.set_size(size);
for (size_t i = 0; i < size; ++i)
deserialize(item[i],in);
}
catch (serialization_error e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type array");
}
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
array<T,mem_manager>::
~array (
)
{
if (array_elements)
{
pool.deallocate_array(array_elements);
}
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
clear (
)
{
reset();
last_pos = 0;
array_size = 0;
if (array_elements)
{
pool.deallocate_array(array_elements);
}
array_elements = 0;
max_array_size = 0;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
const T& array<T,mem_manager>::
operator[] (
size_t pos
) const
{
// make sure requires clause is not broken
DLIB_ASSERT( pos < this->size() ,
"\tconst T& array::operator[]"
<< "\n\tpos must < size()"
<< "\n\tpos: " << pos
<< "\n\tsize(): " << this->size()
<< "\n\tthis: " << this
);
return array_elements[pos];
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
T& array<T,mem_manager>::
operator[] (
size_t pos
)
{
// make sure requires clause is not broken
DLIB_ASSERT( pos < this->size() ,
"\tT& array::operator[]"
<< "\n\tpos must be < size()"
<< "\n\tpos: " << pos
<< "\n\tsize(): " << this->size()
<< "\n\tthis: " << this
);
return array_elements[pos];
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
set_size (
size_t size
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( size <= this->max_size() ),
"\tvoid array::set_size"
<< "\n\tsize must be <= max_size()"
<< "\n\tsize: " << size
<< "\n\tmax size: " << this->max_size()
<< "\n\tthis: " << this
);
reset();
array_size = size;
if (size > 0)
last_pos = array_elements + size - 1;
else
last_pos = 0;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
size_t array<T,mem_manager>::
size (
) const
{
return array_size;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
set_max_size(
size_t max
)
{
reset();
array_size = 0;
last_pos = 0;
if (max != 0)
{
// if new max size is different
if (max != max_array_size)
{
if (array_elements)
{
pool.deallocate_array(array_elements);
}
// try to get more memroy
try { array_elements = pool.allocate_array(max); }
catch (...) { array_elements = 0; max_array_size = 0; throw; }
max_array_size = max;
}
}
// if the array is being made to be zero
else
{
if (array_elements)
pool.deallocate_array(array_elements);
max_array_size = 0;
array_elements = 0;
}
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
size_t array<T,mem_manager>::
max_size (
) const
{
return max_array_size;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
swap (
array<T,mem_manager>& item
)
{
auto array_size_temp = item.array_size;
auto max_array_size_temp = item.max_array_size;
T* array_elements_temp = item.array_elements;
item.array_size = array_size;
item.max_array_size = max_array_size;
item.array_elements = array_elements;
array_size = array_size_temp;
max_array_size = max_array_size_temp;
array_elements = array_elements_temp;
exchange(_at_start,item._at_start);
exchange(pos,item.pos);
exchange(last_pos,item.last_pos);
pool.swap(item.pool);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// enumerable function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
bool array<T,mem_manager>::
at_start (
) const
{
return _at_start;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
reset (
) const
{
_at_start = true;
pos = 0;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
bool array<T,mem_manager>::
current_element_valid (
) const
{
return pos != 0;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
const T& array<T,mem_manager>::
element (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(this->current_element_valid(),
"\tconst T& array::element()"
<< "\n\tThe current element must be valid if you are to access it."
<< "\n\tthis: " << this
);
return *pos;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
T& array<T,mem_manager>::
element (
)
{
// make sure requires clause is not broken
DLIB_ASSERT(this->current_element_valid(),
"\tT& array::element()"
<< "\n\tThe current element must be valid if you are to access it."
<< "\n\tthis: " << this
);
return *pos;
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
bool array<T,mem_manager>::
move_next (
) const
{
if (!_at_start)
{
if (pos < last_pos)
{
++pos;
return true;
}
else
{
pos = 0;
return false;
}
}
else
{
_at_start = false;
if (array_size > 0)
{
pos = array_elements;
return true;
}
else
{
return false;
}
}
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// Yet more functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
sort (
)
{
if (this->size() > 1)
{
// call the quick sort function for arrays that is in algs.h
dlib::qsort_array(*this,0,this->size()-1);
}
this->reset();
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
resize (
size_t new_size
)
{
if (this->max_size() < new_size)
{
array temp;
temp.set_max_size(new_size);
temp.set_size(new_size);
for (size_t i = 0; i < this->size(); ++i)
{
exchange((*this)[i],temp[i]);
}
temp.swap(*this);
}
else
{
this->set_size(new_size);
}
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
T& array<T,mem_manager>::
back (
)
{
// make sure requires clause is not broken
DLIB_ASSERT( this->size() > 0 ,
"\tT& array::back()"
<< "\n\tsize() must be bigger than 0"
<< "\n\tsize(): " << this->size()
<< "\n\tthis: " << this
);
return (*this)[this->size()-1];
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
const T& array<T,mem_manager>::
back (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT( this->size() > 0 ,
"\tconst T& array::back()"
<< "\n\tsize() must be bigger than 0"
<< "\n\tsize(): " << this->size()
<< "\n\tthis: " << this
);
return (*this)[this->size()-1];
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
pop_back (
T& item
)
{
// make sure requires clause is not broken
DLIB_ASSERT( this->size() > 0 ,
"\tvoid array::pop_back()"
<< "\n\tsize() must be bigger than 0"
<< "\n\tsize(): " << this->size()
<< "\n\tthis: " << this
);
exchange(item,(*this)[this->size()-1]);
this->set_size(this->size()-1);
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
pop_back (
)
{
// make sure requires clause is not broken
DLIB_ASSERT( this->size() > 0 ,
"\tvoid array::pop_back()"
<< "\n\tsize() must be bigger than 0"
<< "\n\tsize(): " << this->size()
<< "\n\tthis: " << this
);
this->set_size(this->size()-1);
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
push_back (
T& item
)
{
if (this->max_size() == this->size())
{
// double the size of the array
array temp;
temp.set_max_size(this->size()*2 + 1);
temp.set_size(this->size()+1);
for (size_t i = 0; i < this->size(); ++i)
{
exchange((*this)[i],temp[i]);
}
exchange(item,temp[temp.size()-1]);
temp.swap(*this);
}
else
{
this->set_size(this->size()+1);
exchange(item,(*this)[this->size()-1]);
}
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename mem_manager
>
void array<T,mem_manager>::
push_back (
T&& item
) { push_back(item); }
// ----------------------------------------------------------------------------------------
template <typename T, typename MM>
struct is_array <array<T,MM> >
{
const static bool value = true;
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_ARRAY_KERNEl_2_

View File

@@ -0,0 +1,360 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_ARRAY_KERNEl_ABSTRACT_
#ifdef DLIB_ARRAY_KERNEl_ABSTRACT_
#include "../interfaces/enumerable.h"
#include "../serialize.h"
#include "../algs.h"
namespace dlib
{
template <
typename T,
typename mem_manager = default_memory_manager
>
class array : public enumerable<T>
{
/*!
REQUIREMENTS ON T
T must have a default constructor.
REQUIREMENTS ON mem_manager
must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
mem_manager::type can be set to anything.
POINTERS AND REFERENCES TO INTERNAL DATA
front(), back(), swap(), max_size(), set_size(), and operator[]
functions do not invalidate pointers or references to internal data.
All other functions have no such guarantee.
INITIAL VALUE
size() == 0
max_size() == 0
ENUMERATION ORDER
The enumerator will iterate over the elements of the array in the
order (*this)[0], (*this)[1], (*this)[2], ...
WHAT THIS OBJECT REPRESENTS
This object represents an ordered 1-dimensional array of items,
each item is associated with an integer value. The items are
numbered from 0 though size() - 1 and the operator[] functions
run in constant time.
Also note that unless specified otherwise, no member functions
of this object throw exceptions.
!*/
public:
typedef T type;
typedef T value_type;
typedef mem_manager mem_manager_type;
array (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc or any exception thrown by T's constructor
!*/
explicit array (
size_t new_size
);
/*!
ensures
- #*this is properly initialized
- #size() == new_size
- #max_size() == new_size
- All elements of the array will have initial values for their type.
throws
- std::bad_alloc or any exception thrown by T's constructor
!*/
~array (
);
/*!
ensures
- all memory associated with *this has been released
!*/
array(
array&& item
);
/*!
ensures
- move constructs *this from item. Therefore, the state of item is
moved into *this and #item has a valid but unspecified state.
!*/
array& operator=(
array&& item
);
/*!
ensures
- move assigns *this from item. Therefore, the state of item is
moved into *this and #item has a valid but unspecified state.
- returns a reference to #*this
!*/
void clear (
);
/*!
ensures
- #*this has its initial value
throws
- std::bad_alloc or any exception thrown by T's constructor
if this exception is thrown then the array object is unusable
until clear() is called and succeeds
!*/
const T& operator[] (
size_t pos
) const;
/*!
requires
- pos < size()
ensures
- returns a const reference to the element at position pos
!*/
T& operator[] (
size_t pos
);
/*!
requires
- pos < size()
ensures
- returns a non-const reference to the element at position pos
!*/
void set_size (
size_t size
);
/*!
requires
- size <= max_size()
ensures
- #size() == size
- any element with index between 0 and size - 1 which was in the
array before the call to set_size() retains its value and index.
All other elements have undetermined (but valid for their type)
values. (e.g. this object might buffer old T objects and reuse
them without reinitializing them between calls to set_size())
- #at_start() == true
throws
- std::bad_alloc or any exception thrown by T's constructor
may throw this exception if there is not enough memory and
if it does throw then the call to set_size() has no effect
!*/
size_t max_size(
) const;
/*!
ensures
- returns the maximum size of *this
!*/
void set_max_size(
size_t max
);
/*!
ensures
- #max_size() == max
- #size() == 0
- #at_start() == true
throws
- std::bad_alloc or any exception thrown by T's constructor
may throw this exception if there is not enough
memory and if it does throw then max_size() == 0
!*/
void swap (
array<T>& item
);
/*!
ensures
- swaps *this and item
!*/
void sort (
);
/*!
requires
- T must be a type with that is comparable via operator<
ensures
- for all elements in #*this the ith element is <= the i+1 element
- #at_start() == true
throws
- std::bad_alloc or any exception thrown by T's constructor
data may be lost if sort() throws
!*/
void resize (
size_t new_size
);
/*!
ensures
- #size() == new_size
- #max_size() == max(new_size,max_size())
- for all i < size() && i < new_size:
- #(*this)[i] == (*this)[i]
(i.e. All the original elements of *this which were at index
values less than new_size are unmodified.)
- for all valid i >= size():
- #(*this)[i] has an undefined value
(i.e. any new elements of the array have an undefined value)
throws
- std::bad_alloc or any exception thrown by T's constructor.
If an exception is thrown then it has no effect on *this.
!*/
const T& back (
) const;
/*!
requires
- size() != 0
ensures
- returns a const reference to (*this)[size()-1]
!*/
T& back (
);
/*!
requires
- size() != 0
ensures
- returns a non-const reference to (*this)[size()-1]
!*/
void pop_back (
T& item
);
/*!
requires
- size() != 0
ensures
- #size() == size() - 1
- swaps (*this)[size()-1] into item
- All elements with an index less than size()-1 are
unmodified by this operation.
!*/
void pop_back (
);
/*!
requires
- size() != 0
ensures
- #size() == size() - 1
- All elements with an index less than size()-1 are
unmodified by this operation.
!*/
void push_back (
T& item
);
/*!
ensures
- #size() == size()+1
- swaps item into (*this)[#size()-1]
- #back() == item
- #item has some undefined value (whatever happens to
get swapped out of the array)
throws
- std::bad_alloc or any exception thrown by T's constructor.
If an exception is thrown then it has no effect on *this.
!*/
void push_back (T&& item) { push_back(item); }
/*!
enable push_back from rvalues
!*/
typedef T* iterator;
typedef const T* const_iterator;
iterator begin(
);
/*!
ensures
- returns an iterator that points to the first element in this array or
end() if the array is empty.
!*/
const_iterator begin(
) const;
/*!
ensures
- returns a const iterator that points to the first element in this
array or end() if the array is empty.
!*/
iterator end(
);
/*!
ensures
- returns an iterator that points to one past the end of the array.
!*/
const_iterator end(
) const;
/*!
ensures
- returns a const iterator that points to one past the end of the
array.
!*/
private:
// restricted functions
array(array<T>&); // copy constructor
array<T>& operator=(array<T>&); // assignment operator
};
template <
typename T
>
inline void swap (
array<T>& a,
array<T>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
template <
typename T
>
void serialize (
const array<T>& item,
std::ostream& out
);
/*!
provides serialization support
!*/
template <
typename T
>
void deserialize (
array<T>& item,
std::istream& in
);
/*!
provides deserialization support
!*/
}
#endif // DLIB_ARRAY_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2013 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY_tOOLS_H_
#define DLIB_ARRAY_tOOLS_H_
#include "../assert.h"
#include "array_tools_abstract.h"
namespace dlib
{
template <typename T>
void split_array (
T& a,
T& b,
double frac
)
{
// make sure requires clause is not broken
DLIB_ASSERT(0 <= frac && frac <= 1,
"\t void split_array()"
<< "\n\t frac must be between 0 and 1."
<< "\n\t frac: " << frac
);
const unsigned long asize = static_cast<unsigned long>(a.size()*frac);
const unsigned long bsize = a.size()-asize;
b.resize(bsize);
for (unsigned long i = 0; i < b.size(); ++i)
{
swap(b[i], a[i+asize]);
}
a.resize(asize);
}
}
#endif // DLIB_ARRAY_tOOLS_H_

View File

@@ -0,0 +1,33 @@
// Copyright (C) 2013 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_ARRAY_tOOLS_ABSTRACT_H_
#ifdef DLIB_ARRAY_tOOLS_ABSTRACT_H_
#include "array_kernel_abstract.h"
namespace dlib
{
template <typename T>
void split_array (
T& a,
T& b,
double frac
);
/*!
requires
- 0 <= frac <= 1
- T must be an array type such as dlib::array or std::vector
ensures
- This function takes the elements of a and splits them into two groups. The
first group remains in a and the second group is put into b. The ordering of
elements in a is preserved. In particular, concatenating #a with #b will
reproduce the original contents of a.
- The elements in a are moved around using global swap(). So they must be
swappable, but do not need to be copyable.
- #a.size() == floor(a.size()*frac)
- #b.size() == a.size()-#a.size()
!*/
}
#endif // DLIB_ARRAY_tOOLS_ABSTRACT_H_

View File

@@ -0,0 +1,12 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2d_
#define DLIB_ARRAY2d_
#include "array2d/array2d_kernel.h"
#include "array2d/serialize_pixel_overloads.h"
#include "array2d/array2d_generic_image.h"
#endif // DLIB_ARRAY2d_

View File

@@ -0,0 +1,67 @@
// Copyright (C) 2014 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2D_GENERIC_iMAGE_Hh_
#define DLIB_ARRAY2D_GENERIC_iMAGE_Hh_
#include "array2d_kernel.h"
#include "../image_processing/generic_image.h"
namespace dlib
{
template <typename T, typename mm>
struct image_traits<array2d<T,mm> >
{
typedef T pixel_type;
};
template <typename T, typename mm>
struct image_traits<const array2d<T,mm> >
{
typedef T pixel_type;
};
template <typename T, typename mm>
inline long num_rows( const array2d<T,mm>& img) { return img.nr(); }
template <typename T, typename mm>
inline long num_columns( const array2d<T,mm>& img) { return img.nc(); }
template <typename T, typename mm>
inline void set_image_size(
array2d<T,mm>& img,
long rows,
long cols
) { img.set_size(rows,cols); }
template <typename T, typename mm>
inline void* image_data(
array2d<T,mm>& img
)
{
if (img.size() != 0)
return &img[0][0];
else
return 0;
}
template <typename T, typename mm>
inline const void* image_data(
const array2d<T,mm>& img
)
{
if (img.size() != 0)
return &img[0][0];
else
return 0;
}
template <typename T, typename mm>
inline long width_step(
const array2d<T,mm>& img
)
{
return img.width_step();
}
}
#endif // DLIB_ARRAY2D_GENERIC_iMAGE_Hh_

View File

@@ -0,0 +1,522 @@
// 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_

View File

@@ -0,0 +1,339 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_ARRAY2D_KERNEl_ABSTRACT_
#ifdef DLIB_ARRAY2D_KERNEl_ABSTRACT_
#include "../interfaces/enumerable.h"
#include "../serialize.h"
#include "../algs.h"
#include "../geometry/rectangle_abstract.h"
namespace dlib
{
template <
typename T,
typename mem_manager = default_memory_manager
>
class array2d : public enumerable<T>
{
/*!
REQUIREMENTS ON T
T must have a default constructor.
REQUIREMENTS ON mem_manager
must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
mem_manager::type can be set to anything.
POINTERS AND REFERENCES TO INTERNAL DATA
No member functions in this object will invalidate pointers
or references to internal data except for the set_size()
and clear() member functions.
INITIAL VALUE
nr() == 0
nc() == 0
ENUMERATION ORDER
The enumerator will iterate over the elements of the array starting
with row 0 and then proceeding to row 1 and so on. Each row will be
fully enumerated before proceeding on to the next row and the elements
in a row will be enumerated beginning with the 0th column, then the 1st
column and so on.
WHAT THIS OBJECT REPRESENTS
This object represents a 2-Dimensional array of objects of
type T.
Also note that unless specified otherwise, no member functions
of this object throw exceptions.
Finally, note that this object stores its data contiguously and in
row major order. Moreover, there is no padding at the end of each row.
This means that its width_step() value is always equal to sizeof(type)*nc().
!*/
public:
// ----------------------------------------
typedef T type;
typedef mem_manager mem_manager_type;
typedef T* iterator;
typedef const T* const_iterator;
// ----------------------------------------
class row
{
/*!
POINTERS AND REFERENCES TO INTERNAL DATA
No member functions in this object will invalidate pointers
or references to internal data.
WHAT THIS OBJECT REPRESENTS
This object represents a row of Ts in an array2d object.
!*/
public:
long nc (
) const;
/*!
ensures
- returns the number of columns in this row
!*/
const T& operator[] (
long column
) const;
/*!
requires
- 0 <= column < nc()
ensures
- returns a const reference to the T in the given column
!*/
T& operator[] (
long column
);
/*!
requires
- 0 <= column < nc()
ensures
- returns a non-const reference to the T in the given column
!*/
private:
// restricted functions
row();
row& operator=(row&);
};
// ----------------------------------------
array2d (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
array2d(const array2d&) = delete; // copy constructor
array2d& operator=(const array2d&) = delete; // assignment operator
array2d(
array2d&& item
);
/*!
ensures
- Moves the state of item into *this.
- #item is in a valid but unspecified state.
!*/
array2d (
long rows,
long cols
);
/*!
requires
- rows >= 0 && cols >= 0
ensures
- #nc() == cols
- #nr() == rows
- #at_start() == true
- all elements in this array have initial values for their type
throws
- std::bad_alloc
!*/
virtual ~array2d (
);
/*!
ensures
- all resources associated with *this has been released
!*/
void clear (
);
/*!
ensures
- #*this has an initial value for its type
!*/
long nc (
) const;
/*!
ensures
- returns the number of elements there are in a row. i.e. returns
the number of columns in *this
!*/
long nr (
) const;
/*!
ensures
- returns the number of rows in *this
!*/
void set_size (
long rows,
long cols
);
/*!
requires
- rows >= 0 && cols >= 0
ensures
- #nc() == cols
- #nr() == rows
- #at_start() == true
- if (the call to set_size() doesn't change the dimensions of this array) then
- all elements in this array retain their values from before this function was called
- else
- all elements in this array have initial values for their type
throws
- std::bad_alloc
If this exception is thrown then #*this will have an initial
value for its type.
!*/
row operator[] (
long row_index
);
/*!
requires
- 0 <= row_index < nr()
ensures
- returns a non-const row of nc() elements that represents the
given row_index'th row in *this.
!*/
const row operator[] (
long row_index
) const;
/*!
requires
- 0 <= row_index < nr()
ensures
- returns a const row of nc() elements that represents the
given row_index'th row in *this.
!*/
void swap (
array2d& item
);
/*!
ensures
- swaps *this and item
!*/
array2d& operator= (
array2d&& rhs
);
/*!
ensures
- Moves the state of item into *this.
- #item is in a valid but unspecified state.
- returns #*this
!*/
long width_step (
) const;
/*!
ensures
- returns the size of one row of the image, in bytes.
More precisely, return a number N such that:
(char*)&item[0][0] + N == (char*)&item[1][0].
- for dlib::array2d objects, the returned value
is always equal to sizeof(type)*nc(). However,
other objects which implement dlib::array2d style
interfaces might have padding at the ends of their
rows and therefore might return larger numbers.
An example of such an object is the dlib::cv_image.
!*/
iterator begin(
);
/*!
ensures
- returns a random access iterator pointing to the first element in this
object.
- The iterator will iterate over the elements of the object in row major
order.
!*/
iterator end(
);
/*!
ensures
- returns a random access iterator pointing to one past the end of the last
element in this object.
!*/
const_iterator begin(
) const;
/*!
ensures
- returns a random access iterator pointing to the first element in this
object.
- The iterator will iterate over the elements of the object in row major
order.
!*/
const_iterator end(
) const;
/*!
ensures
- returns a random access iterator pointing to one past the end of the last
element in this object.
!*/
};
template <
typename T,
typename mem_manager
>
inline void swap (
array2d<T,mem_manager>& a,
array2d<T,mem_manager>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
template <
typename T,
typename mem_manager
>
void serialize (
const array2d<T,mem_manager>& item,
std::ostream& out
);
/*!
Provides serialization support. Note that the serialization formats used by the
dlib::matrix and dlib::array2d objects are compatible. That means you can load the
serialized data from one into another and it will work properly.
!*/
template <
typename T,
typename mem_manager
>
void deserialize (
array2d<T,mem_manager>& item,
std::istream& in
);
/*!
provides deserialization support
!*/
}
#endif // DLIB_ARRAY2D_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,371 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_
#define DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_
#include "array2d_kernel.h"
#include "../pixel.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
/*
This file contains overloads of the serialize functions for array2d object
for the case where they contain simple 8bit POD pixel types. In these
cases we can perform a much faster serialization by writing data in chunks
instead of one pixel at a time (this avoids a lot of function call overhead
inside the iostreams).
*/
// ----------------------------------------------------------------------------------------
template <
typename mem_manager
>
void serialize (
const array2d<rgb_pixel,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);
COMPILE_TIME_ASSERT(sizeof(rgb_pixel) == 3);
if (item.size() != 0)
out.write((char*)&item[0][0], sizeof(rgb_pixel)*item.size());
}
catch (serialization_error e)
{
throw serialization_error(e.info + "\n while serializing object of type array2d");
}
}
template <
typename mem_manager
>
void deserialize (
array2d<rgb_pixel,mem_manager>& item,
std::istream& in
)
{
try
{
COMPILE_TIME_ASSERT(sizeof(rgb_pixel) == 3);
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);
if (item.size() != 0)
in.read((char*)&item[0][0], sizeof(rgb_pixel)*item.size());
}
catch (serialization_error e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type array2d");
}
}
// ----------------------------------------------------------------------------------------
template <
typename mem_manager
>
void serialize (
const array2d<bgr_pixel,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);
COMPILE_TIME_ASSERT(sizeof(bgr_pixel) == 3);
if (item.size() != 0)
out.write((char*)&item[0][0], sizeof(bgr_pixel)*item.size());
}
catch (serialization_error e)
{
throw serialization_error(e.info + "\n while serializing object of type array2d");
}
}
template <
typename mem_manager
>
void deserialize (
array2d<bgr_pixel,mem_manager>& item,
std::istream& in
)
{
try
{
COMPILE_TIME_ASSERT(sizeof(bgr_pixel) == 3);
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);
if (item.size() != 0)
in.read((char*)&item[0][0], sizeof(bgr_pixel)*item.size());
}
catch (serialization_error e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type array2d");
}
}
// ----------------------------------------------------------------------------------------
template <
typename mem_manager
>
void serialize (
const array2d<hsi_pixel,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);
COMPILE_TIME_ASSERT(sizeof(hsi_pixel) == 3);
if (item.size() != 0)
out.write((char*)&item[0][0], sizeof(hsi_pixel)*item.size());
}
catch (serialization_error e)
{
throw serialization_error(e.info + "\n while serializing object of type array2d");
}
}
template <
typename mem_manager
>
void deserialize (
array2d<hsi_pixel,mem_manager>& item,
std::istream& in
)
{
try
{
COMPILE_TIME_ASSERT(sizeof(hsi_pixel) == 3);
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);
if (item.size() != 0)
in.read((char*)&item[0][0], sizeof(hsi_pixel)*item.size());
}
catch (serialization_error e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type array2d");
}
}
// ----------------------------------------------------------------------------------------
template <
typename mem_manager
>
void serialize (
const array2d<rgb_alpha_pixel,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);
COMPILE_TIME_ASSERT(sizeof(rgb_alpha_pixel) == 4);
if (item.size() != 0)
out.write((char*)&item[0][0], sizeof(rgb_alpha_pixel)*item.size());
}
catch (serialization_error e)
{
throw serialization_error(e.info + "\n while serializing object of type array2d");
}
}
template <
typename mem_manager
>
void deserialize (
array2d<rgb_alpha_pixel,mem_manager>& item,
std::istream& in
)
{
try
{
COMPILE_TIME_ASSERT(sizeof(rgb_alpha_pixel) == 4);
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);
if (item.size() != 0)
in.read((char*)&item[0][0], sizeof(rgb_alpha_pixel)*item.size());
}
catch (serialization_error e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type array2d");
}
}
// ----------------------------------------------------------------------------------------
template <
typename mem_manager
>
void serialize (
const array2d<unsigned char,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);
if (item.size() != 0)
out.write((char*)&item[0][0], sizeof(unsigned char)*item.size());
}
catch (serialization_error e)
{
throw serialization_error(e.info + "\n while serializing object of type array2d");
}
}
template <
typename mem_manager
>
void deserialize (
array2d<unsigned char,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);
if (item.size() != 0)
in.read((char*)&item[0][0], sizeof(unsigned char)*item.size());
}
catch (serialization_error e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type array2d");
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_

View File

@@ -0,0 +1,217 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ASSERt_
#define DLIB_ASSERt_
#include "config.h"
#include <sstream>
#include <iosfwd>
#include "error.h"
// -----------------------------
// Use some stuff from boost here
// (C) Copyright John Maddock 2001 - 2003.
// (C) Copyright Darin Adler 2001.
// (C) Copyright Peter Dimov 2001.
// (C) Copyright Bill Kempf 2002.
// (C) Copyright Jens Maurer 2002.
// (C) Copyright David Abrahams 2002 - 2003.
// (C) Copyright Gennaro Prota 2003.
// (C) Copyright Eric Friedman 2003.
// License: Boost Software License See LICENSE.txt for the full license.
//
#ifndef DLIB_BOOST_JOIN
#define DLIB_BOOST_JOIN( X, Y ) DLIB_BOOST_DO_JOIN( X, Y )
#define DLIB_BOOST_DO_JOIN( X, Y ) DLIB_BOOST_DO_JOIN2(X,Y)
#define DLIB_BOOST_DO_JOIN2( X, Y ) X##Y
#endif
// figure out if the compiler has rvalue references.
#if defined(__clang__)
# if __has_feature(cxx_rvalue_references)
# define DLIB_HAS_RVALUE_REFERENCES
# endif
# if __has_feature(cxx_generalized_initializers)
# define DLIB_HAS_INITIALIZER_LISTS
# endif
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
# define DLIB_HAS_RVALUE_REFERENCES
# define DLIB_HAS_INITIALIZER_LISTS
#elif defined(_MSC_VER) && _MSC_VER >= 1800
# define DLIB_HAS_INITIALIZER_LISTS
# define DLIB_HAS_RVALUE_REFERENCES
#elif defined(_MSC_VER) && _MSC_VER >= 1600
# define DLIB_HAS_RVALUE_REFERENCES
#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X)
# define DLIB_HAS_RVALUE_REFERENCES
# define DLIB_HAS_INITIALIZER_LISTS
#endif
#if defined(__APPLE__) && defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402)
// Apple has not updated libstdc++ in some time and anything under 4.02 does not have <initializer_list> for sure.
# undef DLIB_HAS_INITIALIZER_LISTS
#endif
// figure out if the compiler has static_assert.
#if defined(__clang__)
# if __has_feature(cxx_static_assert)
# define DLIB_HAS_STATIC_ASSERT
# endif
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__)
# define DLIB_HAS_STATIC_ASSERT
#elif defined(_MSC_VER) && _MSC_VER >= 1600
# define DLIB_HAS_STATIC_ASSERT
#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X)
# define DLIB_HAS_STATIC_ASSERT
#endif
// -----------------------------
namespace dlib
{
template <bool value> struct compile_time_assert;
template <> struct compile_time_assert<true> { enum {value=1}; };
template <typename T, typename U> struct assert_are_same_type;
template <typename T> struct assert_are_same_type<T,T> {enum{value=1};};
template <typename T, typename U> struct assert_are_not_same_type {enum{value=1}; };
template <typename T> struct assert_are_not_same_type<T,T> {};
template <typename T, typename U> struct assert_types_match {enum{value=0};};
template <typename T> struct assert_types_match<T,T> {enum{value=1};};
}
// gcc 4.8 will warn about unused typedefs. But we use typedefs in some of the compile
// time assert macros so we need to make it not complain about them "not being used".
#ifdef __GNUC__
#define DLIB_NO_WARN_UNUSED __attribute__ ((unused))
#else
#define DLIB_NO_WARN_UNUSED
#endif
// Use the newer static_assert if it's available since it produces much more readable error
// messages.
#ifdef DLIB_HAS_STATIC_ASSERT
#define COMPILE_TIME_ASSERT(expression) static_assert(expression, "Failed assertion")
#define ASSERT_ARE_SAME_TYPE(type1, type2) static_assert(::dlib::assert_types_match<type1,type2>::value, "These types should be the same but aren't.")
#define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) static_assert(!::dlib::assert_types_match<type1,type2>::value, "These types should NOT be the same.")
#else
#define COMPILE_TIME_ASSERT(expression) \
DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value]
#define ASSERT_ARE_SAME_TYPE(type1, type2) \
DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type<type1,type2>::value]
#define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \
DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type<type1,type2>::value]
#endif
// -----------------------------
#if defined DLIB_DISABLE_ASSERTS
// if DLIB_DISABLE_ASSERTS is on then never enable DLIB_ASSERT no matter what.
#undef ENABLE_ASSERTS
#endif
#if !defined(DLIB_DISABLE_ASSERTS) && ( defined DEBUG || defined _DEBUG)
// make sure ENABLE_ASSERTS is defined if we are indeed using them.
#ifndef ENABLE_ASSERTS
#define ENABLE_ASSERTS
#endif
#endif
// -----------------------------
#ifdef __GNUC__
// There is a bug in version 4.4.5 of GCC on Ubuntu which causes GCC to segfault
// when __PRETTY_FUNCTION__ is used within certain templated functions. So just
// don't use it with this version of GCC.
# if !(__GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 5)
# define DLIB_FUNCTION_NAME __PRETTY_FUNCTION__
# else
# define DLIB_FUNCTION_NAME "unknown function"
# endif
#elif defined(_MSC_VER)
#define DLIB_FUNCTION_NAME __FUNCSIG__
#else
#define DLIB_FUNCTION_NAME "unknown function"
#endif
#define DLIBM_CASSERT(_exp,_message) \
{if ( !(_exp) ) \
{ \
dlib_assert_breakpoint(); \
std::ostringstream dlib_o_out; \
dlib_o_out << "\n\nError detected at line " << __LINE__ << ".\n"; \
dlib_o_out << "Error detected in file " << __FILE__ << ".\n"; \
dlib_o_out << "Error detected in function " << DLIB_FUNCTION_NAME << ".\n\n"; \
dlib_o_out << "Failing expression was " << #_exp << ".\n"; \
dlib_o_out << std::boolalpha << _message << "\n"; \
throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str()); \
}}
// This macro is not needed if you have a real C++ compiler. It's here to work around bugs in Visual Studio's preprocessor.
#define DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(x) x
// Make it so the 2nd argument of DLIB_CASSERT is optional. That is, you can call it like
// DLIB_CASSERT(exp) or DLIB_CASSERT(exp,message).
#define DLIBM_CASSERT_1_ARGS(exp) DLIBM_CASSERT(exp,"")
#define DLIBM_CASSERT_2_ARGS(exp,message) DLIBM_CASSERT(exp,message)
#define DLIBM_GET_3TH_ARG(arg1, arg2, arg3, ...) arg3
#define DLIBM_CASSERT_CHOOSER(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_GET_3TH_ARG(__VA_ARGS__, DLIBM_CASSERT_2_ARGS, DLIBM_CASSERT_1_ARGS))
#define DLIB_CASSERT(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_CASSERT_CHOOSER(__VA_ARGS__)(__VA_ARGS__))
#ifdef ENABLE_ASSERTS
#define DLIB_ASSERT(...) DLIB_CASSERT(__VA_ARGS__)
#define DLIB_IF_ASSERT(exp) exp
#else
#define DLIB_ASSERT(...) {}
#define DLIB_IF_ASSERT(exp)
#endif
// ----------------------------------------------------------------------------------------
/*!A DLIB_ASSERT_HAS_STANDARD_LAYOUT
This macro is meant to cause a compiler error if a type doesn't have a simple
memory layout (like a C struct). In particular, types with simple layouts are
ones which can be copied via memcpy().
This was called a POD type in C++03 and in C++0x we are looking to check if
it is a "standard layout type". Once we can use C++0x we can change this macro
to something that uses the std::is_standard_layout type_traits class.
See: http://www2.research.att.com/~bs/C++0xFAQ.html#PODs
!*/
// Use the fact that in C++03 you can't put non-PODs into a union.
#define DLIB_ASSERT_HAS_STANDARD_LAYOUT(type) \
union DLIB_BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; }; \
DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(DLIB_BOOST_JOIN(DAHSL_,__LINE__))];
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// breakpoints
extern "C"
{
inline void dlib_assert_breakpoint(
) {}
/*!
ensures
- this function does nothing
It exists just so you can put breakpoints on it in a debugging tool.
It is called only when an DLIB_ASSERT or DLIB_CASSERT fails and is about to
throw an exception.
!*/
}
// -----------------------------
#include "stack_trace.h"
#endif // DLIB_ASSERt_

View File

@@ -0,0 +1,9 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BASe64_
#define DLIB_BASe64_
#include "base64/base64_kernel_1.h"
#endif // DLIB_BASe64_

View File

@@ -0,0 +1,92 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BASE64_KERNEl_1_
#define DLIB_BASE64_KERNEl_1_
#include "../algs.h"
#include "base64_kernel_abstract.h"
#include <iosfwd>
namespace dlib
{
class base64
{
/*!
INITIAL VALUE
- bad_value == 100
- encode_table == a pointer to an array of 64 chars
- where x is a 6 bit value the following is true:
- encode_table[x] == the base64 encoding of x
- decode_table == a pointer to an array of UCHAR_MAX chars
- where x is any char value:
- if (x is a valid character in the base64 coding scheme) then
- decode_table[x] == the 6 bit value that x encodes
- else
- decode_table[x] == bad_value
CONVENTION
- The state of this object never changes so just refer to its
initial value.
!*/
public:
// this is here for backwards compatibility with older versions of dlib.
typedef base64 kernel_1a;
class decode_error : public dlib::error { public:
decode_error( const std::string& e) : error(e) {}};
base64 (
);
virtual ~base64 (
);
enum line_ending_type
{
CR, // i.e. "\r"
LF, // i.e. "\n"
CRLF // i.e. "\r\n"
};
line_ending_type line_ending (
) const;
void set_line_ending (
line_ending_type eol_style_
);
void encode (
std::istream& in,
std::ostream& out
) const;
void decode (
std::istream& in,
std::ostream& out
) const;
private:
char* encode_table;
unsigned char* decode_table;
const unsigned char bad_value;
line_ending_type eol_style;
// restricted functions
base64(base64&); // copy constructor
base64& operator=(base64&); // assignment operator
};
}
#ifdef NO_MAKEFILE
#include "base64_kernel_1.cpp"
#endif
#endif // DLIB_BASE64_KERNEl_1_

View File

@@ -0,0 +1,121 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BASE64_KERNEl_ABSTRACT_
#ifdef DLIB_BASE64_KERNEl_ABSTRACT_
#include "../algs.h"
#include <iosfwd>
namespace dlib
{
class base64
{
/*!
INITIAL VALUE
- line_ending() == LF
WHAT THIS OBJECT REPRESENTS
This object consists of the two functions encode and decode.
These functions allow you to encode and decode data to and from
the Base64 Content-Transfer-Encoding defined in section 6.8 of
rfc2045.
!*/
public:
class decode_error : public dlib::error {};
base64 (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~base64 (
);
/*!
ensures
- all memory associated with *this has been released
!*/
enum line_ending_type
{
CR, // i.e. "\r"
LF, // i.e. "\n"
CRLF // i.e. "\r\n"
};
line_ending_type line_ending (
) const;
/*!
ensures
- returns the type of end of line bytes the encoder
will use when encoding data to base64 blocks. Note that
the ostream object you use might apply some sort of transform
to line endings as well. For example, C++ ofstream objects
usually convert '\n' into whatever a normal newline is for
your platform unless you open a file in binary mode. But
aside from file streams the ostream objects usually don't
modify the data you pass to them.
!*/
void set_line_ending (
line_ending_type eol_style
);
/*!
ensures
- #line_ending() == eol_style
!*/
void encode (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- reads all data from in (until EOF is reached) and encodes it
and writes it to out
throws
- std::ios_base::failure
if there was a problem writing to out then this exception will
be thrown.
- any other exception
this exception may be thrown if there is any other problem
!*/
void decode (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- reads data from in (until EOF is reached), decodes it,
and writes it to out.
throws
- std::ios_base::failure
if there was a problem writing to out then this exception will
be thrown.
- decode_error
if an error was detected in the encoded data that prevented
it from being correctly decoded then this exception is
thrown.
- any other exception
this exception may be thrown if there is any other problem
!*/
private:
// restricted functions
base64(base64&); // copy constructor
base64& operator=(base64&); // assignment operator
};
}
#endif // DLIB_BASE64_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BAYES_UTILs_H_
#define DLIB_BAYES_UTILs_H_
#include "bayes_utils/bayes_utils.h"
#endif // DLIB_BAYES_UTILs_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIGINt_
#define DLIB_BIGINt_
#include "bigint/bigint_kernel_1.h"
#include "bigint/bigint_kernel_2.h"
#include "bigint/bigint_kernel_c.h"
namespace dlib
{
class bigint
{
bigint() {}
public:
//----------- kernels ---------------
// kernel_1a
typedef bigint_kernel_1
kernel_1a;
typedef bigint_kernel_c<kernel_1a>
kernel_1a_c;
// kernel_2a
typedef bigint_kernel_2
kernel_2a;
typedef bigint_kernel_c<kernel_2a>
kernel_2a_c;
};
}
#endif // DLIB_BIGINt_

View File

@@ -0,0 +1,544 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIGINT_KERNEl_1_
#define DLIB_BIGINT_KERNEl_1_
#include "bigint_kernel_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "../uintn.h"
#include <iosfwd>
namespace dlib
{
class bigint_kernel_1
{
/*!
INITIAL VALUE
slack == 25
data->number[0] == 0
data->size == slack
data->references == 1
data->digits_used == 1
CONVENTION
slack == the number of extra digits placed into the number when it is
created. the slack value should never be less than 1
data->number == pointer to an array of data->size uint16s.
data represents a string of base 65535 numbers with data[0] being
the least significant bit and data[data->digits_used-1] being the most
significant
NOTE: In the comments I will consider a word to be a 16 bit value
data->digits_used == the number of significant digits in the number.
data->digits_used tells us the number of used elements in the
data->number array so everything beyond data->number[data->digits_used-1]
is undefined
data->references == the number of bigint_kernel_1 objects which refer
to this data_record
!*/
struct data_record
{
explicit data_record(
uint32 size_
) :
size(size_),
number(new uint16[size_]),
references(1),
digits_used(1)
{*number = 0;}
/*!
ensures
- initializes *this to represent zero
!*/
data_record(
const data_record& item,
uint32 additional_size
) :
size(item.digits_used + additional_size),
number(new uint16[size]),
references(1),
digits_used(item.digits_used)
{
uint16* source = item.number;
uint16* dest = number;
uint16* end = source + digits_used;
while (source != end)
{
*dest = *source;
++dest;
++source;
}
}
/*!
ensures
- *this is a copy of item except with
size == item.digits_used + additional_size
!*/
~data_record(
)
{
delete [] number;
}
const uint32 size;
uint16* number;
uint32 references;
uint32 digits_used;
private:
// no copy constructor
data_record ( data_record&);
};
// note that the second parameter is just there
// to resolve the ambiguity between this constructor and
// bigint_kernel_1(uint32)
explicit bigint_kernel_1 (
data_record* data_, int
): slack(25),data(data_) {}
/*!
ensures
- *this is initialized with data_ as its data member
!*/
public:
bigint_kernel_1 (
);
bigint_kernel_1 (
uint32 value
);
bigint_kernel_1 (
const bigint_kernel_1& item
);
virtual ~bigint_kernel_1 (
);
const bigint_kernel_1 operator+ (
const bigint_kernel_1& rhs
) const;
bigint_kernel_1& operator+= (
const bigint_kernel_1& rhs
);
const bigint_kernel_1 operator- (
const bigint_kernel_1& rhs
) const;
bigint_kernel_1& operator-= (
const bigint_kernel_1& rhs
);
const bigint_kernel_1 operator* (
const bigint_kernel_1& rhs
) const;
bigint_kernel_1& operator*= (
const bigint_kernel_1& rhs
);
const bigint_kernel_1 operator/ (
const bigint_kernel_1& rhs
) const;
bigint_kernel_1& operator/= (
const bigint_kernel_1& rhs
);
const bigint_kernel_1 operator% (
const bigint_kernel_1& rhs
) const;
bigint_kernel_1& operator%= (
const bigint_kernel_1& rhs
);
bool operator < (
const bigint_kernel_1& rhs
) const;
bool operator == (
const bigint_kernel_1& rhs
) const;
bigint_kernel_1& operator= (
const bigint_kernel_1& rhs
);
friend std::ostream& operator<< (
std::ostream& out,
const bigint_kernel_1& rhs
);
friend std::istream& operator>> (
std::istream& in,
bigint_kernel_1& rhs
);
bigint_kernel_1& operator++ (
);
const bigint_kernel_1 operator++ (
int
);
bigint_kernel_1& operator-- (
);
const bigint_kernel_1 operator-- (
int
);
friend const bigint_kernel_1 operator+ (
uint16 lhs,
const bigint_kernel_1& rhs
);
friend const bigint_kernel_1 operator+ (
const bigint_kernel_1& lhs,
uint16 rhs
);
bigint_kernel_1& operator+= (
uint16 rhs
);
friend const bigint_kernel_1 operator- (
uint16 lhs,
const bigint_kernel_1& rhs
);
friend const bigint_kernel_1 operator- (
const bigint_kernel_1& lhs,
uint16 rhs
);
bigint_kernel_1& operator-= (
uint16 rhs
);
friend const bigint_kernel_1 operator* (
uint16 lhs,
const bigint_kernel_1& rhs
);
friend const bigint_kernel_1 operator* (
const bigint_kernel_1& lhs,
uint16 rhs
);
bigint_kernel_1& operator*= (
uint16 rhs
);
friend const bigint_kernel_1 operator/ (
uint16 lhs,
const bigint_kernel_1& rhs
);
friend const bigint_kernel_1 operator/ (
const bigint_kernel_1& lhs,
uint16 rhs
);
bigint_kernel_1& operator/= (
uint16 rhs
);
friend const bigint_kernel_1 operator% (
uint16 lhs,
const bigint_kernel_1& rhs
);
friend const bigint_kernel_1 operator% (
const bigint_kernel_1& lhs,
uint16 rhs
);
bigint_kernel_1& operator%= (
uint16 rhs
);
friend bool operator < (
uint16 lhs,
const bigint_kernel_1& rhs
);
friend bool operator < (
const bigint_kernel_1& lhs,
uint16 rhs
);
friend bool operator == (
const bigint_kernel_1& lhs,
uint16 rhs
);
friend bool operator == (
uint16 lhs,
const bigint_kernel_1& rhs
);
bigint_kernel_1& operator= (
uint16 rhs
);
void swap (
bigint_kernel_1& item
) { data_record* temp = data; data = item.data; item.data = temp; }
private:
void long_add (
const data_record* lhs,
const data_record* rhs,
data_record* result
) const;
/*!
requires
- result->size >= max(lhs->digits_used,rhs->digits_used) + 1
ensures
- result == lhs + rhs
!*/
void long_sub (
const data_record* lhs,
const data_record* rhs,
data_record* result
) const;
/*!
requires
- lhs >= rhs
- result->size >= lhs->digits_used
ensures
- result == lhs - rhs
!*/
void long_div (
const data_record* lhs,
const data_record* rhs,
data_record* result,
data_record* remainder
) const;
/*!
requires
- rhs != 0
- result->size >= lhs->digits_used
- remainder->size >= lhs->digits_used
- each parameter is unique (i.e. lhs != result, lhs != remainder, etc.)
ensures
- result == lhs / rhs
- remainder == lhs % rhs
!*/
void long_mul (
const data_record* lhs,
const data_record* rhs,
data_record* result
) const;
/*!
requires
- result->size >= lhs->digits_used + rhs->digits_used
- result != lhs
- result != rhs
ensures
- result == lhs * rhs
!*/
void short_add (
const data_record* data,
uint16 value,
data_record* result
) const;
/*!
requires
- result->size >= data->size + 1
ensures
- result == data + value
!*/
void short_sub (
const data_record* data,
uint16 value,
data_record* result
) const;
/*!
requires
- data >= value
- result->size >= data->digits_used
ensures
- result == data - value
!*/
void short_mul (
const data_record* data,
uint16 value,
data_record* result
) const;
/*!
requires
- result->size >= data->digits_used + 1
ensures
- result == data * value
!*/
void short_div (
const data_record* data,
uint16 value,
data_record* result,
uint16& remainder
) const;
/*!
requires
- value != 0
- result->size >= data->digits_used
ensures
- result = data*value
- remainder = data%value
!*/
void shift_left (
const data_record* data,
data_record* result,
uint32 shift_amount
) const;
/*!
requires
- result->size >= data->digits_used + shift_amount/8 + 1
ensures
- result == data << shift_amount
!*/
void shift_right (
const data_record* data,
data_record* result
) const;
/*!
requires
- result->size >= data->digits_used
ensures
- result == data >> 1
!*/
bool is_less_than (
const data_record* lhs,
const data_record* rhs
) const;
/*!
ensures
- returns true if lhs < rhs
- returns false otherwise
!*/
bool is_equal_to (
const data_record* lhs,
const data_record* rhs
) const;
/*!
ensures
- returns true if lhs == rhs
- returns false otherwise
!*/
void increment (
const data_record* source,
data_record* dest
) const;
/*!
requires
- dest->size >= source->digits_used + 1
ensures
- dest = source + 1
!*/
void decrement (
const data_record* source,
data_record* dest
) const;
/*!
requires
source != 0
ensuers
dest = source - 1
!*/
// member data
const uint32 slack;
data_record* data;
};
inline void swap (
bigint_kernel_1& a,
bigint_kernel_1& b
) { a.swap(b); }
inline void serialize (
const bigint_kernel_1& item,
std::ostream& out
)
{
std::ios::fmtflags oldflags = out.flags();
out.flags();
out << item << ' ';
out.flags(oldflags);
if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c");
}
inline void deserialize (
bigint_kernel_1& item,
std::istream& in
)
{
std::ios::fmtflags oldflags = in.flags();
in.flags();
in >> item; in.flags(oldflags);
if (in.get() != ' ')
{
item = 0;
throw serialization_error("Error deserializing object of type bigint_kernel_c");
}
}
inline bool operator> (const bigint_kernel_1& a, const bigint_kernel_1& b) { return b < a; }
inline bool operator!= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(a == b); }
inline bool operator<= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(b < a); }
inline bool operator>= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(a < b); }
}
#ifdef NO_MAKEFILE
#include "bigint_kernel_1.cpp"
#endif
#endif // DLIB_BIGINT_KERNEl_1_

View File

@@ -0,0 +1,570 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIGINT_KERNEl_2_
#define DLIB_BIGINT_KERNEl_2_
#include "bigint_kernel_abstract.h"
#include "../algs.h"
#include "../serialize.h"
#include "../uintn.h"
#include <iosfwd>
#include <cmath>
#include <complex>
#include <vector>
namespace dlib
{
class bigint_kernel_2
{
/*!
INITIAL VALUE
slack == 25
data->number[0] == 0
data->size == slack
data->references == 1
data->digits_used == 1
CONVENTION
slack == the number of extra digits placed into the number when it is
created. the slack value should never be less than 1
data->number == pointer to an array of data->size uint16s.
data represents a string of base 65535 numbers with data[0] being
the least significant bit and data[data->digits_used-1] being the most
significant
NOTE: In the comments I will consider a word to be a 16 bit value
data->digits_used == the number of significant digits in the number.
data->digits_used tells us the number of used elements in the
data->number array so everything beyond data->number[data->digits_used-1]
is undefined
data->references == the number of bigint_kernel_2 objects which refer
to this data_record
!*/
struct data_record
{
explicit data_record(
uint32 size_
) :
size(size_),
number(new uint16[size_]),
references(1),
digits_used(1)
{*number = 0;}
/*!
ensures
- initializes *this to represent zero
!*/
data_record(
const data_record& item,
uint32 additional_size
) :
size(item.digits_used + additional_size),
number(new uint16[size]),
references(1),
digits_used(item.digits_used)
{
uint16* source = item.number;
uint16* dest = number;
uint16* end = source + digits_used;
while (source != end)
{
*dest = *source;
++dest;
++source;
}
}
/*!
ensures
- *this is a copy of item except with
size == item.digits_used + additional_size
!*/
~data_record(
)
{
delete [] number;
}
const uint32 size;
uint16* number;
uint32 references;
uint32 digits_used;
private:
// no copy constructor
data_record ( data_record&);
};
// note that the second parameter is just there
// to resolve the ambiguity between this constructor and
// bigint_kernel_2(uint32)
explicit bigint_kernel_2 (
data_record* data_, int
): slack(25),data(data_) {}
/*!
ensures
- *this is initialized with data_ as its data member
!*/
public:
bigint_kernel_2 (
);
bigint_kernel_2 (
uint32 value
);
bigint_kernel_2 (
const bigint_kernel_2& item
);
virtual ~bigint_kernel_2 (
);
const bigint_kernel_2 operator+ (
const bigint_kernel_2& rhs
) const;
bigint_kernel_2& operator+= (
const bigint_kernel_2& rhs
);
const bigint_kernel_2 operator- (
const bigint_kernel_2& rhs
) const;
bigint_kernel_2& operator-= (
const bigint_kernel_2& rhs
);
const bigint_kernel_2 operator* (
const bigint_kernel_2& rhs
) const;
bigint_kernel_2& operator*= (
const bigint_kernel_2& rhs
);
const bigint_kernel_2 operator/ (
const bigint_kernel_2& rhs
) const;
bigint_kernel_2& operator/= (
const bigint_kernel_2& rhs
);
const bigint_kernel_2 operator% (
const bigint_kernel_2& rhs
) const;
bigint_kernel_2& operator%= (
const bigint_kernel_2& rhs
);
bool operator < (
const bigint_kernel_2& rhs
) const;
bool operator == (
const bigint_kernel_2& rhs
) const;
bigint_kernel_2& operator= (
const bigint_kernel_2& rhs
);
friend std::ostream& operator<< (
std::ostream& out,
const bigint_kernel_2& rhs
);
friend std::istream& operator>> (
std::istream& in,
bigint_kernel_2& rhs
);
bigint_kernel_2& operator++ (
);
const bigint_kernel_2 operator++ (
int
);
bigint_kernel_2& operator-- (
);
const bigint_kernel_2 operator-- (
int
);
friend const bigint_kernel_2 operator+ (
uint16 lhs,
const bigint_kernel_2& rhs
);
friend const bigint_kernel_2 operator+ (
const bigint_kernel_2& lhs,
uint16 rhs
);
bigint_kernel_2& operator+= (
uint16 rhs
);
friend const bigint_kernel_2 operator- (
uint16 lhs,
const bigint_kernel_2& rhs
);
friend const bigint_kernel_2 operator- (
const bigint_kernel_2& lhs,
uint16 rhs
);
bigint_kernel_2& operator-= (
uint16 rhs
);
friend const bigint_kernel_2 operator* (
uint16 lhs,
const bigint_kernel_2& rhs
);
friend const bigint_kernel_2 operator* (
const bigint_kernel_2& lhs,
uint16 rhs
);
bigint_kernel_2& operator*= (
uint16 rhs
);
friend const bigint_kernel_2 operator/ (
uint16 lhs,
const bigint_kernel_2& rhs
);
friend const bigint_kernel_2 operator/ (
const bigint_kernel_2& lhs,
uint16 rhs
);
bigint_kernel_2& operator/= (
uint16 rhs
);
friend const bigint_kernel_2 operator% (
uint16 lhs,
const bigint_kernel_2& rhs
);
friend const bigint_kernel_2 operator% (
const bigint_kernel_2& lhs,
uint16 rhs
);
bigint_kernel_2& operator%= (
uint16 rhs
);
friend bool operator < (
uint16 lhs,
const bigint_kernel_2& rhs
);
friend bool operator < (
const bigint_kernel_2& lhs,
uint16 rhs
);
friend bool operator == (
const bigint_kernel_2& lhs,
uint16 rhs
);
friend bool operator == (
uint16 lhs,
const bigint_kernel_2& rhs
);
bigint_kernel_2& operator= (
uint16 rhs
);
void swap (
bigint_kernel_2& item
) { data_record* temp = data; data = item.data; item.data = temp; }
private:
typedef double t;
typedef std::complex<t> ct;
void fft(
ct* data,
unsigned long len
) const;
/*!
requires
- len == x^n for some integer n (i.e. len is a power of 2)
- len > 0
ensures
- #data == the FT decimation in frequency of data
!*/
void ifft(
ct* data,
unsigned long len
) const;
/*!
requires
- len == x^n for some integer n (i.e. len is a power of 2)
- len > 0
ensures
- #data == the inverse decimation in frequency of data.
(i.e. the inverse of what fft(data,len,-1) does to data)
!*/
void long_add (
const data_record* lhs,
const data_record* rhs,
data_record* result
) const;
/*!
requires
- result->size >= max(lhs->digits_used,rhs->digits_used) + 1
ensures
- result == lhs + rhs
!*/
void long_sub (
const data_record* lhs,
const data_record* rhs,
data_record* result
) const;
/*!
requires
- lhs >= rhs
- result->size >= lhs->digits_used
ensures
- result == lhs - rhs
!*/
void long_div (
const data_record* lhs,
const data_record* rhs,
data_record* result,
data_record* remainder
) const;
/*!
requires
- rhs != 0
- result->size >= lhs->digits_used
- remainder->size >= lhs->digits_used
- each parameter is unique (i.e. lhs != result, lhs != remainder, etc.)
ensures
- result == lhs / rhs
- remainder == lhs % rhs
!*/
void long_mul (
const data_record* lhs,
const data_record* rhs,
data_record* result
) const;
/*!
requires
- result->size >= lhs->digits_used + rhs->digits_used
- result != lhs
- result != rhs
ensures
- result == lhs * rhs
!*/
void short_add (
const data_record* data,
uint16 value,
data_record* result
) const;
/*!
requires
- result->size >= data->size + 1
ensures
- result == data + value
!*/
void short_sub (
const data_record* data,
uint16 value,
data_record* result
) const;
/*!
requires
- data >= value
- result->size >= data->digits_used
ensures
- result == data - value
!*/
void short_mul (
const data_record* data,
uint16 value,
data_record* result
) const;
/*!
requires
- result->size >= data->digits_used + 1
ensures
- result == data * value
!*/
void short_div (
const data_record* data,
uint16 value,
data_record* result,
uint16& remainder
) const;
/*!
requires
- value != 0
- result->size >= data->digits_used
ensures
- result = data*value
- remainder = data%value
!*/
void shift_left (
const data_record* data,
data_record* result,
uint32 shift_amount
) const;
/*!
requires
- result->size >= data->digits_used + shift_amount/8 + 1
ensures
- result == data << shift_amount
!*/
void shift_right (
const data_record* data,
data_record* result
) const;
/*!
requires
- result->size >= data->digits_used
ensures
- result == data >> 1
!*/
bool is_less_than (
const data_record* lhs,
const data_record* rhs
) const;
/*!
ensures
- returns true if lhs < rhs
- returns false otherwise
!*/
bool is_equal_to (
const data_record* lhs,
const data_record* rhs
) const;
/*!
ensures
- returns true if lhs == rhs
- returns false otherwise
!*/
void increment (
const data_record* source,
data_record* dest
) const;
/*!
requires
- dest->size >= source->digits_used + 1
ensures
- dest = source + 1
!*/
void decrement (
const data_record* source,
data_record* dest
) const;
/*!
requires
source != 0
ensuers
dest = source - 1
!*/
// member data
const uint32 slack;
data_record* data;
};
inline void swap (
bigint_kernel_2& a,
bigint_kernel_2& b
) { a.swap(b); }
inline void serialize (
const bigint_kernel_2& item,
std::ostream& out
)
{
std::ios::fmtflags oldflags = out.flags();
out.flags();
out << item << ' ';
out.flags(oldflags);
if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c");
}
inline void deserialize (
bigint_kernel_2& item,
std::istream& in
)
{
std::ios::fmtflags oldflags = in.flags();
in.flags();
in >> item; in.flags(oldflags);
if (in.get() != ' ')
{
item = 0;
throw serialization_error("Error deserializing object of type bigint_kernel_c");
}
}
inline bool operator> (const bigint_kernel_2& a, const bigint_kernel_2& b) { return b < a; }
inline bool operator!= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(a == b); }
inline bool operator<= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(b < a); }
inline bool operator>= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(a < b); }
}
#ifdef NO_MAKEFILE
#include "bigint_kernel_2.cpp"
#endif
#endif // DLIB_BIGINT_KERNEl_2_

View File

@@ -0,0 +1,670 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BIGINT_KERNEl_ABSTRACT_
#ifdef DLIB_BIGINT_KERNEl_ABSTRACT_
#include <iosfwd>
#include "../algs.h"
#include "../serialize.h"
#include "../uintn.h"
namespace dlib
{
class bigint
{
/*!
INITIAL VALUE
*this == 0
WHAT THIS OBJECT REPRESENTS
This object represents an arbitrary precision unsigned integer
the following operators are supported:
operator +
operator +=
operator -
operator -=
operator *
operator *=
operator /
operator /=
operator %
operator %=
operator ==
operator <
operator =
operator << (for writing to ostreams)
operator >> (for reading from istreams)
operator++ // pre increment
operator++(int) // post increment
operator-- // pre decrement
operator--(int) // post decrement
the other comparason operators(>, !=, <=, and >=) are
available and come from the templates in dlib::relational_operators
THREAD SAFETY
bigint may be reference counted so it is very unthread safe.
use with care in a multithreaded program
!*/
public:
bigint (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
if this is thrown the bigint will be unusable but
will not leak memory
!*/
bigint (
uint32 value
);
/*!
requires
- value <= (2^32)-1
ensures
- #*this is properly initialized
- #*this == value
throws
- std::bad_alloc
if this is thrown the bigint will be unusable but
will not leak memory
!*/
bigint (
const bigint& item
);
/*!
ensures
- #*this is properly initialized
- #*this == value
throws
- std::bad_alloc
if this is thrown the bigint will be unusable but
will not leak memory
!*/
virtual ~bigint (
);
/*!
ensures
- all resources associated with #*this have been released
!*/
const bigint operator+ (
const bigint& rhs
) const;
/*!
ensures
- returns the result of adding rhs to *this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator+= (
const bigint& rhs
);
/*!
ensures
- #*this == *this + rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
const bigint operator- (
const bigint& rhs
) const;
/*!
requires
- *this >= rhs
ensures
- returns the result of subtracting rhs from *this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator-= (
const bigint& rhs
);
/*!
requires
- *this >= rhs
ensures
- #*this == *this - rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
const bigint operator* (
const bigint& rhs
) const;
/*!
ensures
- returns the result of multiplying *this and rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator*= (
const bigint& rhs
);
/*!
ensures
- #*this == *this * rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
const bigint operator/ (
const bigint& rhs
) const;
/*!
requires
- rhs != 0
ensures
- returns the result of dividing *this by rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator/= (
const bigint& rhs
);
/*!
requires
- rhs != 0
ensures
- #*this == *this / rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
const bigint operator% (
const bigint& rhs
) const;
/*!
requires
- rhs != 0
ensures
- returns the result of *this mod rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator%= (
const bigint& rhs
);
/*!
requires
- rhs != 0
ensures
- #*this == *this % rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bool operator < (
const bigint& rhs
) const;
/*!
ensures
- returns true if *this is less than rhs
- returns false otherwise
!*/
bool operator == (
const bigint& rhs
) const;
/*!
ensures
- returns true if *this and rhs represent the same number
- returns false otherwise
!*/
bigint& operator= (
const bigint& rhs
);
/*!
ensures
- #*this == rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend std::ostream& operator<< (
std::ostream& out,
const bigint& rhs
);
/*!
ensures
- the number in *this has been written to #out as a base ten number
throws
- std::bad_alloc
if this function throws then it has no effect (nothing
is written to out)
!*/
friend std::istream& operator>> (
std::istream& in,
bigint& rhs
);
/*!
ensures
- reads a number from in and puts it into #*this
- if (there is no positive base ten number on the input stream ) then
- #in.fail() == true
throws
- std::bad_alloc
if this function throws the value in rhs is undefined and some
characters may have been read from in. rhs is still usable though,
its value is just unknown.
!*/
bigint& operator++ (
);
/*!
ensures
- #*this == *this + 1
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
const bigint operator++ (
int
);
/*!
ensures
- #*this == *this + 1
- returns *this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator-- (
);
/*!
requires
- *this != 0
ensures
- #*this == *this - 1
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
const bigint operator-- (
int
);
/*!
requires
- *this != 0
ensures
- #*this == *this - 1
- returns *this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
void swap (
bigint& item
);
/*!
ensures
- swaps *this and item
!*/
// ------------------------------------------------------------------
// ---- The following functions are identical to the above -----
// ---- but take uint16 as one of their arguments. They ---
// ---- exist only to allow for a more efficient implementation ---
// ------------------------------------------------------------------
friend const bigint operator+ (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- lhs <= 65535
ensures
- returns the result of adding rhs to lhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator+ (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- returns the result of adding rhs to lhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator+= (
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- #*this == *this + rhs
- returns #this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator- (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- lhs >= rhs
- lhs <= 65535
ensures
- returns the result of subtracting rhs from lhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator- (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- lhs >= rhs
- rhs <= 65535
ensures
- returns the result of subtracting rhs from lhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator-= (
uint16 rhs
);
/*!
requires
- *this >= rhs
- rhs <= 65535
ensures
- #*this == *this - rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator* (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- lhs <= 65535
ensures
- returns the result of multiplying lhs and rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator* (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- returns the result of multiplying lhs and rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator*= (
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- #*this == *this * rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator/ (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- rhs != 0
- lhs <= 65535
ensures
- returns the result of dividing lhs by rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator/ (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- rhs != 0
- rhs <= 65535
ensures
- returns the result of dividing lhs by rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator/= (
uint16 rhs
);
/*!
requires
- rhs != 0
- rhs <= 65535
ensures
- #*this == *this / rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator% (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- rhs != 0
- lhs <= 65535
ensures
- returns the result of lhs mod rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend const bigint operator% (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- rhs != 0
- rhs <= 65535
ensures
- returns the result of lhs mod rhs
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
bigint& operator%= (
uint16 rhs
);
/*!
requires
- rhs != 0
- rhs <= 65535
ensures
- #*this == *this % rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
friend bool operator < (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- lhs <= 65535
ensures
- returns true if lhs is less than rhs
- returns false otherwise
!*/
friend bool operator < (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- returns true if lhs is less than rhs
- returns false otherwise
!*/
friend bool operator == (
const bigint& lhs,
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- returns true if lhs and rhs represent the same number
- returns false otherwise
!*/
friend bool operator == (
uint16 lhs,
const bigint& rhs
);
/*!
requires
- lhs <= 65535
ensures
- returns true if lhs and rhs represent the same number
- returns false otherwise
!*/
bigint& operator= (
uint16 rhs
);
/*!
requires
- rhs <= 65535
ensures
- #*this == rhs
- returns #*this
throws
- std::bad_alloc
if this function throws then it has no effect
!*/
};
inline void swap (
bigint& a,
bigint& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
void serialize (
const bigint& item,
std::istream& in
);
/*!
provides serialization support
!*/
void deserialize (
bigint& item,
std::istream& in
);
/*!
provides deserialization support
!*/
inline bool operator> (const bigint& a, const bigint& b) { return b < a; }
inline bool operator!= (const bigint& a, const bigint& b) { return !(a == b); }
inline bool operator<= (const bigint& a, const bigint& b) { return !(b < a); }
inline bool operator>= (const bigint& a, const bigint& b) { return !(a < b); }
}
#endif // DLIB_BIGINT_KERNEl_ABSTRACT_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BINARY_SEARCH_TREe_
#define DLIB_BINARY_SEARCH_TREe_
#include "binary_search_tree/binary_search_tree_kernel_1.h"
#include "binary_search_tree/binary_search_tree_kernel_2.h"
#include "binary_search_tree/binary_search_tree_kernel_c.h"
#include "algs.h"
#include <functional>
namespace dlib
{
template <
typename domain,
typename range,
typename mem_manager = default_memory_manager,
typename compare = std::less<domain>
>
class binary_search_tree
{
binary_search_tree() {}
public:
//----------- kernels ---------------
// kernel_1a
typedef binary_search_tree_kernel_1<domain,range,mem_manager,compare>
kernel_1a;
typedef binary_search_tree_kernel_c<kernel_1a>
kernel_1a_c;
// kernel_2a
typedef binary_search_tree_kernel_2<domain,range,mem_manager,compare>
kernel_2a;
typedef binary_search_tree_kernel_c<kernel_2a>
kernel_2a_c;
};
}
#endif // DLIB_BINARY_SEARCH_TREe_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,311 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_
#ifdef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_
#include "../interfaces/map_pair.h"
#include "../interfaces/enumerable.h"
#include "../interfaces/remover.h"
#include "../serialize.h"
#include "../algs.h"
#include <functional>
namespace dlib
{
template <
typename domain,
typename range,
typename mem_manager = default_memory_manager,
typename compare = std::less<domain>
>
class binary_search_tree : public enumerable<map_pair<domain,range> >,
public asc_pair_remover<domain,range,compare>
{
/*!
REQUIREMENTS ON domain
domain must be comparable by compare where compare is a functor compatible with std::less and
domain is swappable by a global swap() and
domain must have a default constructor
REQUIREMENTS ON range
range is swappable by a global swap() and
range must have a default constructor
REQUIREMENTS ON mem_manager
must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
mem_manager::type can be set to anything.
POINTERS AND REFERENCES TO INTERNAL DATA
swap(), count(), height(), and operator[] functions
do not invalidate pointers or references to internal data.
position_enumerator() invalidates pointers or references to
data returned by element() and only by element() (i.e. pointers and
references returned by operator[] are still valid).
All other functions have no such guarantees.
INITIAL VALUE
size() == 0
height() == 0
ENUMERATION ORDER
The enumerator will iterate over the domain (and each associated
range element) elements in ascending order according to the compare functor.
(i.e. the elements are enumerated in sorted order)
WHAT THIS OBJECT REPRESENTS
this object represents a data dictionary that is built on top of some
kind of binary search tree. It maps objects of type domain to objects
of type range.
Also note that unless specified otherwise, no member functions
of this object throw exceptions.
NOTE:
definition of equivalent:
a is equivalent to b if
a < b == false and
b < a == false
!*/
public:
typedef domain domain_type;
typedef range range_type;
typedef compare compare_type;
typedef mem_manager mem_manager_type;
binary_search_tree(
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc or any exception thrown by domain's or range's
constructor.
!*/
virtual ~binary_search_tree(
);
/*!
ensures
- all memory associated with *this has been released
!*/
void clear(
);
/*!
ensures
- #*this has its initial value
throws
- std::bad_alloc or any exception thrown by domain's or range's
constructor.
if this exception is thrown then *this is unusable
until clear() is called and succeeds
!*/
short height (
) const;
/*!
ensures
- returns the number of elements in the longest path from the root
of the tree to a leaf
!*/
unsigned long count (
const domain& d
) const;
/*!
ensures
- returns the number of elements in the domain of *this that are
equivalent to d
!*/
void add (
domain& d,
range& r
);
/*!
requires
- &d != &r (i.e. d and r cannot be the same variable)
ensures
- adds a mapping between d and r to *this
- if (count(d) == 0) then
- #*(*this)[d] == r
- else
- #(*this)[d] != 0
- #d and #r have initial values for their types
- #count(d) == count(d) + 1
- #at_start() == true
- #size() == size() + 1
throws
- std::bad_alloc or any exception thrown by domain's or range's
constructor.
if add() throws then it has no effect
!*/
void remove (
const domain& d,
domain& d_copy,
range& r
);
/*!
requires
- (*this)[d] != 0
- &d != &r (i.e. d and r cannot be the same variable)
- &d != &d_copy (i.e. d and d_copy cannot be the same variable)
- &r != &d_copy (i.e. r and d_copy cannot be the same variable)
ensures
- some element in the domain of *this that is equivalent to d has
been removed and swapped into #d_copy. Additionally, its
associated range element has been removed and swapped into #r.
- #count(d) == count(d) - 1
- #size() == size() - 1
- #at_start() == true
!*/
void destroy (
const domain& d
);
/*!
requires
- (*this)[d] != 0
ensures
- an element in the domain of *this equivalent to d has been removed.
The element in the range of *this associated with d has also been
removed.
- #count(d) == count(d) - 1
- #size() == size() - 1
- #at_start() == true
!*/
void remove_last_in_order (
domain& d,
range& r
);
/*!
requires
- size() > 0
ensures
- the last/biggest (according to the compare functor) element in the domain of *this has
been removed and swapped into #d. The element in the range of *this
associated with #d has also been removed and swapped into #r.
- #count(#d) == count(#d) - 1
- #size() == size() - 1
- #at_start() == true
!*/
void remove_current_element (
domain& d,
range& r
);
/*!
requires
- current_element_valid() == true
ensures
- the current element given by element() has been removed and swapped into d and r.
- #d == element().key()
- #r == element().value()
- #count(#d) == count(#d) - 1
- #size() == size() - 1
- moves the enumerator to the next element. If element() was the last
element in enumeration order then #current_element_valid() == false
and #at_start() == false.
!*/
void position_enumerator (
const domain& d
) const;
/*!
ensures
- #at_start() == false
- if (count(d) > 0) then
- #element().key() == d
- else if (there are any items in the domain of *this that are bigger than
d according to the compare functor) then
- #element().key() == the smallest item in the domain of *this that is
bigger than d according to the compare functor.
- else
- #current_element_valid() == false
!*/
const range* operator[] (
const domain& d
) const;
/*!
ensures
- if (there is an element in the domain equivalent to d) then
- returns a pointer to an element in the range of *this that
is associated with an element in the domain of *this
equivalent to d.
- else
- returns 0
!*/
range* operator[] (
const domain& d
);
/*!
ensures
- if (there is an element in the domain equivalent to d) then
- returns a pointer to an element in the range of *this that
is associated with an element in the domain of *this
equivalent to d.
- else
- returns 0
!*/
void swap (
binary_search_tree& item
);
/*!
ensures
- swaps *this and item
!*/
private:
// restricted functions
binary_search_tree(binary_search_tree&);
binary_search_tree& operator=(binary_search_tree&);
};
template <
typename domain,
typename range,
typename mem_manager,
typename compare
>
inline void swap (
binary_search_tree<domain,range,mem_manager,compare>& a,
binary_search_tree<domain,range,mem_manager,compare>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
template <
typename domain,
typename range,
typename mem_manager,
typename compare
>
void deserialize (
binary_search_tree<domain,range,mem_manager,compare>& item,
std::istream& in
);
/*!
provides deserialization support
!*/
}
#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,235 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_C_
#define DLIB_BINARY_SEARCH_TREE_KERNEl_C_
#include "../interfaces/map_pair.h"
#include "binary_search_tree_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
namespace dlib
{
template <
typename bst_base
>
class binary_search_tree_kernel_c : public bst_base
{
typedef typename bst_base::domain_type domain;
typedef typename bst_base::range_type range;
public:
binary_search_tree_kernel_c () {}
void remove (
const domain& d,
domain& d_copy,
range& r
);
void destroy (
const domain& d
);
void add (
domain& d,
range& r
);
void remove_any (
domain& d,
range& r
);
const map_pair<domain, range>& element(
) const
{
DLIB_CASSERT(this->current_element_valid() == true,
"\tconst map_pair<domain,range>& binary_search_tree::element() const"
<< "\n\tyou can't access the current element if it doesn't exist"
<< "\n\tthis: " << this
);
return bst_base::element();
}
map_pair<domain, range>& element(
)
{
DLIB_CASSERT(this->current_element_valid() == true,
"\tmap_pair<domain,range>& binary_search_tree::element()"
<< "\n\tyou can't access the current element if it doesn't exist"
<< "\n\tthis: " << this
);
return bst_base::element();
}
void remove_last_in_order (
domain& d,
range& r
);
void remove_current_element (
domain& d,
range& r
);
};
template <
typename bst_base
>
inline void swap (
binary_search_tree_kernel_c<bst_base>& a,
binary_search_tree_kernel_c<bst_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename bst_base
>
void binary_search_tree_kernel_c<bst_base>::
add (
domain& d,
range& r
)
{
DLIB_CASSERT( static_cast<const void*>(&d) != static_cast<void*>(&r),
"\tvoid binary_search_tree::add"
<< "\n\tyou can't call add() and give the same object to both parameters."
<< "\n\tthis: " << this
<< "\n\t&d: " << &d
<< "\n\t&r: " << &r
<< "\n\tsize(): " << this->size()
);
bst_base::add(d,r);
}
// ----------------------------------------------------------------------------------------
template <
typename bst_base
>
void binary_search_tree_kernel_c<bst_base>::
destroy (
const domain& d
)
{
DLIB_CASSERT(this->operator[](d) != 0,
"\tvoid binary_search_tree::destroy"
<< "\n\tthe element must be in the tree for it to be removed"
<< "\n\tthis: " << this
<< "\n\t&d: " << &d
);
bst_base::destroy(d);
}
// ----------------------------------------------------------------------------------------
template <
typename bst_base
>
void binary_search_tree_kernel_c<bst_base>::
remove (
const domain& d,
domain& d_copy,
range& r
)
{
DLIB_CASSERT(this->operator[](d) != 0 &&
(static_cast<const void*>(&d) != static_cast<void*>(&d_copy)) &&
(static_cast<const void*>(&d) != static_cast<void*>(&r)) &&
(static_cast<const void*>(&r) != static_cast<void*>(&d_copy)),
"\tvoid binary_search_tree::remove"
<< "\n\tthe element must be in the tree for it to be removed"
<< "\n\tthis: " << this
<< "\n\t&d: " << &d
<< "\n\t&d_copy: " << &d_copy
<< "\n\t&r: " << &r
);
bst_base::remove(d,d_copy,r);
}
// ----------------------------------------------------------------------------------------
template <
typename bst_base
>
void binary_search_tree_kernel_c<bst_base>::
remove_any(
domain& d,
range& r
)
{
DLIB_CASSERT(this->size() != 0 &&
(static_cast<const void*>(&d) != static_cast<void*>(&r)),
"\tvoid binary_search_tree::remove_any"
<< "\n\ttree must not be empty if something is going to be removed"
<< "\n\tthis: " << this
<< "\n\t&d: " << &d
<< "\n\t&r: " << &r
);
bst_base::remove_any(d,r);
}
// ----------------------------------------------------------------------------------------
template <
typename bst_base
>
void binary_search_tree_kernel_c<bst_base>::
remove_last_in_order (
domain& d,
range& r
)
{
DLIB_CASSERT(this->size() > 0,
"\tvoid binary_search_tree::remove_last_in_order()"
<< "\n\tyou can't remove an element if it doesn't exist"
<< "\n\tthis: " << this
);
bst_base::remove_last_in_order(d,r);
}
// ----------------------------------------------------------------------------------------
template <
typename bst_base
>
void binary_search_tree_kernel_c<bst_base>::
remove_current_element (
domain& d,
range& r
)
{
DLIB_CASSERT(this->current_element_valid() == true,
"\tvoid binary_search_tree::remove_current_element()"
<< "\n\tyou can't remove the current element if it doesn't exist"
<< "\n\tthis: " << this
);
bst_base::remove_current_element(d,r);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_C_

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAm_
#define DLIB_BIT_STREAm_
#include "bit_stream/bit_stream_kernel_1.h"
#include "bit_stream/bit_stream_kernel_c.h"
#include "bit_stream/bit_stream_multi_1.h"
#include "bit_stream/bit_stream_multi_c.h"
namespace dlib
{
class bit_stream
{
bit_stream() {}
public:
//----------- kernels ---------------
// kernel_1a
typedef bit_stream_kernel_1
kernel_1a;
typedef bit_stream_kernel_c<kernel_1a >
kernel_1a_c;
//---------- extensions ------------
// multi_1 extend kernel_1a
typedef bit_stream_multi_1<kernel_1a>
multi_1a;
typedef bit_stream_multi_c<bit_stream_multi_1<kernel_1a_c> >
multi_1a_c;
};
}
#endif // DLIB_BIT_STREAm_

View File

@@ -0,0 +1,120 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_KERNEl_1_
#define DLIB_BIT_STREAM_KERNEl_1_
#include "bit_stream_kernel_abstract.h"
#include <iosfwd>
namespace dlib
{
class bit_stream_kernel_1
{
/*!
INITIAL VALUE
write_mode == false
read_mode == false
CONVENTION
write_mode == is_in_write_mode()
read_mode == is_in_read_mode()
if (write_mode)
{
osp == pointer to an ostream object
buffer == the low order bits of buffer are the bits to be
written
buffer_size == the number of low order bits in buffer that are
bits that should be written
the lowest order bit is the last bit entered by the user
}
if (read_mode)
{
isp == pointer to an istream object
buffer == the high order bits of buffer are the bits
waiting to be read by the user
buffer_size == the number of high order bits in buffer that
are bits that are waiting to be read
the highest order bit is the next bit to give to the user
}
!*/
public:
bit_stream_kernel_1 (
) :
write_mode(false),
read_mode(false)
{}
virtual ~bit_stream_kernel_1 (
)
{}
void clear (
);
void set_input_stream (
std::istream& is
);
void set_output_stream (
std::ostream& os
);
void close (
);
inline bool is_in_write_mode (
) const;
inline bool is_in_read_mode (
) const;
inline void write (
int bit
);
bool read (
int& bit
);
void swap (
bit_stream_kernel_1& item
);
private:
// member data
std::istream* isp;
std::ostream* osp;
bool write_mode;
bool read_mode;
unsigned char buffer;
unsigned short buffer_size;
// restricted functions
bit_stream_kernel_1(bit_stream_kernel_1&); // copy constructor
bit_stream_kernel_1& operator=(bit_stream_kernel_1&); // assignment operator
};
inline void swap (
bit_stream_kernel_1& a,
bit_stream_kernel_1& b
);
// ----------------------------------------------------------------------------------------
}
#ifdef NO_MAKEFILE
#include "bit_stream_kernel_1.cpp"
#endif
#endif // DLIB_BIT_STREAM_KERNEl_1_

View File

@@ -0,0 +1,185 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BIT_STREAM_KERNEl_ABSTRACT_
#ifdef DLIB_BIT_STREAM_KERNEl_ABSTRACT_
#include <iosfwd>
namespace dlib
{
class bit_stream
{
/*!
INITIAL VALUE
is_in_write_mode() == false
is_in_read_mode() == false
WHAT THIS OBJECT REPRESENTS
this object is a middle man between a user and the iostream classes.
it allows single bits to be read/written easily to/from
the iostream classes
BUFFERING:
This object will only read/write single bytes at a time from/to the
iostream objects. Any buffered bits still in the bit_stream object
when it is closed or destructed are lost if it is in read mode. If
it is in write mode then any remaining bits are guaranteed to be
written to the output stream by the time it is closed or destructed.
!*/
public:
bit_stream (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~bit_stream (
);
/*!
ensures
- all memory associated with *this has been released
!*/
void clear (
);
/*!
ensures
- #*this has its initial value
throws
- std::bad_alloc
if this exception is thrown then *this is unusable
until clear() is called and succeeds
!*/
void set_input_stream (
std::istream& is
);
/*!
requires
- is_in_write_mode() == false
- is_in_read_mode() == false
- is is ready to give input
ensures
- #is_in_write_mode() == false
- #is_in_read_mode() == true
- #*this will now be reading from is
throws
- std::bad_alloc
!*/
void set_output_stream (
std::ostream& os
);
/*!
requires
- is_in_write_mode() == false
- is_in_read_mode() == false
- os is ready to take output
ensures
- #is_in_write_mode() == true
- #is_in_read_mode() == false
- #*this will now write to os
throws
- std::bad_alloc
!*/
void close (
);
/*!
requires
- is_in_write_mode() == true || is_in_read_mode() == true
ensures
- #is_in_write_mode() == false
- #is_in_read_mode() == false
!*/
bool is_in_write_mode (
) const;
/*!
ensures
- returns true if *this is associated with an output stream object
- returns false otherwise
!*/
bool is_in_read_mode (
) const;
/*!
ensures
- returns true if *this is associated with an input stream object
- returns false otherwise
!*/
void write (
int bit
);
/*!
requires
- is_in_write_mode() == true
- bit == 0 || bit == 1
ensures
- bit will be written to the ostream object associated with *this
throws
- std::ios_base::failure
if (there was a problem writing to the output stream) then
this exception will be thrown. #*this will be unusable until
clear() is called and succeeds
- any other exception
if this exception is thrown then #*this is unusable
until clear() is called and succeeds
!*/
bool read (
int& bit
);
/*!
requires
- is_in_read_mode() == true
ensures
- the next bit has been read and placed into #bit
- returns true if the read was successful, else false
(ex. false if EOF has been reached)
throws
- any exception
if this exception is thrown then #*this is unusable
until clear() is called and succeeds
!*/
void swap (
bit_stream& item
);
/*!
ensures
- swaps *this and item
!*/
private:
// restricted functions
bit_stream(bit_stream&); // copy constructor
bit_stream& operator=(bit_stream&); // assignment operator
};
inline void swap (
bit_stream& a,
bit_stream& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
}
#endif // DLIB_BIT_STREAM_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,172 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_KERNEl_C_
#define DLIB_BIT_STREAM_KERNEl_C_
#include "bit_stream_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iosfwd>
namespace dlib
{
template <
typename bit_stream_base // implements bit_stream/bit_stream_kernel_abstract.h
>
class bit_stream_kernel_c : public bit_stream_base
{
public:
void set_input_stream (
std::istream& is
);
void set_output_stream (
std::ostream& os
);
void close (
);
void write (
int bit
);
bool read (
int& bit
);
};
template <
typename bit_stream_base
>
inline void swap (
bit_stream_kernel_c<bit_stream_base>& a,
bit_stream_kernel_c<bit_stream_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
void bit_stream_kernel_c<bit_stream_base>::
set_input_stream (
std::istream& is
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( this->is_in_write_mode() == false ) && ( this->is_in_read_mode() == false ),
"\tvoid bit_stream::set_intput_stream"
<< "\n\tbit_stream must not be in write or read mode"
<< "\n\tthis: " << this
);
// call the real function
bit_stream_base::set_input_stream(is);
}
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
void bit_stream_kernel_c<bit_stream_base>::
set_output_stream (
std::ostream& os
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( this->is_in_write_mode() == false ) && ( this->is_in_read_mode() == false ),
"\tvoid bit_stream::set_output_stream"
<< "\n\tbit_stream must not be in write or read mode"
<< "\n\tthis: " << this
);
// call the real function
bit_stream_base::set_output_stream(os);
}
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
void bit_stream_kernel_c<bit_stream_base>::
close (
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( this->is_in_write_mode() == true ) || ( this->is_in_read_mode() == true ),
"\tvoid bit_stream::close"
<< "\n\tyou can't close a bit_stream that isn't open"
<< "\n\tthis: " << this
);
// call the real function
bit_stream_base::close();
}
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
void bit_stream_kernel_c<bit_stream_base>::
write (
int bit
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( this->is_in_write_mode() == true ) && ( bit == 0 || bit == 1 ),
"\tvoid bit_stream::write"
<< "\n\tthe bit stream bust be in write mode and bit must be either 1 or 0"
<< "\n\tis_in_write_mode() == " << this->is_in_write_mode()
<< "\n\tbit == " << bit
<< "\n\tthis: " << this
);
// call the real function
bit_stream_base::write(bit);
}
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
bool bit_stream_kernel_c<bit_stream_base>::
read (
int& bit
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( this->is_in_read_mode() == true ),
"\tbool bit_stream::read"
<< "\n\tyou can't read from a bit_stream that isn't in read mode"
<< "\n\tthis: " << this
);
// call the real function
return bit_stream_base::read(bit);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BIT_STREAM_KERNEl_C_

View File

@@ -0,0 +1,103 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_MULTi_1_
#define DLIB_BIT_STREAM_MULTi_1_
#include "bit_stream_multi_abstract.h"
namespace dlib
{
template <
typename bit_stream_base
>
class bit_stream_multi_1 : public bit_stream_base
{
public:
void multi_write (
unsigned long data,
int num_to_write
);
int multi_read (
unsigned long& data,
int num_to_read
);
};
template <
typename bit_stream_base
>
inline void swap (
bit_stream_multi_1<bit_stream_base>& a,
bit_stream_multi_1<bit_stream_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
void bit_stream_multi_1<bit_stream_base>::
multi_write (
unsigned long data,
int num_to_write
)
{
// move the first bit into the most significant position
data <<= 32 - num_to_write;
for (int i = 0; i < num_to_write; ++i)
{
// write the first bit from data
this->write(static_cast<char>(data >> 31));
// shift the next bit into position
data <<= 1;
}
}
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
int bit_stream_multi_1<bit_stream_base>::
multi_read (
unsigned long& data,
int num_to_read
)
{
int bit, i;
data = 0;
for (i = 0; i < num_to_read; ++i)
{
// get a bit
if (this->read(bit) == false)
break;
// shift data to make room for this new bit
data <<= 1;
// put bit into the least significant position in data
data += static_cast<unsigned long>(bit);
}
return i;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BIT_STREAM_MULTi_1_

View File

@@ -0,0 +1,77 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BIT_STREAM_MULTi_ABSTRACT_
#ifdef DLIB_BIT_STREAM_MULTi_ABSTRACT_
#include "bit_stream_kernel_abstract.h"
namespace dlib
{
template <
typename bit_stream_base
>
class bit_stream_multi : public bit_stream_base
{
/*!
REQUIREMENTS ON BIT_STREAM_BASE
it is an implementation of bit_stream/bit_stream_kernel_abstract.h
WHAT THIS EXTENSION DOES FOR BIT_STREAM
this gives a bit_stream object the ability to read/write multible bits
at a time
!*/
public:
void multi_write (
unsigned long data,
int num_to_write
);
/*!
requires
- is_in_write_mode() == true
- 0 <= num_to_write <= 32
ensures
- num_to_write low order bits from data will be written to the ostream
- object associated with *this
example: if data is 10010 then the bits will be written in the
order 1,0,0,1,0
!*/
int multi_read (
unsigned long& data,
int num_to_read
);
/*!
requires
- is_in_read_mode() == true
- 0 <= num_to_read <= 32
ensures
- tries to read num_to_read bits into the low order end of #data
example: if the incoming bits were 10010 then data would end
up with 10010 as its low order bits
- all of the bits in #data not filled in by multi_read() are zero
- returns the number of bits actually read into #data
!*/
};
template <
typename bit_stream_base
>
inline void swap (
bit_stream_multi<bit_stream_base>& a,
bit_stream_multi<bit_stream_base>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
}
#endif // DLIB_BIT_STREAM_MULTi_ABSTRACT_

View File

@@ -0,0 +1,101 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BIT_STREAM_MULTi_C_
#define DLIB_BIT_STREAM_MULTi_C_
#include "bit_stream_multi_abstract.h"
#include "../algs.h"
#include "../assert.h"
namespace dlib
{
template <
typename bit_stream_base // implements bit_stream/bit_stream_multi_abstract.h
>
class bit_stream_multi_c : public bit_stream_base
{
public:
void multi_write (
unsigned long data,
int num_to_write
);
int multi_read (
unsigned long& data,
int num_to_read
);
};
template <
typename bit_stream_base
>
inline void swap (
bit_stream_multi_c<bit_stream_base>& a,
bit_stream_multi_c<bit_stream_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
void bit_stream_multi_c<bit_stream_base>::
multi_write (
unsigned long data,
int num_to_write
)
{
// make sure requires clause is not broken
DLIB_CASSERT( (this->is_in_write_mode() == true) && (num_to_write >= 0 && num_to_write <=32),
"\tvoid bit_stream::write"
<< "\n\tthe bit stream bust be in write mode and"
<< "\n\tnum_to_write must be between 0 and 32 inclusive"
<< "\n\tnum_to_write == " << num_to_write
<< "\n\tis_in_write_mode() == " << this->is_in_write_mode()
<< "\n\tthis: " << this
);
// call the real function
bit_stream_base::multi_write(data,num_to_write);
}
// ----------------------------------------------------------------------------------------
template <
typename bit_stream_base
>
int bit_stream_multi_c<bit_stream_base>::
multi_read (
unsigned long& data,
int num_to_read
)
{
// make sure requires clause is not broken
DLIB_CASSERT(( this->is_in_read_mode() == true && ( num_to_read >= 0 && num_to_read <=32 ) ),
"\tvoid bit_stream::read"
<< "\n\tyou can't read from a bit_stream that isn't in read mode and"
<< "\n\tnum_to_read must be between 0 and 32 inclusive"
<< "\n\tnum_to_read == " << num_to_read
<< "\n\tis_in_read_mode() == " << this->is_in_read_mode()
<< "\n\tthis: " << this
);
// call the real function
return bit_stream_base::multi_read(data,num_to_read);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BIT_STREAM_MULTi_C_

View File

@@ -0,0 +1 @@
#include "../dlib_include_path_tutorial.txt"

View File

@@ -0,0 +1,10 @@
// Copyright (C) 2008 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BOUND_FUNCTION_POINTEr_
#define DLIB_BOUND_FUNCTION_POINTEr_
#include "bound_function_pointer/bound_function_pointer_kernel_1.h"
#endif // DLIB_BOUND_FUNCTION_POINTEr_

View File

@@ -0,0 +1,774 @@
// Copyright (C) 2008 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_
#define DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_
#include "../algs.h"
#include "../member_function_pointer.h"
#include "bound_function_pointer_kernel_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace bfp1_helpers
{
template <typename T> struct strip { typedef T type; };
template <typename T> struct strip<T&> { typedef T type; };
// ------------------------------------------------------------------------------------
class bound_function_helper_base_base
{
public:
virtual ~bound_function_helper_base_base(){}
virtual void call() const = 0;
virtual bool is_set() const = 0;
virtual void clone(void* ptr) const = 0;
};
// ------------------------------------------------------------------------------------
template <typename T1, typename T2, typename T3, typename T4>
class bound_function_helper_base : public bound_function_helper_base_base
{
public:
bound_function_helper_base():arg1(0), arg2(0), arg3(0), arg4(0) {}
typename strip<T1>::type* arg1;
typename strip<T2>::type* arg2;
typename strip<T3>::type* arg3;
typename strip<T4>::type* arg4;
member_function_pointer<T1,T2,T3,T4> mfp;
};
// ----------------
template <typename F, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void>
class bound_function_helper : public bound_function_helper_base<T1,T2,T3,T4>
{
public:
void call() const
{
(*fp)(*this->arg1, *this->arg2, *this->arg3, *this->arg4);
}
typename strip<F>::type* fp;
};
template <typename T1, typename T2, typename T3, typename T4>
class bound_function_helper<void,T1,T2,T3,T4> : public bound_function_helper_base<T1,T2,T3,T4>
{
public:
void call() const
{
if (this->mfp) this->mfp(*this->arg1, *this->arg2, *this->arg3, *this->arg4);
else if (fp) fp(*this->arg1, *this->arg2, *this->arg3, *this->arg4);
}
void (*fp)(T1, T2, T3, T4);
};
// ----------------
template <typename F>
class bound_function_helper<F,void,void,void,void> : public bound_function_helper_base<void,void,void,void>
{
public:
void call() const
{
(*fp)();
}
typename strip<F>::type* fp;
};
template <>
class bound_function_helper<void,void,void,void,void> : public bound_function_helper_base<void,void,void,void>
{
public:
void call() const
{
if (this->mfp) this->mfp();
else if (fp) fp();
}
void (*fp)();
};
// ----------------
template <typename F, typename T1>
class bound_function_helper<F,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void>
{
public:
void call() const
{
(*fp)(*this->arg1);
}
typename strip<F>::type* fp;
};
template <typename T1>
class bound_function_helper<void,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void>
{
public:
void call() const
{
if (this->mfp) this->mfp(*this->arg1);
else if (fp) fp(*this->arg1);
}
void (*fp)(T1);
};
// ----------------
template <typename F, typename T1, typename T2>
class bound_function_helper<F,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void>
{
public:
void call() const
{
(*fp)(*this->arg1, *this->arg2);
}
typename strip<F>::type* fp;
};
template <typename T1, typename T2>
class bound_function_helper<void,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void>
{
public:
void call() const
{
if (this->mfp) this->mfp(*this->arg1, *this->arg2);
else if (fp) fp(*this->arg1, *this->arg2);
}
void (*fp)(T1, T2);
};
// ----------------
template <typename F, typename T1, typename T2, typename T3>
class bound_function_helper<F,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void>
{
public:
void call() const
{
(*fp)(*this->arg1, *this->arg2, *this->arg3);
}
typename strip<F>::type* fp;
};
template <typename T1, typename T2, typename T3>
class bound_function_helper<void,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void>
{
public:
void call() const
{
if (this->mfp) this->mfp(*this->arg1, *this->arg2, *this->arg3);
else if (fp) fp(*this->arg1, *this->arg2, *this->arg3);
}
void (*fp)(T1, T2, T3);
};
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
template <typename T>
class bound_function_helper_T : public T
{
public:
bound_function_helper_T(){ this->fp = 0;}
bool is_set() const
{
return this->fp != 0 || this->mfp.is_set();
}
template <unsigned long mem_size>
void safe_clone(stack_based_memory_block<mem_size>& buf)
{
// This is here just to validate the assumption that our block of memory we have made
// in bf_memory is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
COMPILE_TIME_ASSERT(sizeof(bound_function_helper_T) <= mem_size);
clone(buf.get());
}
void clone (void* ptr) const
{
bound_function_helper_T* p = new(ptr) bound_function_helper_T();
p->arg1 = this->arg1;
p->arg2 = this->arg2;
p->arg3 = this->arg3;
p->arg4 = this->arg4;
p->fp = this->fp;
p->mfp = this->mfp;
}
};
}
// ----------------------------------------------------------------------------------------
class bound_function_pointer
{
typedef bfp1_helpers::bound_function_helper_T<bfp1_helpers::bound_function_helper<void,int> > bf_null_type;
public:
// These typedefs are here for backwards compatibility with previous versions of
// dlib.
typedef bound_function_pointer kernel_1a;
typedef bound_function_pointer kernel_1a_c;
bound_function_pointer (
) { bf_null_type().safe_clone(bf_memory); }
bound_function_pointer (
const bound_function_pointer& item
) { item.bf()->clone(bf_memory.get()); }
~bound_function_pointer()
{ destroy_bf_memory(); }
bound_function_pointer& operator= (
const bound_function_pointer& item
) { bound_function_pointer(item).swap(*this); return *this; }
void clear (
) { bound_function_pointer().swap(*this); }
bool is_set (
) const
{
return bf()->is_set();
}
void swap (
bound_function_pointer& item
)
{
// make a temp copy of item
bound_function_pointer temp(item);
// destory the stuff in item
item.destroy_bf_memory();
// copy *this into item
bf()->clone(item.bf_memory.get());
// destory the stuff in this
destroy_bf_memory();
// copy temp into *this
temp.bf()->clone(bf_memory.get());
}
void operator() (
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(is_set() == true ,
"\tvoid bound_function_pointer::operator()"
<< "\n\tYou must call set() before you can use this function"
<< "\n\tthis: " << this
);
bf()->call();
}
private:
struct dummy{ void nonnull() {}};
typedef void (dummy::*safe_bool)();
public:
operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; }
bool operator!() const { return !is_set(); }
// -------------------------------------------
// set function object overloads
// -------------------------------------------
template <typename F>
void set (
F& function_object
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<F> > bf_helper_type;
bf_helper_type temp;
temp.fp = &function_object;
temp.safe_clone(bf_memory);
}
template <typename F, typename A1 >
void set (
F& function_object,
A1& arg1
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<F,A1> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.fp = &function_object;
temp.safe_clone(bf_memory);
}
template <typename F, typename A1, typename A2 >
void set (
F& function_object,
A1& arg1,
A2& arg2
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<F,A1,A2> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.fp = &function_object;
temp.safe_clone(bf_memory);
}
template <typename F, typename A1, typename A2, typename A3 >
void set (
F& function_object,
A1& arg1,
A2& arg2,
A3& arg3
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.fp = &function_object;
temp.safe_clone(bf_memory);
}
template <typename F, typename A1, typename A2, typename A3, typename A4>
void set (
F& function_object,
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
)
{
COMPILE_TIME_ASSERT(is_function<F>::value == false);
COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false);
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3,A4> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.arg4 = &arg4;
temp.fp = &function_object;
temp.safe_clone(bf_memory);
}
// -------------------------------------------
// set mfp overloads
// -------------------------------------------
template <typename T>
void set (
T& object,
void (T::*funct)()
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;
bf_helper_type temp;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
template <typename T >
void set (
const T& object,
void (T::*funct)()const
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;
bf_helper_type temp;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
// -------------------------------------------
template <typename T, typename T1, typename A1 >
void set (
T& object,
void (T::*funct)(T1),
A1& arg1
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
template <typename T, typename T1, typename A1 >
void set (
const T& object,
void (T::*funct)(T1)const,
A1& arg1
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
// ----------------
template <typename T, typename T1, typename A1,
typename T2, typename A2>
void set (
T& object,
void (T::*funct)(T1, T2),
A1& arg1,
A2& arg2
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
template <typename T, typename T1, typename A1,
typename T2, typename A2>
void set (
const T& object,
void (T::*funct)(T1, T2)const,
A1& arg1,
A2& arg2
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
// ----------------
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
void set (
T& object,
void (T::*funct)(T1, T2, T3),
A1& arg1,
A2& arg2,
A3& arg3
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
void set (
const T& object,
void (T::*funct)(T1, T2, T3)const,
A1& arg1,
A2& arg2,
A3& arg3
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
// ----------------
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
typename T4, typename A4>
void set (
T& object,
void (T::*funct)(T1, T2, T3, T4),
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.arg4 = &arg4;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
template <typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
typename T4, typename A4>
void set (
const T& object,
void (T::*funct)(T1, T2, T3, T4)const,
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.arg4 = &arg4;
temp.mfp.set(object,funct);
temp.safe_clone(bf_memory);
}
// -------------------------------------------
// set fp overloads
// -------------------------------------------
void set (
void (*funct)()
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;
bf_helper_type temp;
temp.fp = funct;
temp.safe_clone(bf_memory);
}
template <typename T1, typename A1>
void set (
void (*funct)(T1),
A1& arg1
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.fp = funct;
temp.safe_clone(bf_memory);
}
template <typename T1, typename A1,
typename T2, typename A2>
void set (
void (*funct)(T1, T2),
A1& arg1,
A2& arg2
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.fp = funct;
temp.safe_clone(bf_memory);
}
template <typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
void set (
void (*funct)(T1, T2, T3),
A1& arg1,
A2& arg2,
A3& arg3
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.fp = funct;
temp.safe_clone(bf_memory);
}
template <typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
typename T4, typename A4>
void set (
void (*funct)(T1, T2, T3, T4),
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
)
{
using namespace bfp1_helpers;
destroy_bf_memory();
typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;
bf_helper_type temp;
temp.arg1 = &arg1;
temp.arg2 = &arg2;
temp.arg3 = &arg3;
temp.arg4 = &arg4;
temp.fp = funct;
temp.safe_clone(bf_memory);
}
// -------------------------------------------
private:
stack_based_memory_block<sizeof(bf_null_type)> bf_memory;
void destroy_bf_memory (
)
{
// Honestly, this probably doesn't even do anything but I'm putting
// it here just for good measure.
bf()->~bound_function_helper_base_base();
}
bfp1_helpers::bound_function_helper_base_base* bf ()
{ return static_cast<bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); }
const bfp1_helpers::bound_function_helper_base_base* bf () const
{ return static_cast<const bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); }
};
// ----------------------------------------------------------------------------------------
inline void swap (
bound_function_pointer& a,
bound_function_pointer& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_

View File

@@ -0,0 +1,456 @@
// Copyright (C) 2008 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_
#ifdef DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_
namespace dlib
{
// ----------------------------------------------------------------------------------------
class bound_function_pointer
{
/*!
INITIAL VALUE
is_set() == false
WHAT THIS OBJECT REPRESENTS
This object represents a function with all its arguments bound to
specific objects. For example:
void test(int& var) { var = var+1; }
bound_function_pointer funct;
int a = 4;
funct.set(test,a); // bind the variable a to the first argument of the test() function
// at this point a == 4
funct();
// after funct() is called a == 5
!*/
public:
bound_function_pointer (
);
/*!
ensures
- #*this is properly initialized
!*/
bound_function_pointer(
const bound_function_pointer& item
);
/*!
ensures
- *this == item
!*/
~bound_function_pointer (
);
/*!
ensures
- any resources associated with *this have been released
!*/
bound_function_pointer& operator=(
const bound_function_pointer& item
);
/*!
ensures
- *this == item
!*/
void clear(
);
/*!
ensures
- #*this has its initial value
!*/
bool is_set (
) const;
/*!
ensures
- if (this->set() has been called) then
- returns true
- else
- returns false
!*/
operator some_undefined_pointer_type (
) const;
/*!
ensures
- if (is_set()) then
- returns a non 0 value
- else
- returns a 0 value
!*/
bool operator! (
) const;
/*!
ensures
- returns !is_set()
!*/
void operator () (
) const;
/*!
requires
- is_set() == true
ensures
- calls the bound function on the object(s) specified by the last
call to this->set()
throws
- any exception thrown by the function specified by
the previous call to this->set().
If any of these exceptions are thrown then the call to this
function will have no effect on *this.
!*/
void swap (
bound_function_pointer& item
);
/*!
ensures
- swaps *this and item
!*/
// ----------------------
template <typename F>
void set (
F& function_object
);
/*!
requires
- function_object() is a valid expression
ensures
- #is_set() == true
- calls to this->operator() will call function_object()
(This seems pointless but it is a useful base case)
!*/
template < typename T>
void set (
T& object,
void (T::*funct)()
);
/*!
requires
- funct == a valid member function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)()
!*/
template < typename T>
void set (
const T& object,
void (T::*funct)()const
);
/*!
requires
- funct == a valid bound function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)()
!*/
void set (
void (*funct)()
);
/*!
requires
- funct == a valid function pointer
ensures
- #is_set() == true
- calls to this->operator() will call funct()
!*/
// ----------------------
template <typename F, typename A1 >
void set (
F& function_object,
A1& arg1
);
/*!
requires
- function_object(arg1) is a valid expression
ensures
- #is_set() == true
- calls to this->operator() will call function_object(arg1)
!*/
template < typename T, typename T1, typename A1 >
void set (
T& object,
void (T::*funct)(T1),
A1& arg1
);
/*!
requires
- funct == a valid member function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1)
!*/
template < typename T, typename T1, typename A1 >
void set (
const T& object,
void (T::*funct)(T1)const,
A1& arg1
);
/*!
requires
- funct == a valid bound function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1)
!*/
template <typename T1, typename A1>
void set (
void (*funct)(T1),
A1& arg1
);
/*!
requires
- funct == a valid function pointer
ensures
- #is_set() == true
- calls to this->operator() will call funct(arg1)
!*/
// ----------------------
template <typename F, typename A1, typename A2 >
void set (
F& function_object,
A1& arg1,
A2& arg2
);
/*!
requires
- function_object(arg1,arg2) is a valid expression
ensures
- #is_set() == true
- calls to this->operator() will call function_object(arg1,arg2)
!*/
template < typename T, typename T1, typename A1,
typename T2, typename A2>
void set (
T& object,
void (T::*funct)(T1,T2),
A1& arg1,
A2& arg2
);
/*!
requires
- funct == a valid member function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1,arg2)
!*/
template < typename T, typename T1, typename A1,
typename T2, typename A2>
void set (
const T& object,
void (T::*funct)(T1,T2)const,
A1& arg1,
A2& arg2
);
/*!
requires
- funct == a valid bound function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1,arg2)
!*/
template <typename T1, typename A1,
typename T2, typename A2>
void set (
void (*funct)(T1,T2),
A1& arg1,
A2& arg2
);
/*!
requires
- funct == a valid function pointer
ensures
- #is_set() == true
- calls to this->operator() will call funct(arg1,arg2)
!*/
// ----------------------
template <typename F, typename A1, typename A2, typename A3 >
void set (
F& function_object,
A1& arg1,
A2& arg2,
A3& arg3
);
/*!
requires
- function_object(arg1,arg2,arg3) is a valid expression
ensures
- #is_set() == true
- calls to this->operator() will call function_object(arg1,arg2,arg3)
!*/
template < typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
void set (
T& object,
void (T::*funct)(T1,T2,T3),
A1& arg1,
A2& arg2,
A3& arg3
);
/*!
requires
- funct == a valid member function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1,arg2,arg3)
!*/
template < typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
void set (
const T& object,
void (T::*funct)(T1,T2,T3)const,
A1& arg1,
A2& arg2,
A3& arg3
);
/*!
requires
- funct == a valid bound function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1,arg2,arg3)
!*/
template <typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3>
void set (
void (*funct)(T1,T2,T3),
A1& arg1,
A2& arg2,
A3& arg3
);
/*!
requires
- funct == a valid function pointer
ensures
- #is_set() == true
- calls to this->operator() will call funct(arg1,arg2,arg3)
!*/
// ----------------------
template <typename F, typename A1, typename A2, typename A3, typename A4>
void set (
F& function_object,
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
);
/*!
requires
- function_object(arg1,arg2,arg3,arg4) is a valid expression
ensures
- #is_set() == true
- calls to this->operator() will call function_object(arg1,arg2,arg3,arg4)
!*/
template < typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
typename T4, typename A4>
void set (
T& object,
void (T::*funct)(T1,T2,T3,T4),
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
);
/*!
requires
- funct == a valid member function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1,arg2,arg3,arg4)
!*/
template < typename T, typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
typename T4, typename A4>
void set (
const T& object,
void (T::*funct)(T1,T2,T3,T4)const,
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
);
/*!
requires
- funct == a valid bound function pointer for class T
ensures
- #is_set() == true
- calls to this->operator() will call (object.*funct)(arg1,arg2,arg3,arg4)
!*/
template <typename T1, typename A1,
typename T2, typename A2,
typename T3, typename A3,
typename T4, typename A4>
void set (
void (*funct)(T1,T2,T3,T4),
A1& arg1,
A2& arg2,
A3& arg3,
A4& arg4
);
/*!
requires
- funct == a valid function pointer
ensures
- #is_set() == true
- calls to this->operator() will call funct(arg1,arg2,arg3,arg4)
!*/
};
// ----------------------------------------------------------------------------------------
inline void swap (
bound_function_pointer& a,
bound_function_pointer& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,17 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifdef DLIB_ALL_SOURCE_END
#include "dlib_basic_cpp_build_tutorial.txt"
#endif
#ifndef DLIB_BRIdGE_
#define DLIB_BRIdGE_
#include "bridge/bridge.h"
#endif // DLIB_BRIdGE_

View File

@@ -0,0 +1,669 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BRIDGe_Hh_
#define DLIB_BRIDGe_Hh_
#include <iostream>
#include <memory>
#include <string>
#include "bridge_abstract.h"
#include "../pipe.h"
#include "../threads.h"
#include "../serialize.h"
#include "../sockets.h"
#include "../sockstreambuf.h"
#include "../logger.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
struct connect_to_ip_and_port
{
connect_to_ip_and_port (
const std::string& ip_,
unsigned short port_
): ip(ip_), port(port_)
{
// make sure requires clause is not broken
DLIB_ASSERT(is_ip_address(ip) && port != 0,
"\t connect_to_ip_and_port()"
<< "\n\t Invalid inputs were given to this function"
<< "\n\t ip: " << ip
<< "\n\t port: " << port
<< "\n\t this: " << this
);
}
private:
friend class bridge;
const std::string ip;
const unsigned short port;
};
inline connect_to_ip_and_port connect_to (
const network_address& addr
)
{
// make sure requires clause is not broken
DLIB_ASSERT(addr.port != 0,
"\t connect_to_ip_and_port()"
<< "\n\t The TCP port to connect to can't be 0."
<< "\n\t addr.port: " << addr.port
);
if (is_ip_address(addr.host_address))
{
return connect_to_ip_and_port(addr.host_address, addr.port);
}
else
{
std::string ip;
if(hostname_to_ip(addr.host_address,ip))
throw socket_error(ERESOLVE,"unable to resolve '" + addr.host_address + "' in connect_to()");
return connect_to_ip_and_port(ip, addr.port);
}
}
struct listen_on_port
{
listen_on_port(
unsigned short port_
) : port(port_)
{
// make sure requires clause is not broken
DLIB_ASSERT( port != 0,
"\t listen_on_port()"
<< "\n\t Invalid inputs were given to this function"
<< "\n\t port: " << port
<< "\n\t this: " << this
);
}
private:
friend class bridge;
const unsigned short port;
};
template <typename pipe_type>
struct bridge_transmit_decoration
{
bridge_transmit_decoration (
pipe_type& p_
) : p(p_) {}
private:
friend class bridge;
pipe_type& p;
};
template <typename pipe_type>
bridge_transmit_decoration<pipe_type> transmit ( pipe_type& p) { return bridge_transmit_decoration<pipe_type>(p); }
template <typename pipe_type>
struct bridge_receive_decoration
{
bridge_receive_decoration (
pipe_type& p_
) : p(p_) {}
private:
friend class bridge;
pipe_type& p;
};
template <typename pipe_type>
bridge_receive_decoration<pipe_type> receive ( pipe_type& p) { return bridge_receive_decoration<pipe_type>(p); }
// ----------------------------------------------------------------------------------------
struct bridge_status
{
bridge_status() : is_connected(false), foreign_port(0){}
bool is_connected;
unsigned short foreign_port;
std::string foreign_ip;
};
inline void serialize ( const bridge_status& , std::ostream& )
{
throw serialization_error("It is illegal to serialize bridge_status objects.");
}
inline void deserialize ( bridge_status& , std::istream& )
{
throw serialization_error("It is illegal to serialize bridge_status objects.");
}
// ----------------------------------------------------------------------------------------
namespace impl_brns
{
class impl_bridge_base
{
public:
virtual ~impl_bridge_base() {}
virtual bridge_status get_bridge_status (
) const = 0;
};
template <
typename transmit_pipe_type,
typename receive_pipe_type
>
class impl_bridge : public impl_bridge_base, private noncopyable, private multithreaded_object
{
/*!
CONVENTION
- if (list) then
- this object is supposed to be listening on the list object for incoming
connections when not connected.
- else
- this object is supposed to be attempting to connect to ip:port when
not connected.
- get_bridge_status() == current_bs
!*/
public:
impl_bridge (
unsigned short listen_port,
transmit_pipe_type* transmit_pipe_,
receive_pipe_type* receive_pipe_
) :
s(m),
receive_thread_active(false),
transmit_thread_active(false),
port(0),
transmit_pipe(transmit_pipe_),
receive_pipe(receive_pipe_),
dlog("dlib.bridge"),
keepalive_code(0),
message_code(1)
{
int status = create_listener(list, listen_port);
if (status == PORTINUSE)
{
std::ostringstream sout;
sout << "Error, the port " << listen_port << " is already in use.";
throw socket_error(EPORT_IN_USE, sout.str());
}
else if (status == OTHER_ERROR)
{
throw socket_error("Unable to create listening socket for an unknown reason.");
}
register_thread(*this, &impl_bridge::transmit_thread);
register_thread(*this, &impl_bridge::receive_thread);
register_thread(*this, &impl_bridge::connect_thread);
start();
}
impl_bridge (
const std::string ip_,
unsigned short port_,
transmit_pipe_type* transmit_pipe_,
receive_pipe_type* receive_pipe_
) :
s(m),
receive_thread_active(false),
transmit_thread_active(false),
port(port_),
ip(ip_),
transmit_pipe(transmit_pipe_),
receive_pipe(receive_pipe_),
dlog("dlib.bridge"),
keepalive_code(0),
message_code(1)
{
register_thread(*this, &impl_bridge::transmit_thread);
register_thread(*this, &impl_bridge::receive_thread);
register_thread(*this, &impl_bridge::connect_thread);
start();
}
~impl_bridge()
{
// tell the threads to terminate
stop();
// save current pipe enabled status so we can restore it to however
// it was before this destructor ran.
bool transmit_enabled = true;
bool receive_enabled = true;
// make any calls blocked on a pipe return immediately.
if (transmit_pipe)
{
transmit_enabled = transmit_pipe->is_dequeue_enabled();
transmit_pipe->disable_dequeue();
}
if (receive_pipe)
{
receive_enabled = receive_pipe->is_enqueue_enabled();
receive_pipe->disable_enqueue();
}
{
auto_mutex lock(m);
s.broadcast();
// Shutdown the connection if we have one. This will cause
// all blocked I/O calls to return an error.
if (con)
con->shutdown();
}
// wait for all the threads to terminate.
wait();
if (transmit_pipe && transmit_enabled)
transmit_pipe->enable_dequeue();
if (receive_pipe && receive_enabled)
receive_pipe->enable_enqueue();
}
bridge_status get_bridge_status (
) const
{
auto_mutex lock(current_bs_mutex);
return current_bs;
}
private:
template <typename pipe_type>
typename enable_if<is_convertible<bridge_status, typename pipe_type::type> >::type enqueue_bridge_status (
pipe_type* p,
const bridge_status& status
)
{
if (p)
{
typename pipe_type::type temp(status);
p->enqueue(temp);
}
}
template <typename pipe_type>
typename disable_if<is_convertible<bridge_status, typename pipe_type::type> >::type enqueue_bridge_status (
pipe_type* ,
const bridge_status&
)
{
}
void connect_thread (
)
{
while (!should_stop())
{
auto_mutex lock(m);
int status = OTHER_ERROR;
if (list)
{
do
{
status = list->accept(con, 1000);
} while (status == TIMEOUT && !should_stop());
}
else
{
status = create_connection(con, port, ip);
}
if (should_stop())
break;
if (status != 0)
{
// The last connection attempt failed. So pause for a little bit before making another attempt.
s.wait_or_timeout(2000);
continue;
}
dlog << LINFO << "Established new connection to " << con->get_foreign_ip() << ":" << con->get_foreign_port() << ".";
bridge_status temp_bs;
{ auto_mutex lock(current_bs_mutex);
current_bs.is_connected = true;
current_bs.foreign_port = con->get_foreign_port();
current_bs.foreign_ip = con->get_foreign_ip();
temp_bs = current_bs;
}
enqueue_bridge_status(receive_pipe, temp_bs);
receive_thread_active = true;
transmit_thread_active = true;
s.broadcast();
// Wait for the transmit and receive threads to end before we continue.
// This way we don't invalidate the con pointer while it is in use.
while (receive_thread_active || transmit_thread_active)
s.wait();
dlog << LINFO << "Closed connection to " << con->get_foreign_ip() << ":" << con->get_foreign_port() << ".";
{ auto_mutex lock(current_bs_mutex);
current_bs.is_connected = false;
current_bs.foreign_port = con->get_foreign_port();
current_bs.foreign_ip = con->get_foreign_ip();
temp_bs = current_bs;
}
enqueue_bridge_status(receive_pipe, temp_bs);
}
}
void receive_thread (
)
{
while (true)
{
// wait until we have a connection
{ auto_mutex lock(m);
while (!receive_thread_active && !should_stop())
{
s.wait();
}
if (should_stop())
break;
}
try
{
if (receive_pipe)
{
sockstreambuf buf(con);
std::istream in(&buf);
typename receive_pipe_type::type item;
// This isn't necessary but doing it avoids a warning about
// item being uninitialized sometimes.
assign_zero_if_built_in_scalar_type(item);
while (in.peek() != EOF)
{
unsigned char code;
in.read((char*)&code, sizeof(code));
if (code == message_code)
{
deserialize(item, in);
receive_pipe->enqueue(item);
}
}
}
else
{
// Since we don't have a receive pipe to put messages into we will
// just read the bytes from the connection and ignore them.
char buf[1000];
while (con->read(buf, sizeof(buf)) > 0) ;
}
}
catch (std::bad_alloc& )
{
dlog << LERROR << "std::bad_alloc thrown while deserializing message from "
<< con->get_foreign_ip() << ":" << con->get_foreign_port();
}
catch (dlib::serialization_error& e)
{
dlog << LERROR << "dlib::serialization_error thrown while deserializing message from "
<< con->get_foreign_ip() << ":" << con->get_foreign_port()
<< ".\nThe exception error message is: \n" << e.what();
}
catch (std::exception& e)
{
dlog << LERROR << "std::exception thrown while deserializing message from "
<< con->get_foreign_ip() << ":" << con->get_foreign_port()
<< ".\nThe exception error message is: \n" << e.what();
}
con->shutdown();
auto_mutex lock(m);
receive_thread_active = false;
s.broadcast();
}
auto_mutex lock(m);
receive_thread_active = false;
s.broadcast();
}
void transmit_thread (
)
{
while (true)
{
// wait until we have a connection
{ auto_mutex lock(m);
while (!transmit_thread_active && !should_stop())
{
s.wait();
}
if (should_stop())
break;
}
try
{
sockstreambuf buf(con);
std::ostream out(&buf);
typename transmit_pipe_type::type item;
// This isn't necessary but doing it avoids a warning about
// item being uninitialized sometimes.
assign_zero_if_built_in_scalar_type(item);
while (out)
{
bool dequeue_timed_out = false;
if (transmit_pipe )
{
if (transmit_pipe->dequeue_or_timeout(item,1000))
{
out.write((char*)&message_code, sizeof(message_code));
serialize(item, out);
if (transmit_pipe->size() == 0)
out.flush();
continue;
}
dequeue_timed_out = (transmit_pipe->is_enabled() && transmit_pipe->is_dequeue_enabled());
}
// Pause for about a second. Note that we use a wait_or_timeout() call rather
// than sleep() here because we want to wake up immediately if this object is
// being destructed rather than hang for a second.
if (!dequeue_timed_out)
{
auto_mutex lock(m);
if (should_stop())
break;
s.wait_or_timeout(1000);
}
// Just send the keepalive byte periodically so we can
// tell if the connection is alive.
out.write((char*)&keepalive_code, sizeof(keepalive_code));
out.flush();
}
}
catch (std::bad_alloc& )
{
dlog << LERROR << "std::bad_alloc thrown while serializing message to "
<< con->get_foreign_ip() << ":" << con->get_foreign_port();
}
catch (dlib::serialization_error& e)
{
dlog << LERROR << "dlib::serialization_error thrown while serializing message to "
<< con->get_foreign_ip() << ":" << con->get_foreign_port()
<< ".\nThe exception error message is: \n" << e.what();
}
catch (std::exception& e)
{
dlog << LERROR << "std::exception thrown while serializing message to "
<< con->get_foreign_ip() << ":" << con->get_foreign_port()
<< ".\nThe exception error message is: \n" << e.what();
}
con->shutdown();
auto_mutex lock(m);
transmit_thread_active = false;
s.broadcast();
}
auto_mutex lock(m);
transmit_thread_active = false;
s.broadcast();
}
mutex m;
signaler s;
bool receive_thread_active;
bool transmit_thread_active;
std::unique_ptr<connection> con;
std::unique_ptr<listener> list;
const unsigned short port;
const std::string ip;
transmit_pipe_type* const transmit_pipe;
receive_pipe_type* const receive_pipe;
logger dlog;
const unsigned char keepalive_code;
const unsigned char message_code;
mutex current_bs_mutex;
bridge_status current_bs;
};
}
// ----------------------------------------------------------------------------------------
class bridge : noncopyable
{
public:
bridge () {}
template < typename T, typename U, typename V >
bridge (
T network_parameters,
U pipe1,
V pipe2
) { reconfigure(network_parameters,pipe1,pipe2); }
template < typename T, typename U>
bridge (
T network_parameters,
U pipe
) { reconfigure(network_parameters,pipe); }
void clear (
)
{
pimpl.reset();
}
template < typename T, typename R >
void reconfigure (
listen_on_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe,
bridge_receive_decoration<R> receive_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }
template < typename T, typename R >
void reconfigure (
listen_on_port network_parameters,
bridge_receive_decoration<R> receive_pipe,
bridge_transmit_decoration<T> transmit_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }
template < typename T >
void reconfigure (
listen_on_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,T>(network_parameters.port, &transmit_pipe.p, 0)); }
template < typename R >
void reconfigure (
listen_on_port network_parameters,
bridge_receive_decoration<R> receive_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<R,R>(network_parameters.port, 0, &receive_pipe.p)); }
template < typename T, typename R >
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe,
bridge_receive_decoration<R> receive_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }
template < typename T, typename R >
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_receive_decoration<R> receive_pipe,
bridge_transmit_decoration<T> transmit_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }
template < typename R >
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_receive_decoration<R> receive_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<R,R>(network_parameters.ip, network_parameters.port, 0, &receive_pipe.p)); }
template < typename T >
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe
) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,T>(network_parameters.ip, network_parameters.port, &transmit_pipe.p, 0)); }
bridge_status get_bridge_status (
) const
{
if (pimpl)
return pimpl->get_bridge_status();
else
return bridge_status();
}
private:
std::unique_ptr<impl_brns::impl_bridge_base> pimpl;
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BRIDGe_Hh_

View File

@@ -0,0 +1,347 @@
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BRIDGe_ABSTRACT_
#ifdef DLIB_BRIDGe_ABSTRACT_
#include <string>
#include "../pipe/pipe_kernel_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
struct connect_to_ip_and_port
{
connect_to_ip_and_port (
const std::string& ip,
unsigned short port
);
/*!
requires
- is_ip_address(ip) == true
- port != 0
ensures
- this object will represent a request to make a TCP connection
to the given IP address and port number.
!*/
};
connect_to_ip_and_port connect_to (
const network_address& addr
);
/*!
requires
- addr.port != 0
ensures
- converts the given network_address object into a connect_to_ip_and_port
object.
!*/
struct listen_on_port
{
listen_on_port(
unsigned short port
);
/*!
requires
- port != 0
ensures
- this object will represent a request to listen on the given
port number for incoming TCP connections.
!*/
};
template <
typename pipe_type
>
bridge_transmit_decoration<pipe_type> transmit (
pipe_type& p
);
/*!
requires
- pipe_type is some kind of dlib::pipe object
- the objects in the pipe must be serializable
ensures
- Adds a type decoration to the given pipe, marking it as a transmit pipe, and
then returns it.
!*/
template <
typename pipe_type
>
bridge_receive_decoration<pipe_type> receive (
pipe_type& p
);
/*!
requires
- pipe_type is some kind of dlib::pipe object
- the objects in the pipe must be serializable
ensures
- Adds a type decoration to the given pipe, marking it as a receive pipe, and
then returns it.
!*/
// ----------------------------------------------------------------------------------------
struct bridge_status
{
/*!
WHAT THIS OBJECT REPRESENTS
This simple struct represents the state of a bridge object. A
bridge is either connected or not. If it is connected then it
is connected to a foreign host with an IP address and port number
as indicated by this object.
!*/
bridge_status(
);
/*!
ensures
- #is_connected == false
- #foreign_port == 0
- #foreign_ip == ""
!*/
bool is_connected;
unsigned short foreign_port;
std::string foreign_ip;
};
// ----------------------------------------------------------------------------------------
class bridge : noncopyable
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a tool for bridging a dlib::pipe object between
two network connected applications.
Note also that this object contains a dlib::logger object
which will log various events taking place inside a bridge.
If you want to see these log messages then enable the logger
named "dlib.bridge".
BRIDGE PROTOCOL DETAILS
The bridge object creates a single TCP connection between
two applications. Whenever it sends an object from a pipe
over a TCP connection it sends a byte with the value 1 followed
immediately by the serialized copy of the object from the pipe.
The serialization is performed by calling the global serialize()
function.
Additionally, a bridge object will periodically send bytes with
a value of 0 to ensure the TCP connection remains alive. These
are just read and ignored.
!*/
public:
bridge (
);
/*!
ensures
- this object is properly initialized
- #get_bridge_status().is_connected == false
!*/
template <typename T, typename U, typename V>
bridge (
T network_parameters,
U pipe1,
V pipe2
);
/*!
requires
- T is of type connect_to_ip_and_port or listen_on_port
- U and V are of type bridge_transmit_decoration or bridge_receive_decoration,
however, U and V must be of different types (i.e. one is a receive type and
another a transmit type).
ensures
- this object is properly initialized
- performs: reconfigure(network_parameters, pipe1, pipe2)
(i.e. using this constructor is identical to using the default constructor
and then calling reconfigure())
!*/
template <typename T, typename U>
bridge (
T network_parameters,
U pipe
);
/*!
requires
- T is of type connect_to_ip_and_port or listen_on_port
- U is of type bridge_transmit_decoration or bridge_receive_decoration.
ensures
- this object is properly initialized
- performs: reconfigure(network_parameters, pipe)
(i.e. using this constructor is identical to using the default constructor
and then calling reconfigure())
!*/
~bridge (
);
/*!
ensures
- blocks until all resources associated with this object have been destroyed.
!*/
void clear (
);
/*!
ensures
- returns this object to its default constructed state. That is, it will
be inactive, neither maintaining a connection nor attempting to acquire one.
- Any active connections or listening sockets will be closed.
!*/
bridge_status get_bridge_status (
) const;
/*!
ensures
- returns the current status of this bridge object. In particular, returns
an object BS such that:
- BS.is_connected == true if and only if the bridge has an active TCP
connection to another computer.
- if (BS.is_connected) then
- BS.foreign_ip == the IP address of the remote host we are connected to.
- BS.foreign_port == the port number on the remote host we are connected to.
- else if (the bridge has previously been connected to a remote host but hasn't been
reconfigured or cleared since) then
- BS.foreign_ip == the IP address of the remote host we were connected to.
- BS.foreign_port == the port number on the remote host we were connected to.
- else
- BS.foreign_ip == ""
- BS.foreign_port == 0
!*/
template < typename T, typename R >
void reconfigure (
listen_on_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe,
bridge_receive_decoration<R> receive_pipe
);
/*!
ensures
- This object will begin listening on the port specified by network_parameters
for incoming TCP connections. Any previous bridge state is cleared out.
- Onces a connection is established we will:
- Stop accepting new connections.
- Begin dequeuing objects from the transmit pipe and serializing them over
the TCP connection.
- Begin deserializing objects from the TCP connection and enqueueing them
onto the receive pipe.
- if (the current TCP connection is lost) then
- This object goes back to listening for a new connection.
- if (the receive pipe can contain bridge_status objects) then
- Whenever the bridge's status changes the updated bridge_status will be
enqueued onto the receive pipe unless the change was a TCP disconnect
resulting from a user calling reconfigure(), clear(), or destructing this
bridge. The status contents are defined by get_bridge_status().
throws
- socket_error
This exception is thrown if we are unable to open the listening socket.
!*/
template < typename T, typename R >
void reconfigure (
listen_on_port network_parameters,
bridge_receive_decoration<R> receive_pipe,
bridge_transmit_decoration<T> transmit_pipe
);
/*!
ensures
- performs reconfigure(network_parameters, transmit_pipe, receive_pipe)
!*/
template < typename T >
void reconfigure (
listen_on_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe
);
/*!
ensures
- This function is identical to the above two reconfigure() functions
except that there is no receive pipe.
!*/
template < typename R >
void reconfigure (
listen_on_port network_parameters,
bridge_receive_decoration<R> receive_pipe
);
/*!
ensures
- This function is identical to the above three reconfigure() functions
except that there is no transmit pipe.
!*/
template <typename T, typename R>
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe,
bridge_receive_decoration<R> receive_pipe
);
/*!
ensures
- This object will begin making TCP connection attempts to the IP address and port
specified by network_parameters. Any previous bridge state is cleared out.
- Onces a connection is established we will:
- Stop attempting new connections.
- Begin dequeuing objects from the transmit pipe and serializing them over
the TCP connection.
- Begin deserializing objects from the TCP connection and enqueueing them
onto the receive pipe.
- if (the current TCP connection is lost) then
- This object goes back to attempting to make a TCP connection with the
IP address and port specified by network_parameters.
- if (the receive pipe can contain bridge_status objects) then
- Whenever the bridge's status changes the updated bridge_status will be
enqueued onto the receive pipe unless the change was a TCP disconnect
resulting from a user calling reconfigure(), clear(), or destructing this
bridge. The status contents are defined by get_bridge_status().
!*/
template <typename T, typename R>
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_receive_decoration<R> receive_pipe,
bridge_transmit_decoration<T> transmit_pipe
);
/*!
ensures
- performs reconfigure(network_parameters, transmit_pipe, receive_pipe)
!*/
template <typename T>
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_transmit_decoration<T> transmit_pipe
);
/*!
ensures
- This function is identical to the above two reconfigure() functions
except that there is no receive pipe.
!*/
template <typename R>
void reconfigure (
connect_to_ip_and_port network_parameters,
bridge_receive_decoration<R> receive_pipe
);
/*!
ensures
- This function is identical to the above three reconfigure() functions
except that there is no transmit pipe.
!*/
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BRIDGe_ABSTRACT_

View File

@@ -0,0 +1,12 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BSPh_
#define DLIB_BSPh_
#include "bsp/bsp.h"
#endif // DLIB_BSPh_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,912 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BsP_ABSTRACT_Hh_
#ifdef DLIB_BsP_ABSTRACT_Hh_
#include "../noncopyable.h"
#include "../sockets/sockets_extensions_abstract.h"
#include <vector>
namespace dlib
{
// ----------------------------------------------------------------------------------------
class bsp_context : noncopyable
{
/*!
WHAT THIS OBJECT REPRESENTS
This is a tool used to implement algorithms using the Bulk Synchronous
Parallel (BSP) computing model. A BSP algorithm is composed of a number of
processing nodes, each executing in parallel. The general flow of
execution in each processing node is the following:
1. Do work locally on some data.
2. Send some messages to other nodes.
3. Receive messages from other nodes.
4. Go to step 1 or terminate if complete.
To do this, each processing node needs an API used to send and receive
messages. This API is implemented by the bsp_connect object which provides
these services to a BSP node.
Note that BSP processing nodes are spawned using the bsp_connect() and
bsp_listen() routines defined at the bottom of this file. For example, to
start a BSP algorithm consisting of N processing nodes, you would make N-1
calls to bsp_listen() and one call to bsp_connect(). The call to
bsp_connect() then initiates the computation on all nodes.
Finally, note that there is no explicit barrier synchronization function
you call at the end of step 3. Instead, you can simply call a method such
as try_receive() until it returns false. That is, the bsp_context's
receive methods incorporate a barrier synchronization that happens once all
the BSP nodes are blocked on receive calls and there are no more messages
in flight.
THREAD SAFETY
This object is not thread-safe. In particular, you should only ever have
one thread that works with an instance of this object. This means that,
for example, you should not spawn sub-threads from within a BSP processing
node and have them invoke methods on this object. Instead, you should only
invoke this object's methods from within the BSP processing node's main
thread (i.e. the thread that executes the user supplied function funct()).
!*/
public:
template <typename T>
void send(
const T& item,
unsigned long target_node_id
);
/*!
requires
- item is serializable
- target_node_id < number_of_nodes()
- target_node_id != node_id()
ensures
- sends a copy of item to the node with the given id.
throws
- dlib::socket_error:
This exception is thrown if there is an error which prevents us from
delivering the message to the given node. One way this might happen is
if the target node has already terminated its execution or has lost
network connectivity.
!*/
template <typename T>
void broadcast (
const T& item
);
/*!
ensures
- item is serializable
- sends a copy of item to all other processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents us from
delivering a message to one of the other nodes. This might happen, for
example, if one of the nodes has terminated its execution or has lost
network connectivity.
!*/
unsigned long node_id (
) const;
/*!
ensures
- Returns the id of the current processing node. That is,
returns a number N such that:
- N < number_of_nodes()
- N == the node id of the processing node that called node_id(). This
is a number that uniquely identifies the processing node.
!*/
unsigned long number_of_nodes (
) const;
/*!
ensures
- returns the number of processing nodes participating in the BSP
computation.
!*/
template <typename T>
bool try_receive (
T& item
);
/*!
requires
- item is serializable
ensures
- if (this function returns true) then
- #item == the next message which was sent to the calling processing
node.
- else
- The following must have been true for this function to return false:
- All other nodes were blocked on calls to receive(),
try_receive(), or have terminated.
- There were not any messages in flight between any nodes.
- That is, if all the nodes had continued to block on receive
methods then they all would have blocked forever. Therefore,
this function only returns false once there are no more messages
to process by any node and there is no possibility of more being
generated until control is returned to the callers of receive
methods.
- When one BSP node's receive method returns because of the above
conditions then all of them will also return. That is, it is NOT the
case that just a subset of BSP nodes unblock. Moreover, they all
unblock at the same time.
throws
- dlib::socket_error:
This exception is thrown if some error occurs which prevents us from
communicating with other processing nodes.
- dlib::serialization_error or any exception thrown by the global
deserialize(T) routine:
This is thrown if there is a problem in deserialize(). This might
happen if the message sent doesn't match the type T expected by
try_receive().
!*/
template <typename T>
void receive (
T& item
);
/*!
requires
- item is serializable
ensures
- #item == the next message which was sent to the calling processing
node.
- This function is just a wrapper around try_receive() that throws an
exception if a message is not received (i.e. if try_receive() returns
false).
throws
- dlib::socket_error:
This exception is thrown if some error occurs which prevents us from
communicating with other processing nodes or if there was not a message
to receive.
- dlib::serialization_error or any exception thrown by the global
deserialize(T) routine:
This is thrown if there is a problem in deserialize(). This might
happen if the message sent doesn't match the type T expected by
receive().
!*/
template <typename T>
bool try_receive (
T& item,
unsigned long& sending_node_id
);
/*!
requires
- item is serializable
ensures
- if (this function returns true) then
- #item == the next message which was sent to the calling processing
node.
- #sending_node_id == the node id of the node that sent this message.
- #sending_node_id < number_of_nodes()
- else
- The following must have been true for this function to return false:
- All other nodes were blocked on calls to receive(),
try_receive(), or have terminated.
- There were not any messages in flight between any nodes.
- That is, if all the nodes had continued to block on receive
methods then they all would have blocked forever. Therefore,
this function only returns false once there are no more messages
to process by any node and there is no possibility of more being
generated until control is returned to the callers of receive
methods.
- When one BSP node's receive method returns because of the above
conditions then all of them will also return. That is, it is NOT the
case that just a subset of BSP nodes unblock. Moreover, they all
unblock at the same time.
throws
- dlib::socket_error:
This exception is thrown if some error occurs which prevents us from
communicating with other processing nodes.
- dlib::serialization_error or any exception thrown by the global
deserialize(T) routine:
This is thrown if there is a problem in deserialize(). This might
happen if the message sent doesn't match the type T expected by
try_receive().
!*/
template <typename T>
void receive (
T& item,
unsigned long& sending_node_id
);
/*!
requires
- item is serializable
ensures
- #item == the next message which was sent to the calling processing node.
- #sending_node_id == the node id of the node that sent this message.
- #sending_node_id < number_of_nodes()
- This function is just a wrapper around try_receive() that throws an
exception if a message is not received (i.e. if try_receive() returns
false).
throws
- dlib::socket_error:
This exception is thrown if some error occurs which prevents us from
communicating with other processing nodes or if there was not a message
to receive.
- dlib::serialization_error or any exception thrown by the global
deserialize(T) routine:
This is thrown if there is a problem in deserialize(). This might
happen if the message sent doesn't match the type T expected by
receive().
!*/
void receive (
);
/*!
ensures
- Waits for the following to all be true:
- All other nodes were blocked on calls to receive(), try_receive(), or
have terminated.
- There are not any messages in flight between any nodes.
- That is, if all the nodes had continued to block on receive methods
then they all would have blocked forever. Therefore, this function
only returns once there are no more messages to process by any node
and there is no possibility of more being generated until control is
returned to the callers of receive methods.
- When one BSP node's receive method returns because of the above
conditions then all of them will also return. That is, it is NOT the
case that just a subset of BSP nodes unblock. Moreover, they all unblock
at the same time.
throws
- dlib::socket_error:
This exception is thrown if some error occurs which prevents us from
communicating with other processing nodes or if a message is received
before this function would otherwise return.
!*/
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename funct_type
>
void bsp_connect (
const std::vector<network_address>& hosts,
funct_type funct
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
- The processing node with a node ID of 0 will run locally on the machine
calling bsp_connect(). In particular, this node will execute funct(CONTEXT),
which is expected to carry out this node's portion of the BSP computation.
- The other processing nodes are executed on the hosts indicated by the input
argument. In particular, this function interprets hosts as a list addresses
identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
routines.
- This call to bsp_connect() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1
>
void bsp_connect (
const std::vector<network_address>& hosts,
funct_type funct,
ARG1 arg1
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
- The processing node with a node ID of 0 will run locally on the machine
calling bsp_connect(). In particular, this node will execute funct(CONTEXT,arg1),
which is expected to carry out this node's portion of the BSP computation.
- The other processing nodes are executed on the hosts indicated by the input
argument. In particular, this function interprets hosts as a list addresses
identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
routines.
- This call to bsp_connect() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1,
typename ARG2
>
void bsp_connect (
const std::vector<network_address>& hosts,
funct_type funct,
ARG1 arg1,
ARG2 arg2
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
- The processing node with a node ID of 0 will run locally on the machine
calling bsp_connect(). In particular, this node will execute funct(CONTEXT,arg1,arg2),
which is expected to carry out this node's portion of the BSP computation.
- The other processing nodes are executed on the hosts indicated by the input
argument. In particular, this function interprets hosts as a list addresses
identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
routines.
- This call to bsp_connect() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1,
typename ARG2,
typename ARG3
>
void bsp_connect (
const std::vector<network_address>& hosts,
funct_type funct,
ARG1 arg1,
ARG2 arg2,
ARG3 arg3
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2,arg3) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
- The processing node with a node ID of 0 will run locally on the machine
calling bsp_connect(). In particular, this node will execute funct(CONTEXT,arg1,arg2,arg3),
which is expected to carry out this node's portion of the BSP computation.
- The other processing nodes are executed on the hosts indicated by the input
argument. In particular, this function interprets hosts as a list addresses
identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
routines.
- This call to bsp_connect() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1,
typename ARG2,
typename ARG3,
typename ARG4
>
void bsp_connect (
const std::vector<network_address>& hosts,
funct_type funct,
ARG1 arg1,
ARG2 arg2,
ARG3 arg3,
ARG4 arg4
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function spawns a BSP job consisting of hosts.size()+1 processing nodes.
- The processing node with a node ID of 0 will run locally on the machine
calling bsp_connect(). In particular, this node will execute funct(CONTEXT,arg1,arg2,arg3,arg4),
which is expected to carry out this node's portion of the BSP computation.
- The other processing nodes are executed on the hosts indicated by the input
argument. In particular, this function interprets hosts as a list addresses
identifying machines running the bsp_listen() or bsp_listen_dynamic_port()
routines.
- This call to bsp_connect() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename funct_type
>
void bsp_listen (
unsigned short listening_port,
funct_type funct
);
/*!
requires
- listening_port != 0
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT) will be executed and it will
then be able to participate in the BSP computation as one of the processing
nodes.
- This function will listen on TCP port listening_port for a connection from
bsp_connect(). Once the connection is established, it will close the
listening port so it is free for use by other applications. The connection
and BSP computation will continue uninterrupted.
- This call to bsp_listen() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1
>
void bsp_listen (
unsigned short listening_port,
funct_type funct,
ARG1 arg1
);
/*!
requires
- listening_port != 0
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1) will be executed and it will
then be able to participate in the BSP computation as one of the processing
nodes.
- This function will listen on TCP port listening_port for a connection from
bsp_connect(). Once the connection is established, it will close the
listening port so it is free for use by other applications. The connection
and BSP computation will continue uninterrupted.
- This call to bsp_listen() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1,
typename ARG2
>
void bsp_listen (
unsigned short listening_port,
funct_type funct,
ARG1 arg1,
ARG2 arg2
);
/*!
requires
- listening_port != 0
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1,arg2) will be executed and
it will then be able to participate in the BSP computation as one of the
processing nodes.
- This function will listen on TCP port listening_port for a connection from
bsp_connect(). Once the connection is established, it will close the
listening port so it is free for use by other applications. The connection
and BSP computation will continue uninterrupted.
- This call to bsp_listen() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1,
typename ARG2,
typename ARG3
>
void bsp_listen (
unsigned short listening_port,
funct_type funct,
ARG1 arg1,
ARG2 arg2,
ARG3 arg3
);
/*!
requires
- listening_port != 0
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2,arg3) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1,arg2,arg3) will be
executed and it will then be able to participate in the BSP computation as
one of the processing nodes.
- This function will listen on TCP port listening_port for a connection from
bsp_connect(). Once the connection is established, it will close the
listening port so it is free for use by other applications. The connection
and BSP computation will continue uninterrupted.
- This call to bsp_listen() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename funct_type,
typename ARG1,
typename ARG2,
typename ARG3,
typename ARG4
>
void bsp_listen (
unsigned short listening_port,
funct_type funct,
ARG1 arg1,
ARG2 arg2,
ARG3 arg3,
ARG4 arg4
);
/*!
requires
- listening_port != 0
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression
(i.e. funct must be a function or function object)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1,arg2,arg3,arg4) will be
executed and it will then be able to participate in the BSP computation as
one of the processing nodes.
- This function will listen on TCP port listening_port for a connection from
bsp_connect(). Once the connection is established, it will close the
listening port so it is free for use by other applications. The connection
and BSP computation will continue uninterrupted.
- This call to bsp_listen() blocks until the BSP computation has completed on
all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename port_notify_function_type,
typename funct_type
>
void bsp_listen_dynamic_port (
unsigned short listening_port,
port_notify_function_type port_notify_function,
funct_type funct
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT) must be a valid expression
(i.e. funct must be a function or function object)
- port_notify_function((unsigned short) 1234) must be a valid expression
(i.e. port_notify_function() must be a function or function object taking an
unsigned short)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT) will be executed and it will
then be able to participate in the BSP computation as one of the processing
nodes.
- if (listening_port != 0) then
- This function will listen on TCP port listening_port for a connection
from bsp_connect().
- else
- An available TCP port number is automatically selected and this function
will listen on it for a connection from bsp_connect().
- Once a listening port is opened, port_notify_function() is called with the
port number used. This provides a mechanism to find out what listening port
has been used if it is automatically selected. It also allows you to find
out when the routine has begun listening for an incoming connection from
bsp_connect().
- Once a connection is established, we will close the listening port so it is
free for use by other applications. The connection and BSP computation will
continue uninterrupted.
- This call to bsp_listen_dynamic_port() blocks until the BSP computation has
completed on all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename port_notify_function_type,
typename funct_type,
typename ARG1
>
void bsp_listen_dynamic_port (
unsigned short listening_port,
port_notify_function_type port_notify_function,
funct_type funct,
ARG1 arg1
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1) must be a valid expression
(i.e. funct must be a function or function object)
- port_notify_function((unsigned short) 1234) must be a valid expression
(i.e. port_notify_function() must be a function or function object taking an
unsigned short)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1) will be executed and it
will then be able to participate in the BSP computation as one of the
processing nodes.
- if (listening_port != 0) then
- This function will listen on TCP port listening_port for a connection
from bsp_connect().
- else
- An available TCP port number is automatically selected and this function
will listen on it for a connection from bsp_connect().
- Once a listening port is opened, port_notify_function() is called with the
port number used. This provides a mechanism to find out what listening port
has been used if it is automatically selected. It also allows you to find
out when the routine has begun listening for an incoming connection from
bsp_connect().
- Once a connection is established, we will close the listening port so it is
free for use by other applications. The connection and BSP computation will
continue uninterrupted.
- This call to bsp_listen_dynamic_port() blocks until the BSP computation has
completed on all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename port_notify_function_type,
typename funct_type,
typename ARG1,
typename ARG2
>
void bsp_listen_dynamic_port (
unsigned short listening_port,
port_notify_function_type port_notify_function,
funct_type funct,
ARG1 arg1,
ARG2 arg2
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2) must be a valid expression
(i.e. funct must be a function or function object)
- port_notify_function((unsigned short) 1234) must be a valid expression
(i.e. port_notify_function() must be a function or function object taking an
unsigned short)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1,arg2) will be executed and
it will then be able to participate in the BSP computation as one of the
processing nodes.
- if (listening_port != 0) then
- This function will listen on TCP port listening_port for a connection
from bsp_connect().
- else
- An available TCP port number is automatically selected and this function
will listen on it for a connection from bsp_connect().
- Once a listening port is opened, port_notify_function() is called with the
port number used. This provides a mechanism to find out what listening port
has been used if it is automatically selected. It also allows you to find
out when the routine has begun listening for an incoming connection from
bsp_connect().
- Once a connection is established, we will close the listening port so it is
free for use by other applications. The connection and BSP computation will
continue uninterrupted.
- This call to bsp_listen_dynamic_port() blocks until the BSP computation has
completed on all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename port_notify_function_type,
typename funct_type,
typename ARG1,
typename ARG2,
typename ARG3
>
void bsp_listen_dynamic_port (
unsigned short listening_port,
port_notify_function_type port_notify_function,
funct_type funct,
ARG1 arg1,
ARG2 arg2,
ARG3 arg3
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2,arg3) must be a valid expression
(i.e. funct must be a function or function object)
- port_notify_function((unsigned short) 1234) must be a valid expression
(i.e. port_notify_function() must be a function or function object taking an
unsigned short)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1,arg2,arg3) will be
executed and it will then be able to participate in the BSP computation as
one of the processing nodes.
- if (listening_port != 0) then
- This function will listen on TCP port listening_port for a connection
from bsp_connect().
- else
- An available TCP port number is automatically selected and this function
will listen on it for a connection from bsp_connect().
- Once a listening port is opened, port_notify_function() is called with the
port number used. This provides a mechanism to find out what listening port
has been used if it is automatically selected. It also allows you to find
out when the routine has begun listening for an incoming connection from
bsp_connect().
- Once a connection is established, we will close the listening port so it is
free for use by other applications. The connection and BSP computation will
continue uninterrupted.
- This call to bsp_listen_dynamic_port() blocks until the BSP computation has
completed on all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
template <
typename port_notify_function_type,
typename funct_type,
typename ARG1,
typename ARG2,
typename ARG3,
typename ARG4
>
void bsp_listen_dynamic_port (
unsigned short listening_port,
port_notify_function_type port_notify_function,
funct_type funct,
ARG1 arg1,
ARG2 arg2,
ARG3 arg3,
ARG4 arg4
);
/*!
requires
- let CONTEXT be an instance of a bsp_context object. Then:
- funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression
(i.e. funct must be a function or function object)
- port_notify_function((unsigned short) 1234) must be a valid expression
(i.e. port_notify_function() must be a function or function object taking an
unsigned short)
ensures
- This function listens for a connection from the bsp_connect() routine. Once
this connection is established, funct(CONTEXT,arg1,arg2,arg3,arg4) will be
executed and it will then be able to participate in the BSP computation as
one of the processing nodes.
- if (listening_port != 0) then
- This function will listen on TCP port listening_port for a connection
from bsp_connect().
- else
- An available TCP port number is automatically selected and this function
will listen on it for a connection from bsp_connect().
- Once a listening port is opened, port_notify_function() is called with the
port number used. This provides a mechanism to find out what listening port
has been used if it is automatically selected. It also allows you to find
out when the routine has begun listening for an incoming connection from
bsp_connect().
- Once a connection is established, we will close the listening port so it is
free for use by other applications. The connection and BSP computation will
continue uninterrupted.
- This call to bsp_listen_dynamic_port() blocks until the BSP computation has
completed on all processing nodes.
throws
- dlib::socket_error
This exception is thrown if there is an error which prevents the BSP
job from executing.
- Any exception thrown by funct() will be propagated out of this call to
bsp_connect().
!*/
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BsP_ABSTRACT_Hh_

View File

@@ -0,0 +1,10 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BYTE_ORDEREr_
#define DLIB_BYTE_ORDEREr_
#include "byte_orderer/byte_orderer_kernel_1.h"
#endif // DLIB_BYTE_ORDEREr_

View File

@@ -0,0 +1,176 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BYTE_ORDEREr_KERNEL_1_
#define DLIB_BYTE_ORDEREr_KERNEL_1_
#include "byte_orderer_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
namespace dlib
{
class byte_orderer
{
/*!
INITIAL VALUE
- if (this machine is little endian) then
- little_endian == true
- else
- little_endian == false
CONVENTION
- host_is_big_endian() == !little_endian
- host_is_little_endian() == little_endian
- if (this machine is little endian) then
- little_endian == true
- else
- little_endian == false
!*/
public:
// this is here for backwards compatibility with older versions of dlib.
typedef byte_orderer kernel_1a;
byte_orderer (
)
{
// This will probably never be false but if it is then it means chars are not 8bits
// on this system. Which is a problem for this object.
COMPILE_TIME_ASSERT(sizeof(short) >= 2);
unsigned long temp = 1;
unsigned char* ptr = reinterpret_cast<unsigned char*>(&temp);
if (*ptr == 1)
little_endian = true;
else
little_endian = false;
}
virtual ~byte_orderer (
){}
bool host_is_big_endian (
) const { return !little_endian; }
bool host_is_little_endian (
) const { return little_endian; }
template <
typename T
>
inline void host_to_network (
T& item
) const
{ if (little_endian) flip(item); }
template <
typename T
>
inline void network_to_host (
T& item
) const { if (little_endian) flip(item); }
template <
typename T
>
void host_to_big (
T& item
) const { if (little_endian) flip(item); }
template <
typename T
>
void big_to_host (
T& item
) const { if (little_endian) flip(item); }
template <
typename T
>
void host_to_little (
T& item
) const { if (!little_endian) flip(item); }
template <
typename T
>
void little_to_host (
T& item
) const { if (!little_endian) flip(item); }
private:
template <
typename T,
size_t size
>
inline void flip (
T (&array)[size]
) const
/*!
ensures
- flips the bytes in every element of this array
!*/
{
for (size_t i = 0; i < size; ++i)
{
flip(array[i]);
}
}
template <
typename T
>
inline void flip (
T& item
) const
/*!
ensures
- reverses the byte ordering in item
!*/
{
DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);
T value;
// If you are getting this as an error then you are probably using
// this object wrong. If you think you aren't then send me (Davis) an
// email and I'll either set you straight or change/remove this check so
// your stuff works :)
COMPILE_TIME_ASSERT(sizeof(T) <= sizeof(long double));
// If you are getting a compile error on this line then it means T is
// a pointer type. It doesn't make any sense to byte swap pointers
// since they have no meaning outside the context of their own process.
// So you probably just forgot to dereference that pointer before passing
// it to this function :)
COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);
const size_t size = sizeof(T);
unsigned char* const ptr = reinterpret_cast<unsigned char*>(&item);
unsigned char* const ptr_temp = reinterpret_cast<unsigned char*>(&value);
for (size_t i = 0; i < size; ++i)
ptr_temp[size-i-1] = ptr[i];
item = value;
}
bool little_endian;
};
// make flip not do anything at all for chars
template <> inline void byte_orderer::flip<char> ( char& ) const {}
template <> inline void byte_orderer::flip<unsigned char> ( unsigned char& ) const {}
template <> inline void byte_orderer::flip<signed char> ( signed char& ) const {}
}
#endif // DLIB_BYTE_ORDEREr_KERNEL_1_

View File

@@ -0,0 +1,149 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BYTE_ORDEREr_ABSTRACT_
#ifdef DLIB_BYTE_ORDEREr_ABSTRACT_
#include "../algs.h"
namespace dlib
{
class byte_orderer
{
/*!
INITIAL VALUE
This object has no state.
WHAT THIS OBJECT REPRESENTS
This object simply provides a mechanism to convert data from a
host machine's own byte ordering to big or little endian and to
also do the reverse.
It also provides a pair of functions to convert to/from network byte
order where network byte order is big endian byte order. This pair of
functions does the exact same thing as the host_to_big() and big_to_host()
functions and is provided simply so that client code can use the most
self documenting name appropriate.
Also note that this object is capable of correctly flipping the contents
of arrays when the arrays are declared on the stack. e.g. You can
say things like:
int array[10];
bo.host_to_network(array);
!*/
public:
byte_orderer (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~byte_orderer (
);
/*!
ensures
- any resources associated with *this have been released
!*/
bool host_is_big_endian (
) const;
/*!
ensures
- if (the host computer is a big endian machine) then
- returns true
- else
- returns false
!*/
bool host_is_little_endian (
) const;
/*!
ensures
- if (the host computer is a little endian machine) then
- returns true
- else
- returns false
!*/
template <
typename T
>
void host_to_network (
T& item
) const;
/*!
ensures
- #item == the value of item converted from host byte order
to network byte order.
!*/
template <
typename T
>
void network_to_host (
T& item
) const;
/*!
ensures
- #item == the value of item converted from network byte order
to host byte order.
!*/
template <
typename T
>
void host_to_big (
T& item
) const;
/*!
ensures
- #item == the value of item converted from host byte order
to big endian byte order.
!*/
template <
typename T
>
void big_to_host (
T& item
) const;
/*!
ensures
- #item == the value of item converted from big endian byte order
to host byte order.
!*/
template <
typename T
>
void host_to_little (
T& item
) const;
/*!
ensures
- #item == the value of item converted from host byte order
to little endian byte order.
!*/
template <
typename T
>
void little_to_host (
T& item
) const;
/*!
ensures
- #item == the value of item converted from little endian byte order
to host byte order.
!*/
};
}
#endif // DLIB_BYTE_ORDEREr_ABSTRACT_

View File

@@ -0,0 +1,13 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CLuSTERING_
#define DLIB_CLuSTERING_
#include "clustering/modularity_clustering.h"
#include "clustering/chinese_whispers.h"
#include "clustering/spectral_cluster.h"
#include "clustering/bottom_up_cluster.h"
#include "svm/kkmeans.h"
#endif // DLIB_CLuSTERING_

View File

@@ -0,0 +1,253 @@
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_BOTTOM_uP_CLUSTER_Hh_
#define DLIB_BOTTOM_uP_CLUSTER_Hh_
#include <queue>
#include <map>
#include "bottom_up_cluster_abstract.h"
#include "../algs.h"
#include "../matrix.h"
#include "../disjoint_subsets.h"
#include "../graph_utils.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace buc_impl
{
inline void merge_sets (
matrix<double>& dists,
unsigned long dest,
unsigned long src
)
{
for (long r = 0; r < dists.nr(); ++r)
dists(dest,r) = dists(r,dest) = std::max(dists(r,dest), dists(r,src));
}
struct compare_dist
{
bool operator() (
const sample_pair& a,
const sample_pair& b
) const
{
return a.distance() > b.distance();
}
};
}
// ----------------------------------------------------------------------------------------
template <
typename EXP
>
unsigned long bottom_up_cluster (
const matrix_exp<EXP>& dists_,
std::vector<unsigned long>& labels,
unsigned long min_num_clusters,
double max_dist = std::numeric_limits<double>::infinity()
)
{
matrix<double> dists = matrix_cast<double>(dists_);
// make sure requires clause is not broken
DLIB_CASSERT(dists.nr() == dists.nc() && min_num_clusters > 0,
"\t unsigned long bottom_up_cluster()"
<< "\n\t Invalid inputs were given to this function."
<< "\n\t dists.nr(): " << dists.nr()
<< "\n\t dists.nc(): " << dists.nc()
<< "\n\t min_num_clusters: " << min_num_clusters
);
using namespace buc_impl;
labels.resize(dists.nr());
disjoint_subsets sets;
sets.set_size(dists.nr());
if (labels.size() == 0)
return 0;
// push all the edges in the graph into a priority queue so the best edges to merge
// come first.
std::priority_queue<sample_pair, std::vector<sample_pair>, compare_dist> que;
for (long r = 0; r < dists.nr(); ++r)
for (long c = r+1; c < dists.nc(); ++c)
que.push(sample_pair(r,c,dists(r,c)));
// Now start merging nodes.
for (unsigned long iter = min_num_clusters; iter < sets.size(); ++iter)
{
// find the next best thing to merge.
double best_dist = que.top().distance();
unsigned long a = sets.find_set(que.top().index1());
unsigned long b = sets.find_set(que.top().index2());
que.pop();
// we have been merging and modifying the distances, so make sure this distance
// is still valid and these guys haven't been merged already.
while(a == b || best_dist < dists(a,b))
{
// Haven't merged it yet, so put it back in with updated distance for
// reconsideration later.
if (a != b)
que.push(sample_pair(a, b, dists(a, b)));
best_dist = que.top().distance();
a = sets.find_set(que.top().index1());
b = sets.find_set(que.top().index2());
que.pop();
}
// now merge these sets if the best distance is small enough
if (best_dist > max_dist)
break;
unsigned long news = sets.merge_sets(a,b);
unsigned long olds = (news==a)?b:a;
merge_sets(dists, news, olds);
}
// figure out which cluster each element is in. Also make sure the labels are
// contiguous.
std::map<unsigned long, unsigned long> relabel;
for (unsigned long r = 0; r < labels.size(); ++r)
{
unsigned long l = sets.find_set(r);
// relabel to make contiguous
if (relabel.count(l) == 0)
{
unsigned long next = relabel.size();
relabel[l] = next;
}
labels[r] = relabel[l];
}
return relabel.size();
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
struct snl_range
{
snl_range() = default;
snl_range(double val) : lower(val), upper(val) {}
snl_range(double l, double u) : lower(l), upper(u) { DLIB_ASSERT(lower <= upper)}
double lower = 0;
double upper = 0;
double width() const { return upper-lower; }
bool operator<(const snl_range& item) const { return lower < item.lower; }
};
inline snl_range merge(const snl_range& a, const snl_range& b)
{
return snl_range(std::min(a.lower, b.lower), std::max(a.upper, b.upper));
}
inline double distance (const snl_range& a, const snl_range& b)
{
return std::max(a.lower,b.lower) - std::min(a.upper,b.upper);
}
inline std::ostream& operator<< (std::ostream& out, const snl_range& item )
{
out << "["<<item.lower<<","<<item.upper<<"]";
return out;
}
// ----------------------------------------------------------------------------------------
inline std::vector<snl_range> segment_number_line (
const std::vector<double>& x,
const double max_range_width
)
{
DLIB_CASSERT(max_range_width >= 0);
// create initial ranges, one for each value in x. So initially, all the ranges have
// width of 0.
std::vector<snl_range> ranges;
for (auto v : x)
ranges.push_back(v);
std::sort(ranges.begin(), ranges.end());
std::vector<snl_range> greedy_final_ranges;
if (ranges.size() == 0)
return greedy_final_ranges;
// We will try two different clustering strategies. One that does a simple greedy left
// to right sweep and another that does a bottom up agglomerative clustering. This
// first loop runs the greedy left to right sweep. Then at the end of this routine we
// will return the results that produced the tightest clustering.
greedy_final_ranges.push_back(ranges[0]);
for (size_t i = 1; i < ranges.size(); ++i)
{
auto m = merge(greedy_final_ranges.back(), ranges[i]);
if (m.width() <= max_range_width)
greedy_final_ranges.back() = m;
else
greedy_final_ranges.push_back(ranges[i]);
}
// Here we do the bottom up clustering. So compute the edges connecting our ranges.
// We will simply say there are edges between ranges if and only if they are
// immediately adjacent on the number line.
std::vector<sample_pair> edges;
for (size_t i = 1; i < ranges.size(); ++i)
edges.push_back(sample_pair(i-1,i, distance(ranges[i-1],ranges[i])));
std::sort(edges.begin(), edges.end(), order_by_distance<sample_pair>);
disjoint_subsets sets;
sets.set_size(ranges.size());
// Now start merging nodes.
for (auto edge : edges)
{
// find the next best thing to merge.
unsigned long a = sets.find_set(edge.index1());
unsigned long b = sets.find_set(edge.index2());
// merge it if it doesn't result in an interval that's too big.
auto m = merge(ranges[a], ranges[b]);
if (m.width() <= max_range_width)
{
unsigned long news = sets.merge_sets(a,b);
ranges[news] = m;
}
}
// Now create a list of the final ranges. We will do this by keeping track of which
// range we already added to final_ranges.
std::vector<snl_range> final_ranges;
std::vector<bool> already_output(ranges.size(), false);
for (unsigned long i = 0; i < sets.size(); ++i)
{
auto s = sets.find_set(i);
if (!already_output[s])
{
final_ranges.push_back(ranges[s]);
already_output[s] = true;
}
}
// only use the greedy clusters if they found a clustering with fewer clusters.
// Otherwise, the bottom up clustering probably produced a more sensible clustering.
if (final_ranges.size() <= greedy_final_ranges.size())
return final_ranges;
else
return greedy_final_ranges;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BOTTOM_uP_CLUSTER_Hh_

View File

@@ -0,0 +1,136 @@
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_
#ifdef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_
#include "../matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename EXP
>
unsigned long bottom_up_cluster (
const matrix_exp<EXP>& dists,
std::vector<unsigned long>& labels,
unsigned long min_num_clusters,
double max_dist = std::numeric_limits<double>::infinity()
);
/*!
requires
- dists.nr() == dists.nc()
- min_num_clusters > 0
- dists == trans(dists)
(l.e. dists should be symmetric)
ensures
- Runs a bottom up agglomerative clustering algorithm.
- Interprets dists as a matrix that gives the distances between dists.nr()
items. In particular, we take dists(i,j) to be the distance between the ith
and jth element of some set. This function clusters the elements of this set
into at least min_num_clusters (or dists.nr() if there aren't enough
elements). Additionally, within each cluster, the maximum pairwise distance
between any two cluster elements is <= max_dist.
- returns the number of clusters found.
- #labels.size() == dists.nr()
- for all valid i:
- #labels[i] == the cluster ID of the node with index i (i.e. the node
corresponding to the distances dists(i,*)).
- 0 <= #labels[i] < the number of clusters found
(i.e. cluster IDs are assigned contiguously and start at 0)
!*/
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
struct snl_range
{
/*!
WHAT THIS OBJECT REPRESENTS
This object represents an interval on the real number line. It is used
to store the outputs of the segment_number_line() routine defined below.
!*/
snl_range(
);
/*!
ensures
- #lower == 0
- #upper == 0
!*/
snl_range(
double val
);
/*!
ensures
- #lower == val
- #upper == val
!*/
snl_range(
double l,
double u
);
/*!
requires
- l <= u
ensures
- #lower == l
- #upper == u
!*/
double lower;
double upper;
double width(
) const { return upper-lower; }
/*!
ensures
- returns the width of this interval on the number line.
!*/
bool operator<(const snl_range& item) const { return lower < item.lower; }
/*!
ensures
- provides a total ordering of snl_range objects assuming they are
non-overlapping.
!*/
};
std::ostream& operator<< (std::ostream& out, const snl_range& item );
/*!
ensures
- prints item to out in the form [lower,upper].
!*/
// ----------------------------------------------------------------------------------------
std::vector<snl_range> segment_number_line (
const std::vector<double>& x,
const double max_range_width
);
/*!
requires
- max_range_width >= 0
ensures
- Finds a clustering of the values in x and returns the ranges that define the
clustering. This routine uses a combination of bottom up clustering and a
simple greedy scan to try and find the most compact set of ranges that
contain all the values in x.
- This routine has approximately linear runtime.
- Every value in x will be contained inside one of the returned snl_range
objects;
- All returned snl_range object's will have a width() <= max_range_width and
will also be non-overlapping.
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_

View File

@@ -0,0 +1,135 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CHINESE_WHISPErS_Hh_
#define DLIB_CHINESE_WHISPErS_Hh_
#include "chinese_whispers_abstract.h"
#include <vector>
#include "../rand.h"
#include "../graph_utils/edge_list_graphs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
inline unsigned long chinese_whispers (
const std::vector<ordered_sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations,
dlib::rand& rnd
)
{
// make sure requires clause is not broken
DLIB_ASSERT(is_ordered_by_index(edges),
"\t unsigned long chinese_whispers()"
<< "\n\t Invalid inputs were given to this function"
);
labels.clear();
if (edges.size() == 0)
return 0;
std::vector<std::pair<unsigned long, unsigned long> > neighbors;
find_neighbor_ranges(edges, neighbors);
// Initialize the labels, each node gets a different label.
labels.resize(neighbors.size());
for (unsigned long i = 0; i < labels.size(); ++i)
labels[i] = i;
for (unsigned long iter = 0; iter < neighbors.size()*num_iterations; ++iter)
{
// Pick a random node.
const unsigned long idx = rnd.get_random_64bit_number()%neighbors.size();
// Count how many times each label happens amongst our neighbors.
std::map<unsigned long, double> labels_to_counts;
const unsigned long end = neighbors[idx].second;
for (unsigned long i = neighbors[idx].first; i != end; ++i)
{
labels_to_counts[labels[edges[i].index2()]] += edges[i].distance();
}
// find the most common label
std::map<unsigned long, double>::iterator i;
double best_score = -std::numeric_limits<double>::infinity();
unsigned long best_label = labels[idx];
for (i = labels_to_counts.begin(); i != labels_to_counts.end(); ++i)
{
if (i->second > best_score)
{
best_score = i->second;
best_label = i->first;
}
}
labels[idx] = best_label;
}
// Remap the labels into a contiguous range. First we find the
// mapping.
std::map<unsigned long,unsigned long> label_remap;
for (unsigned long i = 0; i < labels.size(); ++i)
{
const unsigned long next_id = label_remap.size();
if (label_remap.count(labels[i]) == 0)
label_remap[labels[i]] = next_id;
}
// now apply the mapping to all the labels.
for (unsigned long i = 0; i < labels.size(); ++i)
{
labels[i] = label_remap[labels[i]];
}
return label_remap.size();
}
// ----------------------------------------------------------------------------------------
inline unsigned long chinese_whispers (
const std::vector<sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations,
dlib::rand& rnd
)
{
std::vector<ordered_sample_pair> oedges;
convert_unordered_to_ordered(edges, oedges);
std::sort(oedges.begin(), oedges.end(), &order_by_index<ordered_sample_pair>);
return chinese_whispers(oedges, labels, num_iterations, rnd);
}
// ----------------------------------------------------------------------------------------
inline unsigned long chinese_whispers (
const std::vector<sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations = 100
)
{
dlib::rand rnd;
return chinese_whispers(edges, labels, num_iterations, rnd);
}
// ----------------------------------------------------------------------------------------
inline unsigned long chinese_whispers (
const std::vector<ordered_sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations = 100
)
{
dlib::rand rnd;
return chinese_whispers(edges, labels, num_iterations, rnd);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CHINESE_WHISPErS_Hh_

View File

@@ -0,0 +1,97 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_
#ifdef DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_
#include <vector>
#include "../rand.h"
#include "../graph_utils/ordered_sample_pair_abstract.h"
#include "../graph_utils/sample_pair_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
unsigned long chinese_whispers (
const std::vector<ordered_sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations,
dlib::rand& rnd
);
/*!
requires
- is_ordered_by_index(edges) == true
ensures
- This function implements the graph clustering algorithm described in the
paper: Chinese Whispers - an Efficient Graph Clustering Algorithm and its
Application to Natural Language Processing Problems by Chris Biemann.
- Interprets edges as a directed graph. That is, it contains the edges on the
said graph and the ordered_sample_pair::distance() values define the edge
weights (larger values indicating a stronger edge connection between the
nodes). If an edge has a distance() value of infinity then it is considered
a "must link" edge.
- returns the number of clusters found.
- #labels.size() == max_index_plus_one(edges)
- for all valid i:
- #labels[i] == the cluster ID of the node with index i in the graph.
- 0 <= #labels[i] < the number of clusters found
(i.e. cluster IDs are assigned contiguously and start at 0)
- Duplicate edges are interpreted as if there had been just one edge with a
distance value equal to the sum of all the duplicate edge's distance values.
- The algorithm performs exactly num_iterations passes over the graph before
terminating.
!*/
// ----------------------------------------------------------------------------------------
unsigned long chinese_whispers (
const std::vector<sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations,
dlib::rand& rnd
);
/*!
ensures
- This function is identical to the above chinese_whispers() routine except
that it operates on a vector of sample_pair objects instead of
ordered_sample_pairs. Therefore, this is simply a convenience routine. In
particular, it is implemented by transforming the given edges into
ordered_sample_pairs and then calling the chinese_whispers() routine defined
above.
!*/
// ----------------------------------------------------------------------------------------
unsigned long chinese_whispers (
const std::vector<ordered_sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations = 100
);
/*!
requires
- is_ordered_by_index(edges) == true
ensures
- performs: return chinese_whispers(edges, labels, num_iterations, rnd)
where rnd is a default initialized dlib::rand object.
!*/
// ----------------------------------------------------------------------------------------
unsigned long chinese_whispers (
const std::vector<sample_pair>& edges,
std::vector<unsigned long>& labels,
const unsigned long num_iterations = 100
);
/*!
ensures
- performs: return chinese_whispers(edges, labels, num_iterations, rnd)
where rnd is a default initialized dlib::rand object.
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_

View File

@@ -0,0 +1,515 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_MODULARITY_ClUSTERING__H__
#define DLIB_MODULARITY_ClUSTERING__H__
#include "modularity_clustering_abstract.h"
#include "../sparse_vector.h"
#include "../graph_utils/edge_list_graphs.h"
#include "../matrix.h"
#include "../rand.h"
namespace dlib
{
// -----------------------------------------------------------------------------------------
namespace impl
{
inline double newman_cluster_split (
dlib::rand& rnd,
const std::vector<ordered_sample_pair>& edges,
const matrix<double,0,1>& node_degrees, // k from the Newman paper
const matrix<double,0,1>& Bdiag, // diag(B) from the Newman paper
const double& edge_sum, // m from the Newman paper
matrix<double,0,1>& labels,
const double eps,
const unsigned long max_iterations
)
/*!
requires
- node_degrees.size() == max_index_plus_one(edges)
- Bdiag.size() == max_index_plus_one(edges)
- edges must be sorted according to order_by_index()
ensures
- This routine splits a graph into two subgraphs using the Newman
clustering method.
- returns the modularity obtained when the graph is split according
to the contents of #labels.
- #labels.size() == node_degrees.size()
- for all valid i: #labels(i) == -1 or +1
- if (this function returns 0) then
- all the labels are equal, i.e. the graph is not split.
!*/
{
// Scale epsilon so that it is relative to the expected value of an element of a
// unit vector of length node_degrees.size().
const double power_iter_eps = eps * std::sqrt(1.0/node_degrees.size());
// Make a random unit vector and put in labels.
labels.set_size(node_degrees.size());
for (long i = 0; i < labels.size(); ++i)
labels(i) = rnd.get_random_gaussian();
labels /= length(labels);
matrix<double,0,1> Bv, Bv_unit;
// Do the power iteration for a while.
double eig = -1;
double offset = 0;
while (eig < 0)
{
// any number larger than power_iter_eps
double iteration_change = power_iter_eps*2+1;
for (unsigned long i = 0; i < max_iterations && iteration_change > power_iter_eps; ++i)
{
sparse_matrix_vector_multiply(edges, labels, Bv);
Bv -= dot(node_degrees, labels)/(2*edge_sum) * node_degrees;
if (offset != 0)
{
Bv -= offset*labels;
}
const double len = length(Bv);
if (len != 0)
{
Bv_unit = Bv/len;
iteration_change = max(abs(labels-Bv_unit));
labels.swap(Bv_unit);
}
else
{
// Had a bad time, pick another random vector and try it with the
// power iteration.
for (long i = 0; i < labels.size(); ++i)
labels(i) = rnd.get_random_gaussian();
}
}
eig = dot(Bv,labels);
// we will repeat this loop if the largest eigenvalue is negative
offset = eig;
}
for (long i = 0; i < labels.size(); ++i)
{
if (labels(i) > 0)
labels(i) = 1;
else
labels(i) = -1;
}
// compute B*labels, store result in Bv.
sparse_matrix_vector_multiply(edges, labels, Bv);
Bv -= dot(node_degrees, labels)/(2*edge_sum) * node_degrees;
// Do some label refinement. In this step we swap labels if it
// improves the modularity score.
bool flipped_label = true;
while(flipped_label)
{
flipped_label = false;
unsigned long idx = 0;
for (long i = 0; i < labels.size(); ++i)
{
const double val = -2*labels(i);
const double increase = 4*Bdiag(i) + 2*val*Bv(i);
// if there is an increase in modularity for swapping this label
if (increase > 0)
{
labels(i) *= -1;
while (idx < edges.size() && edges[idx].index1() == (unsigned long)i)
{
const long j = edges[idx].index2();
Bv(j) += val*edges[idx].distance();
++idx;
}
Bv -= (val*node_degrees(i)/(2*edge_sum))*node_degrees;
flipped_label = true;
}
else
{
while (idx < edges.size() && edges[idx].index1() == (unsigned long)i)
{
++idx;
}
}
}
}
const double modularity = dot(Bv, labels)/(4*edge_sum);
return modularity;
}
// -------------------------------------------------------------------------------------
inline unsigned long newman_cluster_helper (
dlib::rand& rnd,
const std::vector<ordered_sample_pair>& edges,
const matrix<double,0,1>& node_degrees, // k from the Newman paper
const matrix<double,0,1>& Bdiag, // diag(B) from the Newman paper
const double& edge_sum, // m from the Newman paper
std::vector<unsigned long>& labels,
double modularity_threshold,
const double eps,
const unsigned long max_iterations
)
/*!
ensures
- returns the number of clusters the data was split into
!*/
{
matrix<double,0,1> l;
const double modularity = newman_cluster_split(rnd,edges,node_degrees,Bdiag,edge_sum,l,eps,max_iterations);
// We need to collapse the node index values down to contiguous values. So
// we use the following two vectors to contain the mappings from input index
// values to their corresponding index values in each split.
std::vector<unsigned long> left_idx_map(node_degrees.size());
std::vector<unsigned long> right_idx_map(node_degrees.size());
// figure out how many nodes went into each side of the split.
unsigned long num_left_split = 0;
unsigned long num_right_split = 0;
for (long i = 0; i < l.size(); ++i)
{
if (l(i) > 0)
{
left_idx_map[i] = num_left_split;
++num_left_split;
}
else
{
right_idx_map[i] = num_right_split;
++num_right_split;
}
}
// do a recursive split if it will improve the modularity.
if (modularity > modularity_threshold && num_left_split > 0 && num_right_split > 0)
{
// split the node_degrees and Bdiag matrices into left and right split parts
matrix<double,0,1> left_node_degrees(num_left_split);
matrix<double,0,1> right_node_degrees(num_right_split);
matrix<double,0,1> left_Bdiag(num_left_split);
matrix<double,0,1> right_Bdiag(num_right_split);
for (long i = 0; i < l.size(); ++i)
{
if (l(i) > 0)
{
left_node_degrees(left_idx_map[i]) = node_degrees(i);
left_Bdiag(left_idx_map[i]) = Bdiag(i);
}
else
{
right_node_degrees(right_idx_map[i]) = node_degrees(i);
right_Bdiag(right_idx_map[i]) = Bdiag(i);
}
}
// put the edges from one side of the split into split_edges
std::vector<ordered_sample_pair> split_edges;
modularity_threshold = 0;
for (unsigned long k = 0; k < edges.size(); ++k)
{
const unsigned long i = edges[k].index1();
const unsigned long j = edges[k].index2();
const double d = edges[k].distance();
if (l(i) > 0 && l(j) > 0)
{
split_edges.push_back(ordered_sample_pair(left_idx_map[i], left_idx_map[j], d));
modularity_threshold += d;
}
}
modularity_threshold -= sum(left_node_degrees*sum(left_node_degrees))/(2*edge_sum);
modularity_threshold /= 4*edge_sum;
unsigned long num_left_clusters;
std::vector<unsigned long> left_labels;
num_left_clusters = newman_cluster_helper(rnd,split_edges,left_node_degrees,left_Bdiag,
edge_sum,left_labels,modularity_threshold,
eps, max_iterations);
// now load the other side into split_edges and cluster it as well
split_edges.clear();
modularity_threshold = 0;
for (unsigned long k = 0; k < edges.size(); ++k)
{
const unsigned long i = edges[k].index1();
const unsigned long j = edges[k].index2();
const double d = edges[k].distance();
if (l(i) < 0 && l(j) < 0)
{
split_edges.push_back(ordered_sample_pair(right_idx_map[i], right_idx_map[j], d));
modularity_threshold += d;
}
}
modularity_threshold -= sum(right_node_degrees*sum(right_node_degrees))/(2*edge_sum);
modularity_threshold /= 4*edge_sum;
unsigned long num_right_clusters;
std::vector<unsigned long> right_labels;
num_right_clusters = newman_cluster_helper(rnd,split_edges,right_node_degrees,right_Bdiag,
edge_sum,right_labels,modularity_threshold,
eps, max_iterations);
// Now merge the labels from the two splits.
labels.resize(node_degrees.size());
for (unsigned long i = 0; i < labels.size(); ++i)
{
// if this node was in the left split
if (l(i) > 0)
{
labels[i] = left_labels[left_idx_map[i]];
}
else // if this node was in the right split
{
labels[i] = right_labels[right_idx_map[i]] + num_left_clusters;
}
}
return num_left_clusters + num_right_clusters;
}
else
{
labels.assign(node_degrees.size(),0);
return 1;
}
}
}
// ----------------------------------------------------------------------------------------
inline unsigned long newman_cluster (
const std::vector<ordered_sample_pair>& edges,
std::vector<unsigned long>& labels,
const double eps = 1e-4,
const unsigned long max_iterations = 2000
)
{
// make sure requires clause is not broken
DLIB_ASSERT(is_ordered_by_index(edges),
"\t unsigned long newman_cluster()"
<< "\n\t Invalid inputs were given to this function"
);
labels.clear();
if (edges.size() == 0)
return 0;
const unsigned long num_nodes = max_index_plus_one(edges);
// compute the node_degrees vector, edge_sum value, and diag(B).
matrix<double,0,1> node_degrees(num_nodes);
matrix<double,0,1> Bdiag(num_nodes);
Bdiag = 0;
double edge_sum = 0;
node_degrees = 0;
for (unsigned long i = 0; i < edges.size(); ++i)
{
node_degrees(edges[i].index1()) += edges[i].distance();
edge_sum += edges[i].distance();
if (edges[i].index1() == edges[i].index2())
Bdiag(edges[i].index1()) += edges[i].distance();
}
edge_sum /= 2;
Bdiag -= squared(node_degrees)/(2*edge_sum);
dlib::rand rnd;
return impl::newman_cluster_helper(rnd,edges,node_degrees,Bdiag,edge_sum,labels,0,eps,max_iterations);
}
// ----------------------------------------------------------------------------------------
inline unsigned long newman_cluster (
const std::vector<sample_pair>& edges,
std::vector<unsigned long>& labels,
const double eps = 1e-4,
const unsigned long max_iterations = 2000
)
{
std::vector<ordered_sample_pair> oedges;
convert_unordered_to_ordered(edges, oedges);
std::sort(oedges.begin(), oedges.end(), &order_by_index<ordered_sample_pair>);
return newman_cluster(oedges, labels, eps, max_iterations);
}
// ----------------------------------------------------------------------------------------
namespace impl
{
inline std::vector<unsigned long> remap_labels (
const std::vector<unsigned long>& labels,
unsigned long& num_labels
)
/*!
ensures
- This function takes labels and produces a mapping which maps elements of
labels into the most compact range in [0, max] as possible. In particular,
there won't be any unused integers in the mapped range.
- #num_labels == the number of distinct values in labels.
- returns a vector V such that:
- V.size() == labels.size()
- max(mat(V))+1 == num_labels.
- for all valid i,j:
- if (labels[i] == labels[j]) then
- V[i] == V[j]
- else
- V[i] != V[j]
!*/
{
std::map<unsigned long, unsigned long> temp;
for (unsigned long i = 0; i < labels.size(); ++i)
{
if (temp.count(labels[i]) == 0)
{
const unsigned long next = temp.size();
temp[labels[i]] = next;
}
}
num_labels = temp.size();
std::vector<unsigned long> result(labels.size());
for (unsigned long i = 0; i < labels.size(); ++i)
{
result[i] = temp[labels[i]];
}
return result;
}
}
// ----------------------------------------------------------------------------------------
inline double modularity (
const std::vector<sample_pair>& edges,
const std::vector<unsigned long>& labels
)
{
const unsigned long num_nodes = max_index_plus_one(edges);
// make sure requires clause is not broken
DLIB_ASSERT(labels.size() == num_nodes,
"\t double modularity()"
<< "\n\t Invalid inputs were given to this function"
);
unsigned long num_labels;
const std::vector<unsigned long>& labels_ = dlib::impl::remap_labels(labels,num_labels);
std::vector<double> cluster_sums(num_labels,0);
std::vector<double> k(num_nodes,0);
double Q = 0;
double m = 0;
for (unsigned long i = 0; i < edges.size(); ++i)
{
const unsigned long n1 = edges[i].index1();
const unsigned long n2 = edges[i].index2();
k[n1] += edges[i].distance();
if (n1 != n2)
k[n2] += edges[i].distance();
if (n1 != n2)
m += edges[i].distance();
else
m += edges[i].distance()/2;
if (labels_[n1] == labels_[n2])
{
if (n1 != n2)
Q += 2*edges[i].distance();
else
Q += edges[i].distance();
}
}
if (m == 0)
return 0;
for (unsigned long i = 0; i < labels_.size(); ++i)
{
cluster_sums[labels_[i]] += k[i];
}
for (unsigned long i = 0; i < labels_.size(); ++i)
{
Q -= k[i]*cluster_sums[labels_[i]]/(2*m);
}
return 1.0/(2*m)*Q;
}
// ----------------------------------------------------------------------------------------
inline double modularity (
const std::vector<ordered_sample_pair>& edges,
const std::vector<unsigned long>& labels
)
{
const unsigned long num_nodes = max_index_plus_one(edges);
// make sure requires clause is not broken
DLIB_ASSERT(labels.size() == num_nodes,
"\t double modularity()"
<< "\n\t Invalid inputs were given to this function"
);
unsigned long num_labels;
const std::vector<unsigned long>& labels_ = dlib::impl::remap_labels(labels,num_labels);
std::vector<double> cluster_sums(num_labels,0);
std::vector<double> k(num_nodes,0);
double Q = 0;
double m = 0;
for (unsigned long i = 0; i < edges.size(); ++i)
{
const unsigned long n1 = edges[i].index1();
const unsigned long n2 = edges[i].index2();
k[n1] += edges[i].distance();
m += edges[i].distance();
if (labels_[n1] == labels_[n2])
{
Q += edges[i].distance();
}
}
if (m == 0)
return 0;
for (unsigned long i = 0; i < labels_.size(); ++i)
{
cluster_sums[labels_[i]] += k[i];
}
for (unsigned long i = 0; i < labels_.size(); ++i)
{
Q -= k[i]*cluster_sums[labels_[i]]/m;
}
return 1.0/m*Q;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_MODULARITY_ClUSTERING__H__

View File

@@ -0,0 +1,125 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_
#ifdef DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_
#include <vector>
#include "../graph_utils/ordered_sample_pair_abstract.h"
#include "../graph_utils/sample_pair_abstract.h"
namespace dlib
{
// -----------------------------------------------------------------------------------------
double modularity (
const std::vector<sample_pair>& edges,
const std::vector<unsigned long>& labels
);
/*!
requires
- labels.size() == max_index_plus_one(edges)
- for all valid i:
- 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
ensures
- Interprets edges as an undirected graph. That is, it contains the edges on
the said graph and the sample_pair::distance() values define the edge weights
(larger values indicating a stronger edge connection between the nodes).
- This function returns the modularity value obtained when the given input
graph is broken into subgraphs according to the contents of labels. In
particular, we say that two nodes with indices i and j are in the same
subgraph or community if and only if labels[i] == labels[j].
- Duplicate edges are interpreted as if there had been just one edge with a
distance value equal to the sum of all the duplicate edge's distance values.
- See the paper Modularity and community structure in networks by M. E. J. Newman
for a detailed definition.
!*/
// ----------------------------------------------------------------------------------------
double modularity (
const std::vector<ordered_sample_pair>& edges,
const std::vector<unsigned long>& labels
);
/*!
requires
- labels.size() == max_index_plus_one(edges)
- for all valid i:
- 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
ensures
- Interprets edges as a directed graph. That is, it contains the edges on the
said graph and the ordered_sample_pair::distance() values define the edge
weights (larger values indicating a stronger edge connection between the
nodes). Note that, generally, modularity is only really defined for
undirected graphs. Therefore, the "directed graph" given to this function
should have symmetric edges between all nodes. The reason this function is
provided at all is because sometimes a vector of ordered_sample_pair objects
is a useful representation of an undirected graph.
- This function returns the modularity value obtained when the given input
graph is broken into subgraphs according to the contents of labels. In
particular, we say that two nodes with indices i and j are in the same
subgraph or community if and only if labels[i] == labels[j].
- Duplicate edges are interpreted as if there had been just one edge with a
distance value equal to the sum of all the duplicate edge's distance values.
- See the paper Modularity and community structure in networks by M. E. J. Newman
for a detailed definition.
!*/
// ----------------------------------------------------------------------------------------
unsigned long newman_cluster (
const std::vector<ordered_sample_pair>& edges,
std::vector<unsigned long>& labels,
const double eps = 1e-4,
const unsigned long max_iterations = 2000
);
/*!
requires
- is_ordered_by_index(edges) == true
- for all valid i:
- 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
ensures
- This function performs the clustering algorithm described in the paper
Modularity and community structure in networks by M. E. J. Newman.
- This function interprets edges as a graph and attempts to find the labeling
that maximizes modularity(edges, #labels).
- returns the number of clusters found.
- #labels.size() == max_index_plus_one(edges)
- for all valid i:
- #labels[i] == the cluster ID of the node with index i in the graph.
- 0 <= #labels[i] < the number of clusters found
(i.e. cluster IDs are assigned contiguously and start at 0)
- The main computation of the algorithm is involved in finding an eigenvector
of a certain matrix. To do this, we use the power iteration. In particular,
each time we try to find an eigenvector we will let the power iteration loop
at most max_iterations times or until it reaches an accuracy of eps.
Whichever comes first.
!*/
// ----------------------------------------------------------------------------------------
unsigned long newman_cluster (
const std::vector<sample_pair>& edges,
std::vector<unsigned long>& labels,
const double eps = 1e-4,
const unsigned long max_iterations = 2000
);
/*!
requires
- for all valid i:
- 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()
ensures
- This function is identical to the above newman_cluster() routine except that
it operates on a vector of sample_pair objects instead of
ordered_sample_pairs. Therefore, this is simply a convenience routine. In
particular, it is implemented by transforming the given edges into
ordered_sample_pairs and then calling the newman_cluster() routine defined
above.
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_

View File

@@ -0,0 +1,80 @@
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_SPECTRAL_CLUSTEr_H_
#define DLIB_SPECTRAL_CLUSTEr_H_
#include "spectral_cluster_abstract.h"
#include <vector>
#include "../matrix.h"
#include "../svm/kkmeans.h"
namespace dlib
{
template <
typename kernel_type,
typename vector_type
>
std::vector<unsigned long> spectral_cluster (
const kernel_type& k,
const vector_type& samples,
const unsigned long num_clusters
)
{
DLIB_CASSERT(num_clusters > 0,
"\t std::vector<unsigned long> spectral_cluster(k,samples,num_clusters)"
<< "\n\t num_clusters can't be 0."
);
if (num_clusters == 1)
{
// nothing to do, just assign everything to the 0 cluster.
return std::vector<unsigned long>(samples.size(), 0);
}
// compute the similarity matrix.
matrix<double> K(samples.size(), samples.size());
for (long r = 0; r < K.nr(); ++r)
for (long c = r+1; c < K.nc(); ++c)
K(r,c) = K(c,r) = (double)k(samples[r], samples[c]);
for (long r = 0; r < K.nr(); ++r)
K(r,r) = 0;
matrix<double,0,1> D(K.nr());
for (long r = 0; r < K.nr(); ++r)
D(r) = sum(rowm(K,r));
D = sqrt(reciprocal(D));
K = diagm(D)*K*diagm(D);
matrix<double> u,w,v;
// Use the normal SVD routine unless the matrix is really big, then use the fast
// approximate version.
if (K.nr() < 1000)
svd3(K,u,w,v);
else
svd_fast(K,u,w,v, num_clusters+100, 5);
// Pick out the eigenvectors associated with the largest eigenvalues.
rsort_columns(v,w);
v = colm(v, range(0,num_clusters-1));
// Now build the normalized spectral vectors, one for each input vector.
std::vector<matrix<double,0,1> > spec_samps, centers;
for (long r = 0; r < v.nr(); ++r)
{
spec_samps.push_back(trans(rowm(v,r)));
const double len = length(spec_samps.back());
if (len != 0)
spec_samps.back() /= len;
}
// Finally do the K-means clustering
pick_initial_centers(num_clusters, centers, spec_samps);
find_clusters_using_kmeans(spec_samps, centers);
// And then compute the cluster assignments based on the output of K-means.
std::vector<unsigned long> assignments;
for (unsigned long i = 0; i < spec_samps.size(); ++i)
assignments.push_back(nearest_center(centers, spec_samps[i]));
return assignments;
}
}
#endif // DLIB_SPECTRAL_CLUSTEr_H_

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_
#ifdef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_
#include <vector>
namespace dlib
{
template <
typename kernel_type,
typename vector_type
>
std::vector<unsigned long> spectral_cluster (
const kernel_type& k,
const vector_type& samples,
const unsigned long num_clusters
);
/*!
requires
- samples must be something with an interface compatible with std::vector.
- The following expression must evaluate to a double or float:
k(samples[i], samples[j])
- num_clusters > 0
ensures
- Performs the spectral clustering algorithm described in the paper:
On spectral clustering: Analysis and an algorithm by Ng, Jordan, and Weiss.
and returns the results.
- This function clusters the input data samples into num_clusters clusters and
returns a vector that indicates which cluster each sample falls into. In
particular, we return an array A such that:
- A.size() == samples.size()
- A[i] == the cluster assignment of samples[i].
- for all valid i: 0 <= A[i] < num_clusters
- The "similarity" of samples[i] with samples[j] is given by
k(samples[i],samples[j]). This means that k() should output a number >= 0
and the number should be larger for samples that are more similar.
!*/
}
#endif // DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_

View File

@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 2.8.12)
message(WARNING "add_global_compiler_switch() is deprecated. Use target_compile_options() instead")
# Make macros that can add compiler switches to the entire project. Not just
# to the current cmake folder being built.
macro ( add_global_compiler_switch switch_name )
# If removing the switch would change the flags then it's already present
# and we don't need to do anything.
string(REPLACE "${switch_name}" "" tempstr "${CMAKE_CXX_FLAGS}")
if ("${CMAKE_CXX_FLAGS}" STREQUAL "${tempstr}" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${switch_name}"
CACHE STRING "Flags used by the compiler during all C++ builds."
FORCE)
endif ()
endmacro()
macro ( remove_global_compiler_switch switch_name )
string(REPLACE "${switch_name}" "" tempstr "${CMAKE_CXX_FLAGS}")
if (NOT "${CMAKE_CXX_FLAGS}" STREQUAL "${tempstr}" )
set (CMAKE_CXX_FLAGS "${tempstr}"
CACHE STRING "Flags used by the compiler during all C++ builds."
FORCE)
endif ()
endmacro()
macro (add_global_define def_name)
add_global_compiler_switch(-D${def_name})
endmacro()
macro (remove_global_define def_name)
remove_global_compiler_switch(-D${def_name})
endmacro()

View File

@@ -0,0 +1,19 @@
# This script checks if your compiler and host processor can generate and then run programs with AVX instructions.
cmake_minimum_required(VERSION 2.8.12)
# Don't rerun this script if its already been executed.
if (DEFINED AVX_IS_AVAILABLE_ON_HOST)
return()
endif()
# Set to false unless we find out otherwise in the code below.
set(AVX_IS_AVAILABLE_ON_HOST 0)
try_compile(test_for_avx_worked ${PROJECT_BINARY_DIR}/avx_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_avx
avx_test)
if(test_for_avx_worked)
message (STATUS "AVX instructions can be executed by the host processor.")
set(AVX_IS_AVAILABLE_ON_HOST 1)
endif()

View File

@@ -0,0 +1,20 @@
# This script checks if __ARM_NEON__ is defined for your compiler
cmake_minimum_required(VERSION 2.8.12)
# Don't rerun this script if its already been executed.
if (DEFINED ARM_NEON_IS_AVAILABLE)
return()
endif()
# Set to false unless we find out otherwise in the code below.
set(ARM_NEON_IS_AVAILABLE 0)
# test if __ARM_NEON__ is defined
try_compile(test_for_neon_worked ${PROJECT_BINARY_DIR}/neon_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_neon
neon_test)
if(test_for_neon_worked)
message (STATUS "__ARM_NEON__ defined.")
set(ARM_NEON_IS_AVAILABLE 1)
endif()

View File

@@ -0,0 +1,385 @@
#
# This is a CMake makefile. You can find the cmake utility and
# information about it at http://www.cmake.org
#
#
# This cmake file tries to find installed BLAS and LAPACK libraries.
# It looks for an installed copy of the Intel MKL library first and then
# attempts to find some other BLAS and LAPACK libraries if you don't have
# the Intel MKL.
#
# blas_found - True if BLAS is available
# lapack_found - True if LAPACK is available
# found_intel_mkl - True if the Intel MKL library is available
# found_intel_mkl_headers - True if Intel MKL headers are available
# blas_libraries - link against these to use BLAS library
# lapack_libraries - link against these to use LAPACK library
# mkl_libraries - link against these to use the MKL library
# mkl_include_dir - add to the include path to use the MKL library
# openmp_libraries - Set to Intel's OpenMP library if and only if we
# find the MKL.
# setting this makes CMake allow normal looking if else statements
SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
SET(blas_found 0)
SET(lapack_found 0)
SET(found_intel_mkl 0)
SET(found_intel_mkl_headers 0)
SET(lapack_with_underscore 0)
SET(lapack_without_underscore 0)
message(STATUS "Searching for BLAS and LAPACK")
if (UNIX OR MINGW)
message(STATUS "Searching for BLAS and LAPACK")
if (BUILDING_MATLAB_MEX_FILE)
# # This commented out stuff would link directly to MATLAB's built in
# BLAS and LAPACK. But it's better to not link to anything and do a
#find_library(MATLAB_BLAS_LIBRARY mwblas PATHS ${MATLAB_LIB_FOLDERS} )
#find_library(MATLAB_LAPACK_LIBRARY mwlapack PATHS ${MATLAB_LIB_FOLDERS} )
#if (MATLAB_BLAS_LIBRARY AND MATLAB_LAPACK_LIBRARY)
# add_subdirectory(external/cblas)
# set(blas_libraries ${MATLAB_BLAS_LIBRARY} cblas )
# set(lapack_libraries ${MATLAB_LAPACK_LIBRARY} )
# set(blas_found 1)
# set(lapack_found 1)
# message(STATUS "Found MATLAB's BLAS and LAPACK libraries")
#endif()
# We need cblas since MATLAB doesn't provide cblas symbols.
add_subdirectory(external/cblas)
set(blas_libraries cblas )
set(blas_found 1)
set(lapack_found 1)
message(STATUS "Will link with MATLAB's BLAS and LAPACK at runtime (hopefully!)")
## Don't try to link to anything other than MATLAB's own internal blas
## and lapack libraries because doing so generally upsets MATLAB. So
## we just end here no matter what.
return()
endif()
# First, search for libraries via pkg-config, which is the cleanest path
find_package(PkgConfig)
pkg_check_modules(BLAS_REFERENCE cblas)
pkg_check_modules(LAPACK_REFERENCE lapack)
if (BLAS_REFERENCE_FOUND AND LAPACK_REFERENCE_FOUND)
set(blas_libraries "${BLAS_REFERENCE_LDFLAGS}")
set(lapack_libraries "${LAPACK_REFERENCE_LDFLAGS}")
set(blas_found 1)
set(lapack_found 1)
set(REQUIRES_LIBS "${REQUIRES_LIBS} cblas lapack")
message(STATUS "Found BLAS and LAPACK via pkg-config")
return()
endif()
include(CheckTypeSize)
check_type_size( "void*" SIZE_OF_VOID_PTR)
if (SIZE_OF_VOID_PTR EQUAL 8)
set( mkl_search_path
/opt/intel/mkl/*/lib/em64t
/opt/intel/mkl/lib/intel64
/opt/intel/lib/intel64
/opt/intel/mkl/lib
)
find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path})
mark_as_advanced(mkl_intel)
else()
set( mkl_search_path
/opt/intel/mkl/*/lib/32
/opt/intel/mkl/lib/ia32
/opt/intel/lib/ia32
)
find_library(mkl_intel mkl_intel ${mkl_search_path})
mark_as_advanced(mkl_intel)
endif()
include(CheckLibraryExists)
# Get mkl_include_dir
set(mkl_include_search_path
/opt/intel/mkl/include
/opt/intel/include
)
find_path(mkl_include_dir mkl_version.h ${mkl_include_search_path})
mark_as_advanced(mkl_include_dir)
# Search for the needed libraries from the MKL. We will try to link against the mkl_rt
# file first since this way avoids linking bugs in some cases.
find_library(mkl_rt mkl_rt ${mkl_search_path})
find_library(openmp_libraries iomp5 ${mkl_search_path})
mark_as_advanced( mkl_rt openmp_libraries )
# if we found the MKL
if ( mkl_rt)
set(mkl_libraries ${mkl_rt} )
set(blas_libraries ${mkl_rt} )
set(lapack_libraries ${mkl_rt} )
set(blas_found 1)
set(lapack_found 1)
set(found_intel_mkl 1)
message(STATUS "Found Intel MKL BLAS/LAPACK library")
endif()
if (NOT found_intel_mkl)
# Search for the needed libraries from the MKL. This time try looking for a different
# set of MKL files and try to link against those.
find_library(mkl_core mkl_core ${mkl_search_path})
find_library(mkl_thread mkl_intel_thread ${mkl_search_path})
find_library(mkl_iomp iomp5 ${mkl_search_path})
find_library(mkl_pthread pthread ${mkl_search_path})
mark_as_advanced( mkl_intel mkl_core mkl_thread mkl_iomp mkl_pthread)
# If we found the MKL
if (mkl_intel AND mkl_core AND mkl_thread AND mkl_iomp AND mkl_pthread)
set(mkl_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread})
set(blas_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread})
set(lapack_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread})
set(blas_found 1)
set(lapack_found 1)
set(found_intel_mkl 1)
message(STATUS "Found Intel MKL BLAS/LAPACK library")
endif()
endif()
if (found_intel_mkl AND mkl_include_dir)
set(found_intel_mkl_headers 1)
endif()
# try to find some other LAPACK libraries if we didn't find the MKL
set(extra_paths
/usr/lib64
/usr/lib64/atlas-sse3
/usr/lib64/atlas-sse2
/usr/lib64/atlas
/usr/lib
/usr/lib/atlas-sse3
/usr/lib/atlas-sse2
/usr/lib/atlas
/usr/lib/openblas-base
/opt/OpenBLAS/lib
$ENV{OPENBLAS_HOME}/lib
)
INCLUDE (CheckFunctionExists)
if (NOT blas_found)
find_library(cblas_lib openblas PATHS ${extra_paths})
if (cblas_lib)
set(blas_libraries ${cblas_lib})
set(blas_found 1)
message(STATUS "Found OpenBLAS library")
set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries})
# If you compiled OpenBLAS with LAPACK in it then it should have the
# sgetrf_single function in it. So if we find that function in
# OpenBLAS then just use OpenBLAS's LAPACK.
CHECK_FUNCTION_EXISTS(sgetrf_single OPENBLAS_HAS_LAPACK)
if (OPENBLAS_HAS_LAPACK)
message(STATUS "Using OpenBLAS's built in LAPACK")
# set(lapack_libraries gfortran)
set(lapack_found 1)
endif()
endif()
mark_as_advanced( cblas_lib)
endif()
if (NOT lapack_found)
find_library(lapack_lib NAMES lapack lapack-3 PATHS ${extra_paths})
if (lapack_lib)
set(lapack_libraries ${lapack_lib})
set(lapack_found 1)
message(STATUS "Found LAPACK library")
endif()
mark_as_advanced( lapack_lib)
endif()
# try to find some other BLAS libraries if we didn't find the MKL
if (NOT blas_found)
find_library(atlas_lib atlas PATHS ${extra_paths})
find_library(cblas_lib cblas PATHS ${extra_paths})
if (atlas_lib AND cblas_lib)
set(blas_libraries ${atlas_lib} ${cblas_lib})
set(blas_found 1)
message(STATUS "Found ATLAS BLAS library")
endif()
mark_as_advanced( atlas_lib cblas_lib)
endif()
# CentOS 7 atlas
if (NOT blas_found)
find_library(tatlas_lib tatlas PATHS ${extra_paths})
find_library(satlas_lib satlas PATHS ${extra_paths})
if (tatlas_lib AND satlas_lib )
set(blas_libraries ${tatlas_lib} ${satlas_lib})
set(blas_found 1)
message(STATUS "Found ATLAS BLAS library")
endif()
mark_as_advanced( tatlas_lib satlas_lib)
endif()
if (NOT blas_found)
find_library(cblas_lib cblas PATHS ${extra_paths})
if (cblas_lib)
set(blas_libraries ${cblas_lib})
set(blas_found 1)
message(STATUS "Found CBLAS library")
endif()
mark_as_advanced( cblas_lib)
endif()
if (NOT blas_found)
find_library(generic_blas blas PATHS ${extra_paths})
if (generic_blas)
set(blas_libraries ${generic_blas})
set(blas_found 1)
message(STATUS "Found BLAS library")
endif()
mark_as_advanced( generic_blas)
endif()
# Make sure we really found a CBLAS library. That is, it needs to expose
# the proper cblas link symbols. So here we test if one of them is present
# and assume everything is good if it is. Note that we don't do this check if
# we found the Intel MKL since for some reason CHECK_FUNCTION_EXISTS doesn't work
# with it. But it's fine since the MKL should always have cblas.
if (blas_found AND NOT found_intel_mkl)
set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries})
CHECK_FUNCTION_EXISTS(cblas_ddot HAVE_CBLAS)
if (NOT HAVE_CBLAS)
message(STATUS "BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK")
set(blas_found 0)
set(lapack_found 0)
endif()
endif()
elseif(WIN32 AND NOT MINGW)
message(STATUS "Searching for BLAS and LAPACK")
include(CheckTypeSize)
check_type_size( "void*" SIZE_OF_VOID_PTR)
if (SIZE_OF_VOID_PTR EQUAL 8)
set( mkl_search_path
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/lib/intel64"
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/lib/intel64"
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/lib/intel64"
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/lib/intel64"
"C:/Program Files (x86)/Intel/Composer XE/mkl/lib/intel64"
"C:/Program Files (x86)/Intel/Composer XE/compiler/lib/intel64"
"C:/Program Files/Intel/Composer XE/mkl/lib/intel64"
"C:/Program Files/Intel/Composer XE/compiler/lib/intel64"
)
find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path})
else()
set( mkl_search_path
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/lib/ia32"
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/lib/ia32"
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/lib/ia32"
"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/lib/ia32"
"C:/Program Files (x86)/Intel/Composer XE/mkl/lib/ia32"
"C:/Program Files (x86)/Intel/Composer XE/compiler/lib/ia32"
"C:/Program Files/Intel/Composer XE/mkl/lib/ia32"
"C:/Program Files/Intel/Composer XE/compiler/lib/ia32"
)
find_library(mkl_intel mkl_intel_c ${mkl_search_path})
endif()
INCLUDE (CheckFunctionExists)
# Search for the needed libraries from the MKL.
find_library(mkl_core mkl_core ${mkl_search_path})
find_library(mkl_thread mkl_intel_thread ${mkl_search_path})
find_library(mkl_iomp libiomp5md ${mkl_search_path})
mark_as_advanced( mkl_intel mkl_core mkl_thread mkl_iomp)
# If we found the MKL
if (mkl_intel AND mkl_core AND mkl_thread AND mkl_iomp )
set(blas_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} )
set(lapack_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} )
set(blas_found 1)
set(lapack_found 1)
message(STATUS "Found Intel MKL BLAS/LAPACK library")
# Make sure the version of the Intel MKL we found is compatible with
# the compiler we are using. One way to do this check is to see if we can
# link to it right now.
set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries})
CHECK_FUNCTION_EXISTS(cblas_ddot HAVE_CBLAS)
if (NOT HAVE_CBLAS)
message("BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK")
set(blas_found 0)
set(lapack_found 0)
endif()
endif()
endif()
# When all else fails use CMake's built in functions to find BLAS and LAPACK
if (NOT blas_found)
find_package(BLAS QUIET)
if (${BLAS_FOUND})
set(blas_libraries ${BLAS_LIBRARIES})
set(blas_found 1)
if (NOT lapack_found)
find_package(LAPACK QUIET)
if (${LAPACK_FOUND})
set(lapack_libraries ${LAPACK_LIBRARIES})
set(lapack_found 1)
endif()
endif()
endif()
endif()
# If using lapack, determine whether to mangle functions
if (lapack_found)
include(CheckFunctionExists)
include(CheckFortranFunctionExists)
set(CMAKE_REQUIRED_LIBRARIES ${lapack_libraries})
check_function_exists("sgesv" LAPACK_FOUND_C_UNMANGLED)
check_function_exists("sgesv_" LAPACK_FOUND_C_MANGLED)
if (CMAKE_Fortran_COMPILER_LOADED)
check_fortran_function_exists("sgesv" LAPACK_FOUND_FORTRAN_UNMANGLED)
check_fortran_function_exists("sgesv_" LAPACK_FOUND_FORTRAN_MANGLED)
endif ()
if (LAPACK_FOUND_C_MANGLED OR LAPACK_FOUND_FORTRAN_MANGLED)
set(lapack_with_underscore 1)
elseif (LAPACK_FOUND_C_UNMANGLED OR LAPACK_FOUND_FORTRAN_UNMANGLED)
set(lapack_without_underscore 1)
endif ()
endif()
if (UNIX OR MINGW)
if (NOT blas_found)
message(" *****************************************************************************")
message(" *** No BLAS library found so using dlib's built in BLAS. However, if you ***")
message(" *** install an optimized BLAS such as OpenBLAS or the Intel MKL your code ***")
message(" *** will run faster. On Ubuntu you can install OpenBLAS by executing: ***")
message(" *** sudo apt-get install libopenblas-dev liblapack-dev ***")
message(" *** Or you can easily install OpenBLAS from source by downloading the ***")
message(" *** source tar file from http://www.openblas.net, extracting it, and ***")
message(" *** running: ***")
message(" *** make; sudo make install ***")
message(" *****************************************************************************")
endif()
endif()

View File

@@ -0,0 +1,150 @@
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
# Check if we are being built as part of a pybind11 module.
if (COMMAND pybind11_add_module)
# For python users, assume they have SSE4 at least and then if the host machine has AVX use that too.
set(USE_SSE4_INSTRUCTIONS ON CACHE BOOL "Use SSE4 instructions")
include(${CMAKE_CURRENT_LIST_DIR}/check_if_avx_instructions_executable_on_host.cmake)
if (AVX_IS_AVAILABLE_ON_HOST)
set(USE_AVX_INSTRUCTIONS ON CACHE BOOL "Use AVX instructions")
endif()
endif()
set(USING_OLD_VISUAL_STUDIO_COMPILER 0)
if(MSVC AND MSVC_VERSION VERSION_LESS 1900)
message(FATAL_ERROR "C++11 is required to use dlib, but the version of Visual Studio you are using is too old and doesn't support C++11. You need Visual Studio 2015 or newer. ")
elseif(MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.24210.0 )
message(STATUS "NOTE: Visual Studio didn't have good enough C++11 support until Visual Studio 2015 update 3 (v19.0.24210.0)")
message(STATUS "So we aren't enabling things that require full C++11 support (e.g. the deep learning tools).")
message(STATUS "Also, be aware that Visual Studio's version naming is confusing, in particular, there are multiple versions of 'update 3'")
message(STATUS "So if you are getting this message you need to update to the newer version of Visual Studio to use full C++11.")
set(USING_OLD_VISUAL_STUDIO_COMPILER 1)
elseif(MSVC AND (MSVC_VERSION EQUAL 1911 OR MSVC_VERSION EQUAL 1910))
message(STATUS "******************************************************************************************")
message(STATUS "Your version of Visual Studio has incomplete C++11 support and is unable to compile the ")
message(STATUS "DNN examples. So we are disabling the deep learning tools. If you want to use the DNN ")
message(STATUS "tools in dlib then update your copy of Visual Studio.")
message(STATUS "******************************************************************************************")
set(USING_OLD_VISUAL_STUDIO_COMPILER 1)
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_LESS 4.8)
message(FATAL_ERROR "C++11 is required to use dlib, but the version of GCC you are using is too old and doesn't support C++11. You need GCC 4.8 or newer. ")
endif()
endif()
# push USING_OLD_VISUAL_STUDIO_COMPILER to the parent so we can use it in the
# examples CMakeLists.txt file.
get_directory_property(has_parent PARENT_DIRECTORY)
if(has_parent)
set(USING_OLD_VISUAL_STUDIO_COMPILER ${USING_OLD_VISUAL_STUDIO_COMPILER} PARENT_SCOPE)
endif()
set(gcc_like_compilers GNU Clang Intel)
set(intel_archs x86_64 i386 i686 AMD64 amd64 x86)
# Setup some options to allow a user to enable SSE and AVX instruction use.
if ((";${gcc_like_compilers};" MATCHES ";${CMAKE_CXX_COMPILER_ID};") AND
(";${intel_archs};" MATCHES ";${CMAKE_SYSTEM_PROCESSOR};") AND NOT USE_AUTO_VECTOR)
option(USE_SSE2_INSTRUCTIONS "Compile your program with SSE2 instructions" OFF)
option(USE_SSE4_INSTRUCTIONS "Compile your program with SSE4 instructions" OFF)
option(USE_AVX_INSTRUCTIONS "Compile your program with AVX instructions" OFF)
if(USE_AVX_INSTRUCTIONS)
list(APPEND active_compile_opts -mavx)
message(STATUS "Enabling AVX instructions")
elseif (USE_SSE4_INSTRUCTIONS)
list(APPEND active_compile_opts -msse4)
message(STATUS "Enabling SSE4 instructions")
elseif(USE_SSE2_INSTRUCTIONS)
list(APPEND active_compile_opts -msse2)
message(STATUS "Enabling SSE2 instructions")
endif()
elseif (MSVC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # else if using Visual Studio
# Use SSE2 by default when using Visual Studio.
option(USE_SSE2_INSTRUCTIONS "Compile your program with SSE2 instructions" ON)
option(USE_SSE4_INSTRUCTIONS "Compile your program with SSE4 instructions" OFF)
option(USE_AVX_INSTRUCTIONS "Compile your program with AVX instructions" OFF)
include(CheckTypeSize)
check_type_size( "void*" SIZE_OF_VOID_PTR)
if(USE_AVX_INSTRUCTIONS)
list(APPEND active_compile_opts /arch:AVX)
message(STATUS "Enabling AVX instructions")
elseif (USE_SSE4_INSTRUCTIONS)
# Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes.
# So only give it when we are doing a 32 bit build.
if (SIZE_OF_VOID_PTR EQUAL 4)
list(APPEND active_compile_opts /arch:SSE2)
endif()
message(STATUS "Enabling SSE4 instructions")
list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE2")
list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE3")
list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE41")
elseif(USE_SSE2_INSTRUCTIONS)
# Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes.
# So only give it when we are doing a 32 bit build.
if (SIZE_OF_VOID_PTR EQUAL 4)
list(APPEND active_compile_opts /arch:SSE2)
endif()
message(STATUS "Enabling SSE2 instructions")
list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE2")
endif()
elseif((";${gcc_like_compilers};" MATCHES ";${CMAKE_CXX_COMPILER_ID};") AND
("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^arm"))
option(USE_NEON_INSTRUCTIONS "Compile your program with ARM-NEON instructions" OFF)
if(USE_NEON_INSTRUCTIONS)
list(APPEND active_compile_opts -mfpu=neon)
message(STATUS "Enabling ARM-NEON instructions")
endif()
endif()
if (CMAKE_COMPILER_IS_GNUCXX)
# By default, g++ won't warn or error if you forget to return a value in a
# function which requires you to do so. This option makes it give a warning
# for doing this.
list(APPEND active_compile_opts "-Wreturn-type")
endif()
if ("Clang" MATCHES ${CMAKE_CXX_COMPILER_ID})
# Increase clang's default tempalte recurision depth so the dnn examples don't error out.
list(APPEND active_compile_opts "-ftemplate-depth=500")
endif()
if (MSVC)
# By default Visual Studio does not support .obj files with more than 65k sections.
# However, code generated by file_to_code_ex and code using DNN module can have
# them. So this flag enables > 65k sections, but produces .obj files
# that will not be readable by VS 2005.
list(APPEND active_compile_opts "/bigobj")
# Build dlib with all cores. Don't propagate the setting to client programs
# though since they might compile large translation units that use too much
# RAM.
list(APPEND active_compile_opts_private "/MP")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.3)
# Clang can compile all Dlib's code at Windows platform. Tested with Clang 5
list(APPEND active_compile_opts "-Xclang -fcxx-exceptions")
endif()
endif()

View File

@@ -0,0 +1,19 @@
# Including this cmake script into your cmake project will cause visual studio
# to build your project against the static C runtime.
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
if (MSVC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif()
endforeach(flag_var)
endif()

View File

@@ -0,0 +1,113 @@
# This script creates a function, enable_cpp11_for_target(), which checks if your
# compiler has C++11 support and enables it if it does.
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
set(_where_is_cmake_utils_dir ${CMAKE_CURRENT_LIST_DIR})
function(enable_cpp11_for_target target_name)
# Set to false unless we find out otherwise in the code below.
set(COMPILER_CAN_DO_CPP_11 0)
macro(test_compiler_for_cpp11)
message(STATUS "Building a C++11 test project to see if your compiler supports C++11")
try_compile(test_for_cpp11_worked ${PROJECT_BINARY_DIR}/cpp11_test_build
${_where_is_cmake_utils_dir}/test_for_cpp11 cpp11_test)
if (test_for_cpp11_worked)
message(STATUS "C++11 activated.")
set(COMPILER_CAN_DO_CPP_11 1)
else()
set(COMPILER_CAN_DO_CPP_11 0)
message(STATUS "********** Your compiler failed to build a C++11 project. C++11 is required to use all parts of dlib! **********")
endif()
endmacro()
# Now turn on the appropriate compiler switch to enable C++11 if you have a
# C++11 compiler. In CMake 3.1 there is a simple flag you can set, but earlier
# verions of CMake are not so convenient.
if (CMAKE_VERSION VERSION_LESS "3.1.2")
if(CMAKE_COMPILER_IS_GNUCXX)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
message(STATUS "C++11 activated.")
target_compile_options(${target_name} PUBLIC "-std=gnu++11")
set(COMPILER_CAN_DO_CPP_11 1)
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
execute_process( COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE clang_full_version_string )
string (REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION ${clang_full_version_string})
if (CLANG_VERSION VERSION_GREATER 3.3)
message(STATUS "C++11 activated.")
target_compile_options(${target_name} PUBLIC "-std=c++11")
set(COMPILER_CAN_DO_CPP_11 1)
endif()
else()
# Since we don't know what compiler this is just try to build a c++11 project and see if it compiles.
test_compiler_for_cpp11()
endif()
else()
# Set a flag if the compiler you are using is capable of providing C++11 features.
get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
if (";${cxx_features};" MATCHES ";cxx_rvalue_references;" AND
";${cxx_features};" MATCHES ";cxx_variadic_templates;" AND
";${cxx_features};" MATCHES ";cxx_lambdas;" AND
";${cxx_features};" MATCHES ";cxx_defaulted_move_initializers;" AND
";${cxx_features};" MATCHES ";cxx_delegating_constructors;" AND
";${cxx_features};" MATCHES ";cxx_thread_local;" AND
";${cxx_features};" MATCHES ";cxx_constexpr;" AND
";${cxx_features};" MATCHES ";cxx_decltype_incomplete_return_types;" AND
";${cxx_features};" MATCHES ";cxx_auto_type;")
set(COMPILER_CAN_DO_CPP_11 1)
# Tell cmake that we need C++11 for dlib
target_compile_features(${target_name}
PUBLIC
cxx_rvalue_references
cxx_variadic_templates
cxx_lambdas
cxx_defaulted_move_initializers
cxx_delegating_constructors
cxx_thread_local
cxx_constexpr
# cxx_decltype_incomplete_return_types # purposfully commented out because cmake errors out on this when using visual studio and cmake 3.8.0
cxx_auto_type
)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# Sometimes clang will lie and report that it supports C++11 when
# really it doesn't support thread_local. So check for that.
test_compiler_for_cpp11()
else()
message(STATUS "C++11 activated.")
endif()
endif()
endif()
# Always enable whatever partial C++11 support we have, even if it isn't full
# support, and just hope for the best.
if (NOT COMPILER_CAN_DO_CPP_11)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
message(STATUS "C++11 activated (compiler doesn't have full C++11 support).")
target_compile_options(${target_name} PUBLIC "-std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
message(STATUS "C++0x activated (compiler doesn't have full C++11 support).")
target_compile_options(${target_name} PUBLIC "-std=c++0x")
endif()
endif()
endfunction()

View File

@@ -0,0 +1,84 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CMD_LINE_PARSEr_
#define DLIB_CMD_LINE_PARSEr_
#include "cmd_line_parser/cmd_line_parser_kernel_1.h"
#include "cmd_line_parser/cmd_line_parser_kernel_c.h"
#include "cmd_line_parser/cmd_line_parser_print_1.h"
#include "cmd_line_parser/cmd_line_parser_check_1.h"
#include "cmd_line_parser/cmd_line_parser_check_c.h"
#include <string>
#include "cmd_line_parser/get_option.h"
#include "map.h"
#include "sequence.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename charT
>
class impl_cmd_line_parser
{
/*!
This class is basically just a big templated typedef for building
a complete command line parser type out of all the parts it needs.
!*/
impl_cmd_line_parser() {}
typedef typename sequence<std::basic_string<charT> >::kernel_2a sequence_2a;
typedef typename sequence<std::basic_string<charT>*>::kernel_2a psequence_2a;
typedef typename map<std::basic_string<charT>,void*>::kernel_1a map_1a_string;
public:
typedef cmd_line_parser_kernel_1<charT,map_1a_string,sequence_2a,psequence_2a> kernel_1a;
typedef cmd_line_parser_kernel_c<kernel_1a> kernel_1a_c;
typedef cmd_line_parser_print_1<kernel_1a_c> print_1a_c;
typedef cmd_line_parser_check_c<cmd_line_parser_check_1<print_1a_c> > check_1a_c;
};
// ----------------------------------------------------------------------------------------
template <
typename charT
>
class cmd_line_parser : public impl_cmd_line_parser<charT>::check_1a_c
{
public:
// These typedefs are here for backwards compatibility with previous versions of dlib.
typedef cmd_line_parser kernel_1a;
typedef cmd_line_parser kernel_1a_c;
typedef cmd_line_parser print_1a;
typedef cmd_line_parser print_1a_c;
typedef cmd_line_parser check_1a;
typedef cmd_line_parser check_1a_c;
};
template <
typename charT
>
inline void swap (
cmd_line_parser<charT>& a,
cmd_line_parser<charT>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
typedef cmd_line_parser<char> command_line_parser;
typedef cmd_line_parser<wchar_t> wcommand_line_parser;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSEr_

View File

@@ -0,0 +1,580 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CMD_LINE_PARSER_CHECk_1_
#define DLIB_CMD_LINE_PARSER_CHECk_1_
#include "cmd_line_parser_kernel_abstract.h"
#include <sstream>
#include <string>
#include "../string.h"
#include <vector>
namespace dlib
{
template <
typename clp_base
>
class cmd_line_parser_check_1 : public clp_base
{
/*!
This extension doesn't add any state.
!*/
public:
typedef typename clp_base::char_type char_type;
typedef typename clp_base::string_type string_type;
// ------------------------------------------------------------------------------------
class cmd_line_check_error : public dlib::error
{
friend class cmd_line_parser_check_1;
cmd_line_check_error(
error_type t,
const string_type& opt_,
const string_type& arg_
) :
dlib::error(t),
opt(opt_),
opt2(),
arg(arg_),
required_opts()
{ set_info_string(); }
cmd_line_check_error(
error_type t,
const string_type& opt_,
const string_type& opt2_,
int // this is just to make this constructor different from the one above
) :
dlib::error(t),
opt(opt_),
opt2(opt2_),
arg(),
required_opts()
{ set_info_string(); }
cmd_line_check_error (
error_type t,
const string_type& opt_,
const std::vector<string_type>& vect
) :
dlib::error(t),
opt(opt_),
opt2(),
arg(),
required_opts(vect)
{ set_info_string(); }
cmd_line_check_error(
error_type t,
const string_type& opt_
) :
dlib::error(t),
opt(opt_),
opt2(),
arg(),
required_opts()
{ set_info_string(); }
~cmd_line_check_error() throw() {}
void set_info_string (
)
{
std::ostringstream sout;
switch (type)
{
case EINVALID_OPTION_ARG:
sout << "Command line error: '" << narrow(arg) << "' is not a valid argument to "
<< "the '" << narrow(opt) << "' option.";
break;
case EMISSING_REQUIRED_OPTION:
if (required_opts.size() == 1)
{
sout << "Command line error: The '" << narrow(opt) << "' option requires the presence of "
<< "the '" << required_opts[0] << "' option.";
}
else
{
sout << "Command line error: The '" << narrow(opt) << "' option requires the presence of "
<< "one of the following options: ";
for (unsigned long i = 0; i < required_opts.size(); ++i)
{
if (i == required_opts.size()-2)
sout << "'" << required_opts[i] << "' or ";
else if (i == required_opts.size()-1)
sout << "'" << required_opts[i] << "'.";
else
sout << "'" << required_opts[i] << "', ";
}
}
break;
case EINCOMPATIBLE_OPTIONS:
sout << "Command line error: The '" << narrow(opt) << "' and '" << narrow(opt2)
<< "' options cannot be given together on the command line.";
break;
case EMULTIPLE_OCCURANCES:
sout << "Command line error: The '" << narrow(opt) << "' option can only "
<< "be given on the command line once.";
break;
default:
sout << "Command line error.";
break;
}
const_cast<std::string&>(info) = wrap_string(sout.str(),0,0);
}
public:
const string_type opt;
const string_type opt2;
const string_type arg;
const std::vector<string_type> required_opts;
};
// ------------------------------------------------------------------------------------
template <
typename T
>
void check_option_arg_type (
const string_type& option_name
) const;
template <
typename T
>
void check_option_arg_range (
const string_type& option_name,
const T& first,
const T& last
) const;
template <
typename T,
size_t length
>
void check_option_arg_range (
const string_type& option_name,
const T (&arg_set)[length]
) const;
template <
size_t length
>
void check_option_arg_range (
const string_type& option_name,
const char_type* (&arg_set)[length]
) const;
template <
size_t length
>
void check_incompatible_options (
const char_type* (&option_set)[length]
) const;
template <
size_t length
>
void check_one_time_options (
const char_type* (&option_set)[length]
) const;
void check_incompatible_options (
const string_type& option_name1,
const string_type& option_name2
) const;
void check_sub_option (
const string_type& parent_option,
const string_type& sub_option
) const;
template <
size_t length
>
void check_sub_options (
const string_type& parent_option,
const char_type* (&sub_option_set)[length]
) const;
template <
size_t length
>
void check_sub_options (
const char_type* (&parent_option_set)[length],
const string_type& sub_option
) const;
template <
size_t parent_length,
size_t sub_length
>
void check_sub_options (
const char_type* (&parent_option_set)[parent_length],
const char_type* (&sub_option_set)[sub_length]
) const;
};
template <
typename clp_base
>
inline void swap (
cmd_line_parser_check_1<clp_base>& a,
cmd_line_parser_check_1<clp_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template <typename T>
void cmd_line_parser_check_1<clp_base>::
check_option_arg_type (
const string_type& option_name
) const
{
try
{
const typename clp_base::option_type& opt = this->option(option_name);
const unsigned long number_of_arguments = opt.number_of_arguments();
const unsigned long count = opt.count();
for (unsigned long i = 0; i < number_of_arguments; ++i)
{
for (unsigned long j = 0; j < count; ++j)
{
string_cast<T>(opt.argument(i,j));
}
}
}
catch (string_cast_error& e)
{
throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info);
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template <typename T>
void cmd_line_parser_check_1<clp_base>::
check_option_arg_range (
const string_type& option_name,
const T& first,
const T& last
) const
{
try
{
const typename clp_base::option_type& opt = this->option(option_name);
const unsigned long number_of_arguments = opt.number_of_arguments();
const unsigned long count = opt.count();
for (unsigned long i = 0; i < number_of_arguments; ++i)
{
for (unsigned long j = 0; j < count; ++j)
{
T temp(string_cast<T>(opt.argument(i,j)));
if (temp < first || last < temp)
{
throw cmd_line_check_error(
EINVALID_OPTION_ARG,
option_name,
opt.argument(i,j)
);
}
}
}
}
catch (string_cast_error& e)
{
throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info);
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < typename T, size_t length >
void cmd_line_parser_check_1<clp_base>::
check_option_arg_range (
const string_type& option_name,
const T (&arg_set)[length]
) const
{
try
{
const typename clp_base::option_type& opt = this->option(option_name);
const unsigned long number_of_arguments = opt.number_of_arguments();
const unsigned long count = opt.count();
for (unsigned long i = 0; i < number_of_arguments; ++i)
{
for (unsigned long j = 0; j < count; ++j)
{
T temp(string_cast<T>(opt.argument(i,j)));
size_t k = 0;
for (; k < length; ++k)
{
if (arg_set[k] == temp)
break;
}
if (k == length)
{
throw cmd_line_check_error(
EINVALID_OPTION_ARG,
option_name,
opt.argument(i,j)
);
}
}
}
}
catch (string_cast_error& e)
{
throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info);
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < size_t length >
void cmd_line_parser_check_1<clp_base>::
check_option_arg_range (
const string_type& option_name,
const char_type* (&arg_set)[length]
) const
{
const typename clp_base::option_type& opt = this->option(option_name);
const unsigned long number_of_arguments = opt.number_of_arguments();
const unsigned long count = opt.count();
for (unsigned long i = 0; i < number_of_arguments; ++i)
{
for (unsigned long j = 0; j < count; ++j)
{
size_t k = 0;
for (; k < length; ++k)
{
if (arg_set[k] == opt.argument(i,j))
break;
}
if (k == length)
{
throw cmd_line_check_error(
EINVALID_OPTION_ARG,
option_name,
opt.argument(i,j)
);
}
}
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < size_t length >
void cmd_line_parser_check_1<clp_base>::
check_incompatible_options (
const char_type* (&option_set)[length]
) const
{
for (size_t i = 0; i < length; ++i)
{
for (size_t j = i+1; j < length; ++j)
{
if (this->option(option_set[i]).count() > 0 &&
this->option(option_set[j]).count() > 0 )
{
throw cmd_line_check_error(
EINCOMPATIBLE_OPTIONS,
option_set[i],
option_set[j],
0 // this argument has no meaning and is only here to make this
// call different from the other constructor
);
}
}
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
void cmd_line_parser_check_1<clp_base>::
check_incompatible_options (
const string_type& option_name1,
const string_type& option_name2
) const
{
if (this->option(option_name1).count() > 0 &&
this->option(option_name2).count() > 0 )
{
throw cmd_line_check_error(
EINCOMPATIBLE_OPTIONS,
option_name1,
option_name2,
0 // this argument has no meaning and is only here to make this
// call different from the other constructor
);
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
void cmd_line_parser_check_1<clp_base>::
check_sub_option (
const string_type& parent_option,
const string_type& sub_option
) const
{
if (this->option(parent_option).count() == 0)
{
if (this->option(sub_option).count() != 0)
{
std::vector<string_type> vect;
vect.resize(1);
vect[0] = parent_option;
throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect);
}
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < size_t length >
void cmd_line_parser_check_1<clp_base>::
check_sub_options (
const string_type& parent_option,
const char_type* (&sub_option_set)[length]
) const
{
if (this->option(parent_option).count() == 0)
{
size_t i = 0;
for (; i < length; ++i)
{
if (this->option(sub_option_set[i]).count() > 0)
break;
}
if (i != length)
{
std::vector<string_type> vect;
vect.resize(1);
vect[0] = parent_option;
throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect);
}
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < size_t length >
void cmd_line_parser_check_1<clp_base>::
check_sub_options (
const char_type* (&parent_option_set)[length],
const string_type& sub_option
) const
{
// first check if the sub_option is present
if (this->option(sub_option).count() > 0)
{
// now check if any of the parents are present
bool parents_present = false;
for (size_t i = 0; i < length; ++i)
{
if (this->option(parent_option_set[i]).count() > 0)
{
parents_present = true;
break;
}
}
if (!parents_present)
{
std::vector<string_type> vect(parent_option_set, parent_option_set+length);
throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect);
}
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < size_t parent_length, size_t sub_length >
void cmd_line_parser_check_1<clp_base>::
check_sub_options (
const char_type* (&parent_option_set)[parent_length],
const char_type* (&sub_option_set)[sub_length]
) const
{
// first check if any of the parent options are present
bool parents_present = false;
for (size_t i = 0; i < parent_length; ++i)
{
if (this->option(parent_option_set[i]).count() > 0)
{
parents_present = true;
break;
}
}
if (!parents_present)
{
// none of these sub options should be present
size_t i = 0;
for (; i < sub_length; ++i)
{
if (this->option(sub_option_set[i]).count() > 0)
break;
}
if (i != sub_length)
{
std::vector<string_type> vect(parent_option_set, parent_option_set+parent_length);
throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect);
}
}
}
// ----------------------------------------------------------------------------------------
template <typename clp_base>
template < size_t length >
void cmd_line_parser_check_1<clp_base>::
check_one_time_options (
const char_type* (&option_set)[length]
) const
{
size_t i = 0;
for (; i < length; ++i)
{
if (this->option(option_set[i]).count() > 1)
break;
}
if (i != length)
{
throw cmd_line_check_error(
EMULTIPLE_OCCURANCES,
option_set[i]
);
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSER_CHECk_1_

View File

@@ -0,0 +1,453 @@
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CMD_LINE_PARSER_CHECk_C_
#define DLIB_CMD_LINE_PARSER_CHECk_C_
#include "cmd_line_parser_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <string>
#include "../interfaces/cmd_line_parser_option.h"
#include "../string.h"
namespace dlib
{
template <
typename clp_check
>
class cmd_line_parser_check_c : public clp_check
{
public:
typedef typename clp_check::char_type char_type;
typedef typename clp_check::string_type string_type;
template <
typename T
>
void check_option_arg_type (
const string_type& option_name
) const;
template <
typename T
>
void check_option_arg_range (
const string_type& option_name,
const T& first,
const T& last
) const;
template <
typename T,
size_t length
>
void check_option_arg_range (
const string_type& option_name,
const T (&arg_set)[length]
) const;
template <
size_t length
>
void check_option_arg_range (
const string_type& option_name,
const char_type* (&arg_set)[length]
) const;
template <
size_t length
>
void check_incompatible_options (
const char_type* (&option_set)[length]
) const;
template <
size_t length
>
void check_one_time_options (
const char_type* (&option_set)[length]
) const;
void check_incompatible_options (
const string_type& option_name1,
const string_type& option_name2
) const;
void check_sub_option (
const string_type& parent_option,
const string_type& sub_option
) const;
template <
size_t length
>
void check_sub_options (
const string_type& parent_option,
const char_type* (&sub_option_set)[length]
) const;
template <
size_t length
>
void check_sub_options (
const char_type* (&parent_option_set)[length],
const string_type& sub_option
) const;
template <
size_t parent_length,
size_t sub_length
>
void check_sub_options (
const char_type* (&parent_option_set)[parent_length],
const char_type* (&sub_option_set)[sub_length]
) const;
};
template <
typename clp_check
>
inline void swap (
cmd_line_parser_check_c<clp_check>& a,
cmd_line_parser_check_c<clp_check>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template <typename T>
void cmd_line_parser_check_c<clp_check>::
check_option_arg_type (
const string_type& option_name
) const
{
COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name),
"\tvoid cmd_line_parser_check::check_option_arg_type()"
<< "\n\tYou must have already parsed the command line and option_name must be valid."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_name: " << option_name
);
clp_check::template check_option_arg_type<T>(option_name);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template <typename T>
void cmd_line_parser_check_c<clp_check>::
check_option_arg_range (
const string_type& option_name,
const T& first,
const T& last
) const
{
COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name) &&
first <= last,
"\tvoid cmd_line_parser_check::check_option_arg_range()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_name: " << option_name
<< "\n\tfirst: " << first
<< "\n\tlast: " << last
);
clp_check::check_option_arg_range(option_name,first,last);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < typename T, size_t length >
void cmd_line_parser_check_c<clp_check>::
check_option_arg_range (
const string_type& option_name,
const T (&arg_set)[length]
) const
{
COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name),
"\tvoid cmd_line_parser_check::check_option_arg_range()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_name: " << option_name
);
clp_check::check_option_arg_range(option_name,arg_set);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < size_t length >
void cmd_line_parser_check_c<clp_check>::
check_option_arg_range (
const string_type& option_name,
const char_type* (&arg_set)[length]
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name),
"\tvoid cmd_line_parser_check::check_option_arg_range()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_name: " << option_name
);
clp_check::check_option_arg_range(option_name,arg_set);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < size_t length >
void cmd_line_parser_check_c<clp_check>::
check_incompatible_options (
const char_type* (&option_set)[length]
) const
{
// make sure requires clause is not broken
for (size_t i = 0; i < length; ++i)
{
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_set[i]),
"\tvoid cmd_line_parser_check::check_incompatible_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_set[i]): " << ((this->option_is_defined(option_set[i]))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_set[i]: " << option_set[i]
<< "\n\ti: " << static_cast<unsigned long>(i)
);
}
clp_check::check_incompatible_options(option_set);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
void cmd_line_parser_check_c<clp_check>::
check_incompatible_options (
const string_type& option_name1,
const string_type& option_name2
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name1) &&
this->option_is_defined(option_name2),
"\tvoid cmd_line_parser_check::check_incompatible_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_name1): " << ((this->option_is_defined(option_name1))?"true":"false")
<< "\n\toption_is_defined(option_name2): " << ((this->option_is_defined(option_name2))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_name1: " << option_name1
<< "\n\toption_name2: " << option_name2
);
clp_check::check_incompatible_options(option_name1,option_name2);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
void cmd_line_parser_check_c<clp_check>::
check_sub_option (
const string_type& parent_option,
const string_type& sub_option
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(parent_option) &&
this->option_is_defined(sub_option),
"\tvoid cmd_line_parser_check::check_sub_option()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\tparsed_line(): " << this->parsed_line()
<< "\n\toption_is_defined(parent_option): " << this->option_is_defined(parent_option)
<< "\n\toption_is_defined(sub_option): " << this->option_is_defined(sub_option)
<< "\n\tparent_option: " << parent_option
<< "\n\tsub_option: " << sub_option
);
clp_check::check_sub_option(parent_option,sub_option);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < size_t length >
void cmd_line_parser_check_c<clp_check>::
check_sub_options (
const string_type& parent_option,
const char_type* (&sub_option_set)[length]
) const
{
// make sure requires clause is not broken
for (size_t i = 0; i < length; ++i)
{
DLIB_CASSERT( this->option_is_defined(sub_option_set[i]),
"\tvoid cmd_line_parser_check::check_sub_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(sub_option_set[i]): "
<< ((this->option_is_defined(sub_option_set[i]))?"true":"false")
<< "\n\tsub_option_set[i]: " << sub_option_set[i]
<< "\n\ti: " << static_cast<unsigned long>(i)
);
}
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(parent_option),
"\tvoid cmd_line_parser_check::check_sub_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(parent_option): " << ((this->option_is_defined(parent_option))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\tparent_option: " << parent_option
);
clp_check::check_sub_options(parent_option,sub_option_set);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < size_t length >
void cmd_line_parser_check_c<clp_check>::
check_sub_options (
const char_type* (&parent_option_set)[length],
const string_type& sub_option
) const
{
// make sure requires clause is not broken
for (size_t i = 0; i < length; ++i)
{
DLIB_CASSERT( this->option_is_defined(parent_option_set[i]),
"\tvoid cmd_line_parser_check::check_sub_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(parent_option_set[i]): "
<< ((this->option_is_defined(parent_option_set[i]))?"true":"false")
<< "\n\tparent_option_set[i]: " << parent_option_set[i]
<< "\n\ti: " << static_cast<unsigned long>(i)
);
}
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(sub_option),
"\tvoid cmd_line_parser_check::check_sub_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(sub_option): " << ((this->option_is_defined(sub_option))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\tsub_option: " << sub_option
);
clp_check::check_sub_options(parent_option_set,sub_option);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < size_t parent_length, size_t sub_length >
void cmd_line_parser_check_c<clp_check>::
check_sub_options (
const char_type* (&parent_option_set)[parent_length],
const char_type* (&sub_option_set)[sub_length]
) const
{
// make sure requires clause is not broken
for (size_t i = 0; i < sub_length; ++i)
{
DLIB_CASSERT( this->option_is_defined(sub_option_set[i]),
"\tvoid cmd_line_parser_check::check_sub_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(sub_option_set[i]): "
<< ((this->option_is_defined(sub_option_set[i]))?"true":"false")
<< "\n\tsub_option_set[i]: " << sub_option_set[i]
<< "\n\ti: " << static_cast<unsigned long>(i)
);
}
for (size_t i = 0; i < parent_length; ++i)
{
DLIB_CASSERT( this->option_is_defined(parent_option_set[i]),
"\tvoid cmd_line_parser_check::check_parent_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(parent_option_set[i]): "
<< ((this->option_is_defined(parent_option_set[i]))?"true":"false")
<< "\n\tparent_option_set[i]: " << parent_option_set[i]
<< "\n\ti: " << static_cast<unsigned long>(i)
);
}
DLIB_CASSERT( this->parsed_line() == true ,
"\tvoid cmd_line_parser_check::check_sub_options()"
<< "\n\tYou must have parsed the command line before you call this function."
<< "\n\tthis: " << this
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
);
clp_check::check_sub_options(parent_option_set,sub_option_set);
}
// ----------------------------------------------------------------------------------------
template <typename clp_check>
template < size_t length >
void cmd_line_parser_check_c<clp_check>::
check_one_time_options (
const char_type* (&option_set)[length]
) const
{
// make sure requires clause is not broken
for (size_t i = 0; i < length; ++i)
{
DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_set[i]),
"\tvoid cmd_line_parser_check::check_one_time_options()"
<< "\n\tSee the requires clause for this function."
<< "\n\tthis: " << this
<< "\n\toption_is_defined(option_set[i]): " << ((this->option_is_defined(option_set[i]))?"true":"false")
<< "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false")
<< "\n\toption_set[i]: " << option_set[i]
<< "\n\ti: " << static_cast<unsigned long>(i)
);
}
clp_check::check_one_time_options(option_set);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSER_CHECk_C_

View File

@@ -0,0 +1,799 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CMD_LINE_PARSER_KERNEl_1_
#define DLIB_CMD_LINE_PARSER_KERNEl_1_
#include "cmd_line_parser_kernel_abstract.h"
#include "../algs.h"
#include <string>
#include <sstream>
#include "../interfaces/enumerable.h"
#include "../interfaces/cmd_line_parser_option.h"
#include "../assert.h"
#include "../string.h"
namespace dlib
{
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
class cmd_line_parser_kernel_1 : public enumerable<cmd_line_parser_option<charT> >
{
/*!
REQUIREMENTS ON map
is an implementation of map/map_kernel_abstract.h
is instantiated to map items of type std::basic_string<charT> to void*
REQUIREMENTS ON sequence
is an implementation of sequence/sequence_kernel_abstract.h and
is instantiated with std::basic_string<charT>
REQUIREMENTS ON sequence2
is an implementation of sequence/sequence_kernel_abstract.h and
is instantiated with std::basic_string<charT>*
INITIAL VALUE
options.size() == 0
argv.size() == 0
have_parsed_line == false
CONVENTION
have_parsed_line == parsed_line()
argv[index] == operator[](index)
argv.size() == number_of_arguments()
*((option_t*)options[name]) == option(name)
options.is_in_domain(name) == option_is_defined(name)
!*/
public:
typedef charT char_type;
typedef std::basic_string<charT> string_type;
typedef cmd_line_parser_option<charT> option_type;
// exception class
class cmd_line_parse_error : public dlib::error
{
void set_info_string (
)
{
std::ostringstream sout;
switch (type)
{
case EINVALID_OPTION:
sout << "Command line error: '" << narrow(item) << "' is not a valid option.";
break;
case ETOO_FEW_ARGS:
if (num > 1)
{
sout << "Command line error: The '" << narrow(item) << "' option requires " << num
<< " arguments.";
}
else
{
sout << "Command line error: The '" << narrow(item) << "' option requires " << num
<< " argument.";
}
break;
case ETOO_MANY_ARGS:
sout << "Command line error: The '" << narrow(item) << "' option does not take any arguments.\n";
break;
default:
sout << "Command line error.";
break;
}
const_cast<std::string&>(info) = wrap_string(sout.str(),0,0);
}
public:
cmd_line_parse_error(
error_type t,
const std::basic_string<charT>& _item
) :
dlib::error(t),
item(_item),
num(0)
{ set_info_string();}
cmd_line_parse_error(
error_type t,
const std::basic_string<charT>& _item,
unsigned long _num
) :
dlib::error(t),
item(_item),
num(_num)
{ set_info_string();}
cmd_line_parse_error(
) :
dlib::error(),
item(),
num(0)
{ set_info_string();}
~cmd_line_parse_error() throw() {}
const std::basic_string<charT> item;
const unsigned long num;
};
private:
class option_t : public cmd_line_parser_option<charT>
{
/*!
INITIAL VALUE
options.size() == 0
CONVENTION
name_ == name()
description_ == description()
number_of_arguments_ == number_of_arguments()
options[N][arg] == argument(arg,N)
num_present == count()
!*/
friend class cmd_line_parser_kernel_1<charT,map,sequence,sequence2>;
public:
const std::basic_string<charT>& name (
) const { return name_; }
const std::basic_string<charT>& group_name (
) const { return group_name_; }
const std::basic_string<charT>& description (
) const { return description_; }
unsigned long number_of_arguments(
) const { return number_of_arguments_; }
unsigned long count (
) const { return num_present; }
const std::basic_string<charT>& argument (
unsigned long arg,
unsigned long N
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( N < count() && arg < number_of_arguments(),
"\tconst string_type& cmd_line_parser_option::argument(unsigned long,unsigned long)"
<< "\n\tInvalid arguments were given to this function."
<< "\n\tthis: " << this
<< "\n\tN: " << N
<< "\n\targ: " << arg
<< "\n\tname(): " << narrow(name())
<< "\n\tcount(): " << count()
<< "\n\tnumber_of_arguments(): " << number_of_arguments()
);
return options[N][arg];
}
protected:
option_t (
) :
num_present(0)
{}
~option_t()
{
clear();
}
private:
void clear()
/*!
ensures
- #count() == 0
- clears everything out of options and frees memory
!*/
{
for (unsigned long i = 0; i < options.size(); ++i)
{
delete [] options[i];
}
options.clear();
num_present = 0;
}
// data members
std::basic_string<charT> name_;
std::basic_string<charT> group_name_;
std::basic_string<charT> description_;
sequence2 options;
unsigned long number_of_arguments_;
unsigned long num_present;
// restricted functions
option_t(option_t&); // copy constructor
option_t& operator=(option_t&); // assignment operator
};
// --------------------------
public:
cmd_line_parser_kernel_1 (
);
virtual ~cmd_line_parser_kernel_1 (
);
void clear(
);
void parse (
int argc,
const charT** argv
);
void parse (
int argc,
charT** argv
)
{
parse(argc, const_cast<const charT**>(argv));
}
bool parsed_line(
) const;
bool option_is_defined (
const string_type& name
) const;
void add_option (
const string_type& name,
const string_type& description,
unsigned long number_of_arguments = 0
);
void set_group_name (
const string_type& group_name
);
string_type get_group_name (
) const { return group_name; }
const cmd_line_parser_option<charT>& option (
const string_type& name
) const;
unsigned long number_of_arguments(
) const;
const string_type& operator[] (
unsigned long index
) const;
void swap (
cmd_line_parser_kernel_1& item
);
// functions from the enumerable interface
bool at_start (
) const { return options.at_start(); }
void reset (
) const { options.reset(); }
bool current_element_valid (
) const { return options.current_element_valid(); }
const cmd_line_parser_option<charT>& element (
) const { return *static_cast<cmd_line_parser_option<charT>*>(options.element().value()); }
cmd_line_parser_option<charT>& element (
) { return *static_cast<cmd_line_parser_option<charT>*>(options.element().value()); }
bool move_next (
) const { return options.move_next(); }
size_t size (
) const { return options.size(); }
private:
// data members
map options;
sequence argv;
bool have_parsed_line;
string_type group_name;
// restricted functions
cmd_line_parser_kernel_1(cmd_line_parser_kernel_1&); // copy constructor
cmd_line_parser_kernel_1& operator=(cmd_line_parser_kernel_1&); // assignment operator
};
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
inline void swap (
cmd_line_parser_kernel_1<charT,map,sequence,sequence2>& a,
cmd_line_parser_kernel_1<charT,map,sequence,sequence2>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
cmd_line_parser_kernel_1 (
) :
have_parsed_line(false)
{
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
~cmd_line_parser_kernel_1 (
)
{
// delete all option_t objects in options
options.reset();
while (options.move_next())
{
delete static_cast<option_t*>(options.element().value());
}
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
clear(
)
{
have_parsed_line = false;
argv.clear();
// delete all option_t objects in options
options.reset();
while (options.move_next())
{
delete static_cast<option_t*>(options.element().value());
}
options.clear();
reset();
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
parse (
int argc_,
const charT** argv
)
{
using namespace std;
// make sure there aren't any arguments hanging around from the last time
// parse was called
this->argv.clear();
// make sure that the options have been cleared of any arguments since
// the last time parse() was called
if (have_parsed_line)
{
options.reset();
while (options.move_next())
{
static_cast<option_t*>(options.element().value())->clear();
}
options.reset();
}
// this tells us if we have seen -- on the command line all by itself
// or not.
bool escape = false;
const unsigned long argc = static_cast<unsigned long>(argc_);
try
{
for (unsigned long i = 1; i < argc; ++i)
{
if (argv[i][0] == _dT(charT,'-') && !escape)
{
// we are looking at the start of an option
// --------------------------------------------------------------------
if (argv[i][1] == _dT(charT,'-'))
{
// we are looking at the start of a "long named" option
string_type temp = &argv[i][2];
string_type first_argument;
typename string_type::size_type pos = temp.find_first_of(_dT(charT,'='));
// This variable will be 1 if there is an argument supplied via the = sign
// and 0 otherwise.
unsigned long extra_argument = 0;
if (pos != string_type::npos)
{
// there should be an extra argument
extra_argument = 1;
first_argument = temp.substr(pos+1);
temp = temp.substr(0,pos);
}
// make sure this name is defined
if (!options.is_in_domain(temp))
{
// the long name is not a valid option
if (argv[i][2] == _dT(charT,'\0'))
{
// there was nothing after the -- on the command line
escape = true;
continue;
}
else
{
// there was something after the command line but it
// wasn't a valid option
throw cmd_line_parse_error(EINVALID_OPTION,temp);
}
}
option_t* o = static_cast<option_t*>(options[temp]);
// check the number of arguments after this option and make sure
// it is correct
if (argc + extra_argument <= o->number_of_arguments() + i)
{
// there are too few arguments
throw cmd_line_parse_error(ETOO_FEW_ARGS,temp,o->number_of_arguments());
}
if (extra_argument && first_argument.size() == 0 )
{
// if there would be exactly the right number of arguments if
// the first_argument wasn't empty
if (argc == o->number_of_arguments() + i)
throw cmd_line_parse_error(ETOO_FEW_ARGS,temp,o->number_of_arguments());
else
{
// in this case we just ignore the trailing = and parse everything
// the same.
extra_argument = 0;
}
}
// you can't force an option that doesn't have any arguments to take
// one by using the --option=arg syntax
if (extra_argument == 1 && o->number_of_arguments() == 0)
{
throw cmd_line_parse_error(ETOO_MANY_ARGS,temp);
}
// at this point we know that the option is ok and we should
// populate its options object
if (o->number_of_arguments() > 0)
{
string_type* stemp = new string_type[o->number_of_arguments()];
unsigned long j = 0;
// add the argument after the = sign if one is present
if (extra_argument)
{
stemp[0] = first_argument;
++j;
}
for (; j < o->number_of_arguments(); ++j)
{
stemp[j] = argv[i+j+1-extra_argument];
}
o->options.add(o->options.size(),stemp);
}
o->num_present += 1;
// adjust the value of i to account for the arguments to
// this option
i += o->number_of_arguments() - extra_argument;
}
// --------------------------------------------------------------------
else
{
// we are looking at the start of a list of a single char options
// make sure there is something in this string other than -
if (argv[i][1] == _dT(charT,'\0'))
{
throw cmd_line_parse_error();
}
string_type temp = &argv[i][1];
const typename string_type::size_type num = temp.size();
for (unsigned long k = 0; k < num; ++k)
{
string_type name;
// Doing this instead of name = temp[k] seems to avoid a bug in g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
// which results in name[0] having the wrong value.
name.resize(1);
name[0] = temp[k];
// make sure this name is defined
if (!options.is_in_domain(name))
{
// the name is not a valid option
throw cmd_line_parse_error(EINVALID_OPTION,name);
}
option_t* o = static_cast<option_t*>(options[name]);
// if there are chars immediately following this option
int delta = 0;
if (num != k+1)
{
delta = 1;
}
// check the number of arguments after this option and make sure
// it is correct
if (argc + delta <= o->number_of_arguments() + i)
{
// there are too few arguments
std::ostringstream sout;
throw cmd_line_parse_error(ETOO_FEW_ARGS,name,o->number_of_arguments());
}
o->num_present += 1;
// at this point we know that the option is ok and we should
// populate its options object
if (o->number_of_arguments() > 0)
{
string_type* stemp = new string_type[o->number_of_arguments()];
if (delta == 1)
{
temp = &argv[i][2+k];
k = (unsigned long)num; // this ensures that the argument to this
// option isn't going to be treated as a
// list of options
stemp[0] = temp;
}
for (unsigned long j = 0; j < o->number_of_arguments()-delta; ++j)
{
stemp[j+delta] = argv[i+j+1];
}
o->options.add(o->options.size(),stemp);
// adjust the value of i to account for the arguments to
// this option
i += o->number_of_arguments()-delta;
}
} // for (unsigned long k = 0; k < num; ++k)
}
// --------------------------------------------------------------------
}
else
{
// this is just a normal argument
string_type temp = argv[i];
this->argv.add(this->argv.size(),temp);
}
}
have_parsed_line = true;
}
catch (...)
{
have_parsed_line = false;
// clear all the option objects
options.reset();
while (options.move_next())
{
static_cast<option_t*>(options.element().value())->clear();
}
options.reset();
throw;
}
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
bool cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
parsed_line(
) const
{
return have_parsed_line;
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
bool cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
option_is_defined (
const string_type& name
) const
{
return options.is_in_domain(name);
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
set_group_name (
const string_type& group_name_
)
{
group_name = group_name_;
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
add_option (
const string_type& name,
const string_type& description,
unsigned long number_of_arguments
)
{
option_t* temp = new option_t;
try
{
temp->name_ = name;
temp->group_name_ = group_name;
temp->description_ = description;
temp->number_of_arguments_ = number_of_arguments;
void* t = temp;
string_type n(name);
options.add(n,t);
}catch (...) { delete temp; throw;}
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
const cmd_line_parser_option<charT>& cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
option (
const string_type& name
) const
{
return *static_cast<cmd_line_parser_option<charT>*>(options[name]);
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
unsigned long cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
number_of_arguments(
) const
{
return argv.size();
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
const std::basic_string<charT>& cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
operator[] (
unsigned long index
) const
{
return argv[index];
}
// ----------------------------------------------------------------------------------------
template <
typename charT,
typename map,
typename sequence,
typename sequence2
>
void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::
swap (
cmd_line_parser_kernel_1<charT,map,sequence,sequence2>& item
)
{
options.swap(item.options);
argv.swap(item.argv);
exchange(have_parsed_line,item.have_parsed_line);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSER_KERNEl_1_

View File

@@ -0,0 +1,673 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_
#ifdef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_
#include "../algs.h"
#include <string>
#include "../interfaces/enumerable.h"
#include "../interfaces/cmd_line_parser_option.h"
#include <vector>
#include <iostream>
namespace dlib
{
template <
typename charT
>
class cmd_line_parser : public enumerable<cmd_line_parser_option<charT> >
{
/*!
REQUIREMENTS ON charT
Must be an integral type suitable for storing characters. (e.g. char
or wchar_t)
INITIAL VALUE
- parsed_line() == false
- option_is_defined(x) == false, for all values of x
- get_group_name() == ""
ENUMERATION ORDER
The enumerator will enumerate over all the options defined in *this
in alphebetical order according to the name of the option.
POINTERS AND REFERENCES TO INTERNAL DATA
parsed_line(), option_is_defined(), option(), number_of_arguments(),
operator[](), and swap() functions do not invalidate pointers or
references to internal data. All other functions have no such guarantee.
WHAT THIS OBJECT REPRESENTS
This object represents a command line parser.
The command lines must match the following BNF.
command_line ::= <program_name> { <options> | <arg> } [ -- {<word>} ]
program_name ::= <word>
arg ::= any <word> that does not start with -
option_arg ::= <sword>
option_name ::= <char>
long_option_name ::= <char> {<char> | - }
options ::= <bword> - <option_name> {<option_name>} {<option_arg>} |
<bword> -- <long_option_name> [=<option_arg>] {<bword> <option_arg>}
char ::= any character other than - or =
word ::= any string from argv where argv is the second
parameter to main()
sword ::= any suffix of a string from argv where argv is the
second parameter to main()
bword ::= This is an empty string which denotes the begining of a
<word>.
Options with arguments:
An option with N arguments will consider the next N swords to be
its arguments.
so for example, if we have an option o that expects 2 arguments
then the following are a few legal examples:
program -o arg1 arg2 general_argument
program -oarg1 arg2 general_argument
arg1 and arg2 are associated with the option o and general_argument
is not.
Arguments not associated with an option:
An argument that is not associated with an option is considered a
general command line argument and is indexed by operator[] defined
by the cmd_line_parser object. Additionally, if the string
"--" appears in the command line all by itself then all words
following it are considered to be general command line arguments.
Consider the following two examples involving a command line and
a cmd_line_parser object called parser.
Example 1:
command line: program general_arg1 -o arg1 arg2 general_arg2
Then the following is true (assuming the o option is defined
and takes 2 arguments).
parser[0] == "general_arg1"
parser[1] == "general_arg2"
parser.number_of_arguments() == 2
parser.option("o").argument(0) == "arg1"
parser.option("o").argument(1) == "arg2"
parser.option("o").count() == 1
Example 2:
command line: program general_arg1 -- -o arg1 arg2 general_arg2
Then the following is true (the -- causes everything following
it to be treated as a general argument).
parser[0] == "general_arg1"
parser[1] == "-o"
parser[2] == "arg1"
parser[3] == "arg2"
parser[4] == "general_arg2"
parser.number_of_arguments() == 5
parser.option("o").count() == 0
!*/
public:
typedef charT char_type;
typedef std::basic_string<charT> string_type;
typedef cmd_line_parser_option<charT> option_type;
// exception class
class cmd_line_parse_error : public dlib::error
{
/*!
GENERAL
This exception is thrown if there is an error detected in a
command line while it is being parsed. You can consult this
object's type and item members to determine the nature of the
error. (note that the type member is inherited from dlib::error).
INTERPRETING THIS EXCEPTION
- if (type == EINVALID_OPTION) then
- There was an undefined option on the command line
- item == The invalid option that was on the command line
- if (type == ETOO_FEW_ARGS) then
- An option was given on the command line but it was not
supplied with the required number of arguments.
- item == The name of this option.
- num == The number of arguments expected by this option.
- if (type == ETOO_MANY_ARGS) then
- An option was given on the command line such as --option=arg
but this option doesn't take any arguments.
- item == The name of this option.
!*/
public:
const std::basic_string<charT> item;
const unsigned long num;
};
// --------------------------
cmd_line_parser (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~cmd_line_parser (
);
/*!
ensures
- all memory associated with *this has been released
!*/
void clear(
);
/*!
ensures
- #*this has its initial value
throws
- std::bad_alloc
if this exception is thrown then #*this is unusable
until clear() is called and succeeds
!*/
void parse (
int argc,
const charT** argv
);
/*!
requires
- argv == an array of strings that was obtained from the second argument
of the function main().
(i.e. argv[0] should be the <program> token, argv[1] should be
an <options> or <arg> token, etc.)
- argc == the number of strings in argv
ensures
- parses the command line given by argc and argv
- #parsed_line() == true
- #at_start() == true
throws
- std::bad_alloc
if this exception is thrown then #*this is unusable until clear()
is called successfully
- cmd_line_parse_error
This exception is thrown if there is an error parsing the command line.
If this exception is thrown then #parsed_line() == false and all
options will have their count() set to 0 but otherwise there will
be no effect (i.e. all registered options will remain registered).
!*/
void parse (
int argc,
charT** argv
);
/*!
This just calls this->parse(argc,argv) and performs the necessary const_cast
on argv.
!*/
bool parsed_line(
) const;
/*!
ensures
- returns true if parse() has been called successfully
- returns false otherwise
!*/
bool option_is_defined (
const string_type& name
) const;
/*!
ensures
- returns true if the option has been added to the parser object
by calling add_option(name).
- returns false otherwise
!*/
void add_option (
const string_type& name,
const string_type& description,
unsigned long number_of_arguments = 0
);
/*!
requires
- parsed_line() == false
- option_is_defined(name) == false
- name does not contain any ' ', '\t', '\n', or '=' characters
- name[0] != '-'
- name.size() > 0
ensures
- #option_is_defined(name) == true
- #at_start() == true
- #option(name).count() == 0
- #option(name).description() == description
- #option(name).number_of_arguments() == number_of_arguments
- #option(name).group_name() == get_group_name()
throws
- std::bad_alloc
if this exception is thrown then the add_option() function has no
effect
!*/
const option_type& option (
const string_type& name
) const;
/*!
requires
- option_is_defined(name) == true
ensures
- returns the option specified by name
!*/
unsigned long number_of_arguments(
) const;
/*!
requires
- parsed_line() == true
ensures
- returns the number of arguments present in the command line.
This count does not include options or their arguments. Only
arguments unrelated to any option are counted.
!*/
const string_type& operator[] (
unsigned long N
) const;
/*!
requires
- parsed_line() == true
- N < number_of_arguments()
ensures
- returns the Nth command line argument
!*/
void swap (
cmd_line_parser& item
);
/*!
ensures
- swaps *this and item
!*/
void print_options (
std::basic_ostream<char_type>& out
) const;
/*!
ensures
- prints all the command line options to out.
- #at_start() == true
throws
- any exception.
if an exception is thrown then #at_start() == true but otherwise
it will have no effect on the state of #*this.
!*/
void print_options (
) const;
/*!
ensures
- prints all the command line options to cout.
- #at_start() == true
throws
- any exception.
if an exception is thrown then #at_start() == true but otherwise
it will have no effect on the state of #*this.
!*/
string_type get_group_name (
) const;
/*!
ensures
- returns the current group name. This is the group new options will be
added into when added via add_option().
- The group name of an option is used by print_options(). In particular,
it groups all options with the same group name together and displays them
under a title containing the text of the group name. This allows you to
group similar options together in the output of print_options().
- A group name of "" (i.e. the empty string) means that no group name is
set.
!*/
void set_group_name (
const string_type& group_name
);
/*!
ensures
- #get_group_name() == group_name
!*/
// -------------------------------------------------------------
// Input Validation Tools
// -------------------------------------------------------------
class cmd_line_check_error : public dlib::error
{
/*!
This is the exception thrown by the check_*() routines if they find a
command line error. The interpretation of the member variables is defined
below in each check_*() routine.
!*/
public:
const string_type opt;
const string_type opt2;
const string_type arg;
const std::vector<string_type> required_opts;
};
template <
typename T
>
void check_option_arg_type (
const string_type& option_name
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(option_name) == true
- T is not a pointer type
ensures
- all the arguments for the given option are convertible
by string_cast<T>() to an object of type T.
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EINVALID_OPTION_ARG
- opt == option_name
- arg == the text of the offending argument
!*/
template <
typename T
>
void check_option_arg_range (
const string_type& option_name,
const T& first,
const T& last
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(option_name) == true
- first <= last
- T is not a pointer type
ensures
- all the arguments for the given option are convertible
by string_cast<T>() to an object of type T and the resulting value is
in the range first to last inclusive.
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EINVALID_OPTION_ARG
- opt == option_name
- arg == the text of the offending argument
!*/
template <
typename T,
size_t length
>
void check_option_arg_range (
const string_type& option_name,
const T (&arg_set)[length]
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(option_name) == true
- T is not a pointer type
ensures
- for each argument to the given option:
- this argument is convertible by string_cast<T>() to an object of
type T and the resulting value is equal to some element in the
arg_set array.
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EINVALID_OPTION_ARG
- opt == option_name
- arg == the text of the offending argument
!*/
template <
size_t length
>
void check_option_arg_range (
const string_type& option_name,
const char_type* (&arg_set)[length]
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(option_name) == true
ensures
- for each argument to the given option:
- there is a string in the arg_set array that is equal to this argument.
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EINVALID_OPTION_ARG
- opt == option_name
- arg == the text of the offending argument
!*/
template <
size_t length
>
void check_one_time_options (
const char_type* (&option_set)[length]
) const;
/*!
requires
- parsed_line() == true
- for all valid i:
- option_is_defined(option_set[i]) == true
ensures
- all the options in the option_set array occur at most once on the
command line.
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EMULTIPLE_OCCURANCES
- opt == the option that occurred more than once on the command line.
!*/
void check_incompatible_options (
const string_type& option_name1,
const string_type& option_name2
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(option_name1) == true
- option_is_defined(option_name2) == true
ensures
- option(option_name1).count() == 0 || option(option_name2).count() == 0
(i.e. at most, only one of the options is currently present)
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EINCOMPATIBLE_OPTIONS
- opt == option_name1
- opt2 == option_name2
!*/
template <
size_t length
>
void check_incompatible_options (
const char_type* (&option_set)[length]
) const;
/*!
requires
- parsed_line() == true
- for all valid i:
- option_is_defined(option_set[i]) == true
ensures
- At most only one of the options in the array option_set has a count()
greater than 0. (i.e. at most, only one of the options is currently present)
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EINCOMPATIBLE_OPTIONS
- opt == One of the incompatible options found.
- opt2 == The next incompatible option found.
!*/
void check_sub_option (
const string_type& parent_option,
const string_type& sub_option
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(parent_option) == true
- option_is_defined(sub_option) == true
ensures
- if (option(parent_option).count() == 0) then
- option(sub_option).count() == 0
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EMISSING_REQUIRED_OPTION
- opt == sub_option.
- required_opts == a vector that contains only parent_option.
!*/
template <
size_t length
>
void check_sub_options (
const char_type* (&parent_option_set)[length],
const string_type& sub_option
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(sub_option) == true
- for all valid i:
- option_is_defined(parent_option_set[i] == true
ensures
- if (option(sub_option).count() > 0) then
- At least one of the options in the array parent_option_set has a count()
greater than 0. (i.e. at least one of the options in parent_option_set
is currently present)
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EMISSING_REQUIRED_OPTION
- opt == the first option from the sub_option that is present.
- required_opts == a vector containing everything from parent_option_set.
!*/
template <
size_t length
>
void check_sub_options (
const string_type& parent_option,
const char_type* (&sub_option_set)[length]
) const;
/*!
requires
- parsed_line() == true
- option_is_defined(parent_option) == true
- for all valid i:
- option_is_defined(sub_option_set[i]) == true
ensures
- if (option(parent_option).count() == 0) then
- for all valid i:
- option(sub_option_set[i]).count() == 0
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EMISSING_REQUIRED_OPTION
- opt == the first option from the sub_option_set that is present.
- required_opts == a vector that contains only parent_option.
!*/
template <
size_t parent_length,
size_t sub_length
>
void check_sub_options (
const char_type* (&parent_option_set)[parent_length],
const char_type* (&sub_option_set)[sub_length]
) const;
/*!
requires
- parsed_line() == true
- for all valid i:
- option_is_defined(parent_option_set[i] == true
- for all valid j:
- option_is_defined(sub_option_set[j]) == true
ensures
- for all valid j:
- if (option(sub_option_set[j]).count() > 0) then
- At least one of the options in the array parent_option_set has a count()
greater than 0. (i.e. at least one of the options in parent_option_set
is currently present)
throws
- std::bad_alloc
- cmd_line_check_error
This exception is thrown if the ensures clause could not be satisfied.
The exception's members will be set as follows:
- type == EMISSING_REQUIRED_OPTION
- opt == the first option from the sub_option_set that is present.
- required_opts == a vector containing everything from parent_option_set.
!*/
private:
// restricted functions
cmd_line_parser(cmd_line_parser&); // copy constructor
cmd_line_parser& operator=(cmd_line_parser&); // assignment operator
};
// -----------------------------------------------------------------------------------------
typedef cmd_line_parser<char> command_line_parser;
typedef cmd_line_parser<wchar_t> wcommand_line_parser;
// -----------------------------------------------------------------------------------------
template <
typename charT
>
inline void swap (
cmd_line_parser<charT>& a,
cmd_line_parser<charT>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// -----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,203 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CMD_LINE_PARSER_KERNEl_C_
#define DLIB_CMD_LINE_PARSER_KERNEl_C_
#include "cmd_line_parser_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <string>
#include "../interfaces/cmd_line_parser_option.h"
#include "../string.h"
namespace dlib
{
template <
typename clp_base
>
class cmd_line_parser_kernel_c : public clp_base
{
public:
typedef typename clp_base::char_type char_type;
typedef typename clp_base::string_type string_type;
typedef typename clp_base::option_type option_type;
void add_option (
const string_type& name,
const string_type& description,
unsigned long number_of_arguments = 0
);
const option_type& option (
const string_type& name
) const;
unsigned long number_of_arguments(
) const;
const option_type& element (
) const;
option_type& element (
);
const string_type& operator[] (
unsigned long N
) const;
};
template <
typename clp_base
>
inline void swap (
cmd_line_parser_kernel_c<clp_base>& a,
cmd_line_parser_kernel_c<clp_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
const typename clp_base::string_type& cmd_line_parser_kernel_c<clp_base>::
operator[] (
unsigned long N
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true && N < number_of_arguments(),
"\tvoid cmd_line_parser::operator[](unsigned long N)"
<< "\n\tYou must specify a valid index N and the parser must have run already."
<< "\n\tthis: " << this
<< "\n\tN: " << N
<< "\n\tparsed_line(): " << this->parsed_line()
<< "\n\tnumber_of_arguments(): " << number_of_arguments()
);
return clp_base::operator[](N);
}
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
void cmd_line_parser_kernel_c<clp_base>::
add_option (
const string_type& name,
const string_type& description,
unsigned long number_of_arguments
)
{
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == false &&
name.size() > 0 &&
this->option_is_defined(name) == false &&
name.find_first_of(_dT(char_type," \t\n=")) == string_type::npos &&
name[0] != '-',
"\tvoid cmd_line_parser::add_option(const string_type&,const string_type&,unsigned long)"
<< "\n\tsee the requires clause of add_option()"
<< "\n\tthis: " << this
<< "\n\tname.size(): " << static_cast<unsigned long>(name.size())
<< "\n\tname: \"" << narrow(name) << "\""
<< "\n\tparsed_line(): " << (this->parsed_line()? "true" : "false")
<< "\n\tis_option_defined(\"" << narrow(name) << "\"): " << (this->option_is_defined(name)? "true" : "false")
);
clp_base::add_option(name,description,number_of_arguments);
}
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
const typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::
option (
const string_type& name
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->option_is_defined(name) == true,
"\toption cmd_line_parser::option(const string_type&)"
<< "\n\tto get an option it must be defined by a call to add_option()"
<< "\n\tthis: " << this
<< "\n\tname: \"" << narrow(name) << "\""
);
return clp_base::option(name);
}
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
unsigned long cmd_line_parser_kernel_c<clp_base>::
number_of_arguments(
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->parsed_line() == true ,
"\tunsigned long cmd_line_parser::number_of_arguments()"
<< "\n\tyou must parse the command line before you can find out how many arguments it has"
<< "\n\tthis: " << this
);
return clp_base::number_of_arguments();
}
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
const typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::
element (
) const
{
// make sure requires clause is not broken
DLIB_CASSERT(this->current_element_valid() == true,
"\tconst cmd_line_parser_option& cmd_line_parser::element()"
<< "\n\tyou can't access the current element if it doesn't exist"
<< "\n\tthis: " << this
);
// call the real function
return clp_base::element();
}
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::
element (
)
{
// make sure requires clause is not broken
DLIB_CASSERT(this->current_element_valid() == true,
"\tcmd_line_parser_option& cmd_line_parser::element()"
<< "\n\tyou can't access the current element if it doesn't exist"
<< "\n\tthis: " << this
);
// call the real function
return clp_base::element();
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSER_KERNEl_C_

View File

@@ -0,0 +1,205 @@
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CMD_LINE_PARSER_PRINt_1_
#define DLIB_CMD_LINE_PARSER_PRINt_1_
#include "cmd_line_parser_kernel_abstract.h"
#include "../algs.h"
#include "../string.h"
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <memory>
namespace dlib
{
template <
typename clp_base
>
class cmd_line_parser_print_1 : public clp_base
{
public:
void print_options (
std::basic_ostream<typename clp_base::char_type>& out
) const;
void print_options (
) const
{
print_options(std::cout);
}
};
template <
typename clp_base
>
inline void swap (
cmd_line_parser_print_1<clp_base>& a,
cmd_line_parser_print_1<clp_base>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename clp_base
>
void cmd_line_parser_print_1<clp_base>::
print_options (
std::basic_ostream<typename clp_base::char_type>& out
) const
{
typedef typename clp_base::char_type ct;
typedef std::basic_string<ct> string;
typedef typename string::size_type size_type;
typedef std::basic_ostringstream<ct> ostringstream;
try
{
size_type max_len = 0;
this->reset();
// this loop here is just the bottom loop but without the print statements.
// I'm doing this to figure out what len should be.
while (this->move_next())
{
size_type len = 0;
len += 3;
if (this->element().name().size() > 1)
{
++len;
}
len += this->element().name().size();
if (this->element().number_of_arguments() == 1)
{
len += 6;
}
else
{
for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i)
{
len += 7;
if (i+1 > 9)
++len;
}
}
len += 3;
if (len < 33)
max_len = std::max(max_len,len);
}
// Make a separate ostringstream for each option group. We are going to write
// the output for each group to a separate ostringstream so that we can keep
// them grouped together in the final output.
std::map<string,std::shared_ptr<ostringstream> > groups;
this->reset();
while(this->move_next())
{
if (!groups[this->element().group_name()])
groups[this->element().group_name()].reset(new ostringstream);
}
this->reset();
while (this->move_next())
{
ostringstream& sout = *groups[this->element().group_name()];
size_type len = 0;
sout << _dT(ct,"\n -");
len += 3;
if (this->element().name().size() > 1)
{
sout << _dT(ct,"-");
++len;
}
sout << this->element().name();
len += this->element().name().size();
if (this->element().number_of_arguments() == 1)
{
sout << _dT(ct," <arg>");
len += 6;
}
else
{
for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i)
{
sout << _dT(ct," <arg") << i+1 << _dT(ct,">");
len += 7;
if (i+1 > 9)
++len;
}
}
sout << _dT(ct," ");
len += 3;
while (len < max_len)
{
++len;
sout << _dT(ct," ");
}
const unsigned long ml = static_cast<unsigned long>(max_len);
// now print the description but make it wrap around nicely if it
// is to long to fit on one line.
if (len <= max_len)
sout << wrap_string(this->element().description(),0,ml);
else
sout << _dT(ct,"\n") << wrap_string(this->element().description(),ml,ml);
}
// Only print out a generic Options: group name if there is an unnamed option
// present.
if (groups.count(string()) == 1)
out << _dT(ct,"Options:");
// Now print everything out
typename std::map<string,std::shared_ptr<ostringstream> >::iterator i;
for (i = groups.begin(); i != groups.end(); ++i)
{
// print the group name if we have one
if (i->first.size() != 0)
{
if (i != groups.begin())
out << _dT(ct,"\n\n");
out << i->first << _dT(ct,":");
}
// print the options in the group
out << i->second->str();
}
out << _dT(ct,"\n\n");
this->reset();
}
catch (...)
{
this->reset();
throw;
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CMD_LINE_PARSER_PRINt_1_

View File

@@ -0,0 +1,181 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_GET_OPTiON_Hh_
#define DLIB_GET_OPTiON_Hh_
#include "get_option_abstract.h"
#include "../string.h"
#include "../is_kind.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class option_parse_error : public error
{
public:
option_parse_error(const std::string& option_string, const std::string& str):
error(EOPTION_PARSE,"Error parsing argument for option '" + option_string + "', offending string is '" + str + "'.") {}
};
// ----------------------------------------------------------------------------------------
template <typename config_reader_type, typename T>
T impl_config_reader_get_option (
const config_reader_type& cr,
const std::string& option_name,
const std::string& full_option_name,
T default_value
)
{
std::string::size_type pos = option_name.find_first_of(".");
if (pos == std::string::npos)
{
if (cr.is_key_defined(option_name))
{
try{ return string_cast<T>(cr[option_name]); }
catch (string_cast_error&) { throw option_parse_error(full_option_name, cr[option_name]); }
}
}
else
{
std::string block_name = option_name.substr(0,pos);
if (cr.is_block_defined(block_name))
{
return impl_config_reader_get_option(cr.block(block_name),
option_name.substr(pos+1),
full_option_name,
default_value);
}
}
return default_value;
}
// ----------------------------------------------------------------------------------------
template <typename cr_type, typename T>
typename enable_if<is_config_reader<cr_type>,T>::type get_option (
const cr_type& cr,
const std::string& option_name,
T default_value
)
{
return impl_config_reader_get_option(cr, option_name, option_name, default_value);
}
// ----------------------------------------------------------------------------------------
template <typename parser_type, typename T>
typename disable_if<is_config_reader<parser_type>,T>::type get_option (
const parser_type& parser,
const std::string& option_name,
T default_value
)
{
// make sure requires clause is not broken
DLIB_ASSERT( parser.option_is_defined(option_name) == true &&
parser.option(option_name).number_of_arguments() == 1,
"\t T get_option()"
<< "\n\t option_name: " << option_name
<< "\n\t parser.option_is_defined(option_name): " << parser.option_is_defined(option_name)
<< "\n\t parser.option(option_name).number_of_arguments(): " << parser.option(option_name).number_of_arguments()
);
if (parser.option(option_name))
{
try
{
default_value = string_cast<T>(parser.option(option_name).argument());
}
catch (string_cast_error&)
{
throw option_parse_error(option_name, parser.option(option_name).argument());
}
}
return default_value;
}
// ----------------------------------------------------------------------------------------
template <typename parser_type, typename cr_type, typename T>
typename disable_if<is_config_reader<parser_type>,T>::type get_option (
const parser_type& parser,
const cr_type& cr,
const std::string& option_name,
T default_value
)
{
// make sure requires clause is not broken
DLIB_ASSERT( parser.option_is_defined(option_name) == true &&
parser.option(option_name).number_of_arguments() == 1,
"\t T get_option()"
<< "\n\t option_name: " << option_name
<< "\n\t parser.option_is_defined(option_name): " << parser.option_is_defined(option_name)
<< "\n\t parser.option(option_name).number_of_arguments(): " << parser.option(option_name).number_of_arguments()
);
if (parser.option(option_name))
return get_option(parser, option_name, default_value);
else
return get_option(cr, option_name, default_value);
}
// ----------------------------------------------------------------------------------------
template <typename parser_type, typename cr_type, typename T>
typename disable_if<is_config_reader<parser_type>,T>::type get_option (
const cr_type& cr,
const parser_type& parser,
const std::string& option_name,
T default_value
)
{
// make sure requires clause is not broken
DLIB_ASSERT( parser.option_is_defined(option_name) == true &&
parser.option(option_name).number_of_arguments() == 1,
"\t T get_option()"
<< "\n\t option_name: " << option_name
<< "\n\t parser.option_is_defined(option_name): " << parser.option_is_defined(option_name)
<< "\n\t parser.option(option_name).number_of_arguments(): " << parser.option(option_name).number_of_arguments()
);
if (parser.option(option_name))
return get_option(parser, option_name, default_value);
else
return get_option(cr, option_name, default_value);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <typename T>
inline std::string get_option (
const T& cr,
const std::string& option_name,
const char* default_value
)
{
return get_option(cr, option_name, std::string(default_value));
}
// ----------------------------------------------------------------------------------------
template <typename T, typename U>
inline std::string get_option (
const T& parser,
const U& cr,
const std::string& option_name,
const char* default_value
)
{
return get_option(parser, cr, option_name, std::string(default_value));
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_GET_OPTiON_Hh_

View File

@@ -0,0 +1,146 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_GET_OPTiON_ABSTRACT_Hh_
#ifdef DLIB_GET_OPTiON_ABSTRACT_Hh_
#inclue <string>
namespace dlib
{
// ----------------------------------------------------------------------------------------
class option_parse_error : public error
{
/*!
WHAT THIS OBJECT REPRESENTS
This is the exception thrown by the get_option() functions. It is
thrown when the option string given by a command line parser or
config reader can't be converted into the type T.
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename config_reader_type,
typename T
>
T get_option (
const config_reader_type& cr,
const std::string& option_name,
T default_value
);
/*!
requires
- T is a type which can be read from an input stream
- config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h
ensures
- option_name is used to index into the given config_reader.
- if (cr contains an entry corresponding to option_name) then
- converts the string value in cr corresponding to option_name into
an object of type T and returns it.
- else
- returns default_value
- The scheme for indexing into cr based on option_name is best
understood by looking at a few examples:
- an option name of "name" corresponds to cr["name"]
- an option name of "block1.name" corresponds to cr.block("block1")["name"]
- an option name of "block1.block2.name" corresponds to cr.block("block1").block("block2")["name"]
throws
- option_parse_error
This exception is thrown if we attempt but fail to convert the string value
in cr into an object of type T.
!*/
// ----------------------------------------------------------------------------------------
template <
typename command_line_parser_type,
typename T
>
T get_option (
const command_line_parser_type& parser,
const std::string& option_name,
T default_value
);
/*!
requires
- parser.option_is_defined(option_name) == true
- parser.option(option_name).number_of_arguments() == 1
- T is a type which can be read from an input stream
- command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h
ensures
- if (parser.option(option_name)) then
- converts parser.option(option_name).argument() into an object
of type T and returns it. That is, the string argument to this
command line option is converted into a T and returned.
- else
- returns default_value
throws
- option_parse_error
This exception is thrown if we attempt but fail to convert the string
argument into an object of type T.
!*/
// ----------------------------------------------------------------------------------------
template <
typename command_line_parser_type,
typename config_reader_type,
typename T
>
T get_option (
const command_line_parser_type& parser,
const config_reader_type& cr,
const std::string& option_name,
T default_value
);
/*!
requires
- parser.option_is_defined(option_name) == true
- parser.option(option_name).number_of_arguments() == 1
- T is a type which can be read from an input stream
- command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h
- config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h
ensures
- if (parser.option(option_name)) then
- returns get_option(parser, option_name, default_value)
- else
- returns get_option(cr, option_name, default_value)
!*/
// ----------------------------------------------------------------------------------------
template <
typename command_line_parser_type,
typename config_reader_type,
typename T
>
T get_option (
const config_reader_type& cr,
const command_line_parser_type& parser,
const std::string& option_name,
T default_value
);
/*!
requires
- parser.option_is_defined(option_name) == true
- parser.option(option_name).number_of_arguments() == 1
- T is a type which can be read from an input stream
- command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h
- config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h
ensures
- if (parser.option(option_name)) then
- returns get_option(parser, option_name, default_value)
- else
- returns get_option(cr, option_name, default_value)
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_GET_OPTiON_ABSTRACT_Hh_

View File

@@ -0,0 +1,133 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAm_
#define DLIB_COMPRESS_STREAm_
#include "compress_stream/compress_stream_kernel_1.h"
#include "compress_stream/compress_stream_kernel_2.h"
#include "compress_stream/compress_stream_kernel_3.h"
#include "conditioning_class.h"
#include "entropy_encoder.h"
#include "entropy_decoder.h"
#include "entropy_encoder_model.h"
#include "entropy_decoder_model.h"
#include "lz77_buffer.h"
#include "sliding_buffer.h"
#include "lzp_buffer.h"
#include "crc32.h"
namespace dlib
{
class compress_stream
{
compress_stream() {}
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_1b fce1;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_1b fcd1;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2b fce2;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2b fcd2;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_3b fce3;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_3b fcd3;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4a fce4a;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4a fcd4a;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4b fce4b;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4b fcd4b;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5a fce5a;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5a fcd5a;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5b fce5b;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5b fcd5b;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5c fce5c;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5c fcd5c;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_6a fce6;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_6a fcd6;
typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2d fce2d;
typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2d fcd2d;
typedef sliding_buffer<unsigned char>::kernel_1a sliding_buffer1;
typedef lz77_buffer::kernel_2a lz77_buffer2a;
typedef lzp_buffer::kernel_1a lzp_buf_1;
typedef lzp_buffer::kernel_2a lzp_buf_2;
typedef entropy_encoder_model<513,entropy_encoder::kernel_2a>::kernel_1b fce_length;
typedef entropy_decoder_model<513,entropy_decoder::kernel_2a>::kernel_1b fcd_length;
typedef entropy_encoder_model<65534,entropy_encoder::kernel_2a>::kernel_1b fce_length_2;
typedef entropy_decoder_model<65534,entropy_decoder::kernel_2a>::kernel_1b fcd_length_2;
typedef entropy_encoder_model<32257,entropy_encoder::kernel_2a>::kernel_1b fce_index;
typedef entropy_decoder_model<32257,entropy_decoder::kernel_2a>::kernel_1b fcd_index;
public:
//----------- kernels ---------------
// kernel_1a
typedef compress_stream_kernel_1 <fce1,fcd1,crc32::kernel_1a>
kernel_1a;
// kernel_1b
typedef compress_stream_kernel_1 <fce2,fcd2,crc32::kernel_1a>
kernel_1b;
// kernel_1c
typedef compress_stream_kernel_1 <fce3,fcd3,crc32::kernel_1a>
kernel_1c;
// kernel_1da
typedef compress_stream_kernel_1 <fce4a,fcd4a,crc32::kernel_1a>
kernel_1da;
// kernel_1ea
typedef compress_stream_kernel_1 <fce5a,fcd5a,crc32::kernel_1a>
kernel_1ea;
// kernel_1db
typedef compress_stream_kernel_1 <fce4b,fcd4b,crc32::kernel_1a>
kernel_1db;
// kernel_1eb
typedef compress_stream_kernel_1 <fce5b,fcd5b,crc32::kernel_1a>
kernel_1eb;
// kernel_1ec
typedef compress_stream_kernel_1 <fce5c,fcd5c,crc32::kernel_1a>
kernel_1ec;
// kernel_2a
typedef compress_stream_kernel_2 <fce2,fcd2,lz77_buffer2a,sliding_buffer1,fce_length,fcd_length,fce_index,fcd_index,crc32::kernel_1a>
kernel_2a;
// kernel_3a
typedef compress_stream_kernel_3 <lzp_buf_1,crc32::kernel_1a,16>
kernel_3a;
// kernel_3b
typedef compress_stream_kernel_3 <lzp_buf_2,crc32::kernel_1a,16>
kernel_3b;
};
}
#endif // DLIB_COMPRESS_STREAm_

View File

@@ -0,0 +1,252 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_1_
#define DLIB_COMPRESS_STREAM_KERNEl_1_
#include "../algs.h"
#include <iostream>
#include <streambuf>
#include <cstdio>
#include "compress_stream_kernel_abstract.h"
namespace dlib
{
template <
typename fce,
typename fcd,
typename crc32
>
class compress_stream_kernel_1
{
/*!
REQUIREMENTS ON fce
is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
the alphabet_size of fce must be 257.
fce and fcd share the same kernel number.
REQUIREMENTS ON fcd
is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
the alphabet_size of fcd must be 257.
fce and fcd share the same kernel number.
REQUIREMENTS ON crc32
is an implementation of crc32/crc32_kernel_abstract.h
INITIAL VALUE
this object has no state
CONVENTION
this object has no state
!*/
const static unsigned long eof_symbol = 256;
public:
class decompression_error : public dlib::error
{
public:
decompression_error(
const char* i
) :
dlib::error(std::string(i))
{}
decompression_error(
const std::string& i
) :
dlib::error(i)
{}
};
compress_stream_kernel_1 (
)
{}
~compress_stream_kernel_1 (
)
{}
void compress (
std::istream& in,
std::ostream& out
) const;
void decompress (
std::istream& in,
std::ostream& out
) const;
private:
// restricted functions
compress_stream_kernel_1(compress_stream_kernel_1&); // copy constructor
compress_stream_kernel_1& operator=(compress_stream_kernel_1&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename fce,
typename fcd,
typename crc32
>
void compress_stream_kernel_1<fce,fcd,crc32>::
compress (
std::istream& in_,
std::ostream& out_
) const
{
std::streambuf::int_type temp;
std::streambuf& in = *in_.rdbuf();
typename fce::entropy_encoder_type coder;
coder.set_stream(out_);
fce model(coder);
crc32 crc;
unsigned long count = 0;
while (true)
{
// write out a known value every 20000 symbols
if (count == 20000)
{
count = 0;
coder.encode(1500,1501,8000);
}
++count;
// get the next character
temp = in.sbumpc();
// if we have hit EOF then encode the marker symbol
if (temp != EOF)
{
// encode the symbol
model.encode(static_cast<unsigned long>(temp));
crc.add(static_cast<unsigned char>(temp));
continue;
}
else
{
model.encode(eof_symbol);
// now write the checksum
unsigned long checksum = crc.get_checksum();
unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);
model.encode(byte1);
model.encode(byte2);
model.encode(byte3);
model.encode(byte4);
break;
}
}
}
// ----------------------------------------------------------------------------------------
template <
typename fce,
typename fcd,
typename crc32
>
void compress_stream_kernel_1<fce,fcd,crc32>::
decompress (
std::istream& in_,
std::ostream& out_
) const
{
std::streambuf& out = *out_.rdbuf();
typename fcd::entropy_decoder_type coder;
coder.set_stream(in_);
fcd model(coder);
unsigned long symbol;
unsigned long count = 0;
crc32 crc;
// decode until we hit the marker symbol
while (true)
{
// make sure this is the value we expect
if (count == 20000)
{
if (coder.get_target(8000) != 1500)
{
throw decompression_error("Error detected in compressed data stream.");
}
count = 0;
coder.decode(1500,1501);
}
++count;
// decode the next symbol
model.decode(symbol);
if (symbol != eof_symbol)
{
crc.add(static_cast<unsigned char>(symbol));
// write this symbol to out
if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))
{
throw std::ios::failure("error occurred in compress_stream_kernel_1::decompress");
}
continue;
}
else
{
// we read eof from the encoded data. now we just have to check the checksum and we are done.
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);
model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);
model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);
model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);
unsigned long checksum = byte1;
checksum <<= 8;
checksum |= byte2;
checksum <<= 8;
checksum |= byte3;
checksum <<= 8;
checksum |= byte4;
if (checksum != crc.get_checksum())
throw decompression_error("Error detected in compressed data stream.");
break;
}
} // while (true)
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_COMPRESS_STREAM_KERNEl_1_

View File

@@ -0,0 +1,431 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_2_
#define DLIB_COMPRESS_STREAM_KERNEl_2_
#include "../algs.h"
#include <iostream>
#include <streambuf>
#include "compress_stream_kernel_abstract.h"
namespace dlib
{
template <
typename fce,
typename fcd,
typename lz77_buffer,
typename sliding_buffer,
typename fce_length,
typename fcd_length,
typename fce_index,
typename fcd_index,
typename crc32
>
class compress_stream_kernel_2
{
/*!
REQUIREMENTS ON fce
is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
the alphabet_size of fce must be 257.
fce and fcd share the same kernel number.
REQUIREMENTS ON fcd
is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
the alphabet_size of fcd must be 257.
fce and fcd share the same kernel number.
REQUIREMENTS ON lz77_buffer
is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h
REQUIREMENTS ON sliding_buffer
is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h
is instantiated with T = unsigned char
REQUIREMENTS ON fce_length
is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
the alphabet_size of fce must be 513. This will be used to encode the length of lz77 matches.
fce_length and fcd share the same kernel number.
REQUIREMENTS ON fcd_length
is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
the alphabet_size of fcd must be 513. This will be used to decode the length of lz77 matches.
fce_length and fcd share the same kernel number.
REQUIREMENTS ON fce_index
is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
the alphabet_size of fce must be 32257. This will be used to encode the index of lz77 matches.
fce_index and fcd share the same kernel number.
REQUIREMENTS ON fcd_index
is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
the alphabet_size of fcd must be 32257. This will be used to decode the index of lz77 matches.
fce_index and fcd share the same kernel number.
REQUIREMENTS ON crc32
is an implementation of crc32/crc32_kernel_abstract.h
INITIAL VALUE
this object has no state
CONVENTION
this object has no state
!*/
const static unsigned long eof_symbol = 256;
public:
class decompression_error : public dlib::error
{
public:
decompression_error(
const char* i
) :
dlib::error(std::string(i))
{}
decompression_error(
const std::string& i
) :
dlib::error(i)
{}
};
compress_stream_kernel_2 (
)
{}
~compress_stream_kernel_2 (
)
{}
void compress (
std::istream& in,
std::ostream& out
) const;
void decompress (
std::istream& in,
std::ostream& out
) const;
private:
// restricted functions
compress_stream_kernel_2(compress_stream_kernel_2&); // copy constructor
compress_stream_kernel_2& operator=(compress_stream_kernel_2&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename fce,
typename fcd,
typename lz77_buffer,
typename sliding_buffer,
typename fce_length,
typename fcd_length,
typename fce_index,
typename fcd_index,
typename crc32
>
void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>::
compress (
std::istream& in_,
std::ostream& out_
) const
{
std::streambuf::int_type temp;
std::streambuf& in = *in_.rdbuf();
typename fce::entropy_encoder_type coder;
coder.set_stream(out_);
fce model(coder);
fce_length model_length(coder);
fce_index model_index(coder);
const unsigned long LOOKAHEAD_LIMIT = 512;
lz77_buffer buffer(15,LOOKAHEAD_LIMIT);
crc32 crc;
unsigned long count = 0;
unsigned long lz77_count = 1; // number of times we used lz77 to encode
unsigned long ppm_count = 1; // number of times we used ppm to encode
while (true)
{
// write out a known value every 20000 symbols
if (count == 20000)
{
count = 0;
coder.encode(150,151,400);
}
++count;
// try to fill the lookahead buffer
if (buffer.get_lookahead_buffer_size() < buffer.get_lookahead_buffer_limit())
{
temp = in.sbumpc();
while (temp != EOF)
{
crc.add(static_cast<unsigned char>(temp));
buffer.add(static_cast<unsigned char>(temp));
if (buffer.get_lookahead_buffer_size() == buffer.get_lookahead_buffer_limit())
break;
temp = in.sbumpc();
}
}
// compute the sum of ppm_count and lz77_count but make sure
// it is less than 65536
unsigned long sum = ppm_count + lz77_count;
if (sum >= 65536)
{
ppm_count >>= 1;
lz77_count >>= 1;
ppm_count |= 1;
lz77_count |= 1;
sum = ppm_count+lz77_count;
}
// if there are still more symbols in the lookahead buffer to encode
if (buffer.get_lookahead_buffer_size() > 0)
{
unsigned long match_index, match_length;
buffer.find_match(match_index,match_length,6);
if (match_length != 0)
{
// signal the decoder that we are using lz77
coder.encode(0,lz77_count,sum);
++lz77_count;
// encode the index and length pair
model_index.encode(match_index);
model_length.encode(match_length);
}
else
{
// signal the decoder that we are using ppm
coder.encode(lz77_count,sum,sum);
++ppm_count;
// encode the symbol using the ppm model
model.encode(buffer.lookahead_buffer(0));
buffer.shift_buffers(1);
}
}
else
{
// signal the decoder that we are using ppm
coder.encode(lz77_count,sum,sum);
model.encode(eof_symbol);
// now write the checksum
unsigned long checksum = crc.get_checksum();
unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);
model.encode(byte1);
model.encode(byte2);
model.encode(byte3);
model.encode(byte4);
break;
}
} // while (true)
}
// ----------------------------------------------------------------------------------------
template <
typename fce,
typename fcd,
typename lz77_buffer,
typename sliding_buffer,
typename fce_length,
typename fcd_length,
typename fce_index,
typename fcd_index,
typename crc32
>
void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>::
decompress (
std::istream& in_,
std::ostream& out_
) const
{
std::streambuf& out = *out_.rdbuf();
typename fcd::entropy_decoder_type coder;
coder.set_stream(in_);
fcd model(coder);
fcd_length model_length(coder);
fcd_index model_index(coder);
unsigned long symbol;
unsigned long count = 0;
sliding_buffer buffer;
buffer.set_size(15);
// Initialize the buffer to all zeros. There is no algorithmic reason to
// do this. But doing so avoids a warning from valgrind so that is why
// I'm doing this.
for (unsigned long i = 0; i < buffer.size(); ++i)
buffer[i] = 0;
crc32 crc;
unsigned long lz77_count = 1; // number of times we used lz77 to encode
unsigned long ppm_count = 1; // number of times we used ppm to encode
bool next_block_lz77;
// decode until we hit the marker symbol
while (true)
{
// make sure this is the value we expect
if (count == 20000)
{
if (coder.get_target(400) != 150)
{
throw decompression_error("Error detected in compressed data stream.");
}
count = 0;
coder.decode(150,151);
}
++count;
// compute the sum of ppm_count and lz77_count but make sure
// it is less than 65536
unsigned long sum = ppm_count + lz77_count;
if (sum >= 65536)
{
ppm_count >>= 1;
lz77_count >>= 1;
ppm_count |= 1;
lz77_count |= 1;
sum = ppm_count+lz77_count;
}
// check if we are decoding a lz77 or ppm block
if (coder.get_target(sum) < lz77_count)
{
coder.decode(0,lz77_count);
next_block_lz77 = true;
++lz77_count;
}
else
{
coder.decode(lz77_count,sum);
next_block_lz77 = false;
++ppm_count;
}
if (next_block_lz77)
{
unsigned long match_length, match_index;
// decode the match index
model_index.decode(match_index);
// decode the match length
model_length.decode(match_length);
match_index += match_length;
buffer.rotate_left(match_length);
for (unsigned long i = 0; i < match_length; ++i)
{
unsigned char ch = buffer[match_index-i];
buffer[match_length-i-1] = ch;
crc.add(ch);
// write this ch to out
if (out.sputc(static_cast<char>(ch)) != static_cast<int>(ch))
{
throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress");
}
}
}
else
{
// decode the next symbol
model.decode(symbol);
if (symbol != eof_symbol)
{
buffer.rotate_left(1);
buffer[0] = static_cast<unsigned char>(symbol);
crc.add(static_cast<unsigned char>(symbol));
// write this symbol to out
if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))
{
throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress");
}
}
else
{
// this was the eof marker symbol so we are done. now check the checksum
// now get the checksum and make sure it matches
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);
model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);
model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);
model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);
unsigned long checksum = byte1;
checksum <<= 8;
checksum |= byte2;
checksum <<= 8;
checksum |= byte3;
checksum <<= 8;
checksum |= byte4;
if (checksum != crc.get_checksum())
throw decompression_error("Error detected in compressed data stream.");
break;
}
}
} // while (true)
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_COMPRESS_STREAM_KERNEl_2_

View File

@@ -0,0 +1,381 @@
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_3_
#define DLIB_COMPRESS_STREAM_KERNEl_3_
#include "../algs.h"
#include "compress_stream_kernel_abstract.h"
#include "../assert.h"
namespace dlib
{
template <
typename lzp_buf,
typename crc32,
unsigned long buffer_size
>
class compress_stream_kernel_3
{
/*!
REQUIREMENTS ON lzp_buf
is an implementation of lzp_buffer/lzp_buffer_kernel_abstract.h
REQUIREMENTS ON buffer_size
10 < buffer_size < 32
REQUIREMENTS ON crc32
is an implementation of crc32/crc32_kernel_abstract.h
INITIAL VALUE
this object has no state
CONVENTION
this object has no state
This implementation uses the lzp_buffer and writes out matches
in a byte aligned format.
!*/
public:
class decompression_error : public dlib::error
{
public:
decompression_error(
const char* i
) :
dlib::error(std::string(i))
{}
decompression_error(
const std::string& i
) :
dlib::error(i)
{}
};
compress_stream_kernel_3 (
)
{
COMPILE_TIME_ASSERT(10 < buffer_size && buffer_size < 32);
}
~compress_stream_kernel_3 (
)
{}
void compress (
std::istream& in,
std::ostream& out
) const;
void decompress (
std::istream& in,
std::ostream& out
) const;
private:
inline void write (
unsigned char symbol
) const
{
if (out->sputn(reinterpret_cast<char*>(&symbol),1)==0)
throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3");
}
inline void decode (
unsigned char& symbol,
unsigned char& flag
) const
{
if (count == 0)
{
if (((size_t)in->sgetn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))
throw decompression_error("Error detected in compressed data stream.");
count = 8;
}
--count;
symbol = buffer[8-count];
flag = buffer[0] >> 7;
buffer[0] <<= 1;
}
inline void encode (
unsigned char symbol,
unsigned char flag
) const
/*!
requires
- 0 <= flag <= 1
ensures
- writes symbol with the given one bit flag
!*/
{
// add this symbol and flag to the buffer
++count;
buffer[0] <<= 1;
buffer[count] = symbol;
buffer[0] |= flag;
if (count == 8)
{
if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))
throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3");
count = 0;
buffer[0] = 0;
}
}
void clear (
) const
/*!
ensures
- resets the buffers
!*/
{
count = 0;
}
void flush (
) const
/*!
ensures
- flushes any data in the buffers to out
!*/
{
if (count != 0)
{
buffer[0] <<= (8-count);
if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))
throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3");
}
}
mutable unsigned int count;
// count tells us how many bytes are buffered in buffer and how many flag
// bit are currently in buffer[0]
mutable unsigned char buffer[9];
// buffer[0] holds the flag bits to be writen.
// the rest of the buffer holds the bytes to be writen.
mutable std::streambuf* in;
mutable std::streambuf* out;
// restricted functions
compress_stream_kernel_3(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&); // copy constructor
compress_stream_kernel_3<lzp_buf,crc32,buffer_size>& operator=(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename lzp_buf,
typename crc32,
unsigned long buffer_size
>
void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>::
compress (
std::istream& in_,
std::ostream& out_
) const
{
in = in_.rdbuf();
out = out_.rdbuf();
clear();
crc32 crc;
lzp_buf buffer(buffer_size);
std::streambuf::int_type temp = in->sbumpc();
unsigned long index;
unsigned char symbol;
unsigned char length;
while (temp != EOF)
{
symbol = static_cast<unsigned char>(temp);
if (buffer.predict_match(index))
{
if (buffer[index] == symbol)
{
// this is a match so we must find out how long it is
length = 1;
buffer.add(symbol);
crc.add(symbol);
temp = in->sbumpc();
while (length < 255)
{
if (temp == EOF)
{
break;
}
else if (static_cast<unsigned long>(length) >= index)
{
break;
}
else if (static_cast<unsigned char>(temp) == buffer[index])
{
++length;
buffer.add(static_cast<unsigned char>(temp));
crc.add(static_cast<unsigned char>(temp));
temp = in->sbumpc();
}
else
{
break;
}
}
encode(length,1);
}
else
{
// this is also not a match
encode(symbol,0);
buffer.add(symbol);
crc.add(symbol);
// get the next symbol
temp = in->sbumpc();
}
}
else
{
// there wasn't a match so just write this symbol
encode(symbol,0);
buffer.add(symbol);
crc.add(symbol);
// get the next symbol
temp = in->sbumpc();
}
}
// use a match of zero length to indicate EOF
encode(0,1);
// now write the checksum
unsigned long checksum = crc.get_checksum();
unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);
encode(byte1,0);
encode(byte2,0);
encode(byte3,0);
encode(byte4,0);
flush();
}
// ----------------------------------------------------------------------------------------
template <
typename lzp_buf,
typename crc32,
unsigned long buffer_size
>
void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>::
decompress (
std::istream& in_,
std::ostream& out_
) const
{
in = in_.rdbuf();
out = out_.rdbuf();
clear();
crc32 crc;
lzp_buf buffer(buffer_size);
unsigned long index = 0;
unsigned char symbol;
unsigned char length;
unsigned char flag;
decode(symbol,flag);
while (flag == 0 || symbol != 0)
{
buffer.predict_match(index);
if (flag == 1)
{
length = symbol;
do
{
--length;
symbol = buffer[index];
write(symbol);
buffer.add(symbol);
crc.add(symbol);
} while (length != 0);
}
else
{
// this is just a literal
write(symbol);
buffer.add(symbol);
crc.add(symbol);
}
decode(symbol,flag);
}
// now get the checksum and make sure it matches
unsigned char byte1;
unsigned char byte2;
unsigned char byte3;
unsigned char byte4;
decode(byte1,flag);
if (flag != 0)
throw decompression_error("Error detected in compressed data stream.");
decode(byte2,flag);
if (flag != 0)
throw decompression_error("Error detected in compressed data stream.");
decode(byte3,flag);
if (flag != 0)
throw decompression_error("Error detected in compressed data stream.");
decode(byte4,flag);
if (flag != 0)
throw decompression_error("Error detected in compressed data stream.");
unsigned long checksum = byte1;
checksum <<= 8;
checksum |= byte2;
checksum <<= 8;
checksum |= byte3;
checksum <<= 8;
checksum |= byte4;
if (checksum != crc.get_checksum())
throw decompression_error("Error detected in compressed data stream.");
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_COMPRESS_STREAM_KERNEl_3_

View File

@@ -0,0 +1,94 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_
#ifdef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_
#include "../algs.h"
#include <iosfwd>
namespace dlib
{
class compress_stream
{
/*!
INITIAL VALUE
This object does not have any state associated with it.
WHAT THIS OBJECT REPRESENTS
This object consists of the two functions compress and decompress.
These functions allow you to compress and decompress data.
!*/
public:
class decompression_error : public dlib::error {};
compress_stream (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~compress_stream (
);
/*!
ensures
- all memory associated with *this has been released
!*/
void compress (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- reads all data from in (until EOF is reached) and compresses it
and writes it to out
throws
- std::ios_base::failure
if there was a problem writing to out then this exception will
be thrown.
- any other exception
this exception may be thrown if there is any other problem
!*/
void decompress (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- reads data from in, decompresses it and writes it to out. note that
it stops reading data from in when it encounters the end of the
compressed data, not when it encounters EOF.
throws
- std::ios_base::failure
if there was a problem writing to out then this exception will
be thrown.
- decompression_error
if an error was detected in the compressed data that prevented
it from being correctly decompressed then this exception is
thrown.
- any other exception
this exception may be thrown if there is any other problem
!*/
private:
// restricted functions
compress_stream(compress_stream&); // copy constructor
compress_stream& operator=(compress_stream&); // assignment operator
};
}
#endif // DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,80 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASs_
#define DLIB_CONDITIONING_CLASs_
#include "conditioning_class/conditioning_class_kernel_1.h"
#include "conditioning_class/conditioning_class_kernel_2.h"
#include "conditioning_class/conditioning_class_kernel_3.h"
#include "conditioning_class/conditioning_class_kernel_4.h"
#include "conditioning_class/conditioning_class_kernel_c.h"
#include "memory_manager.h"
namespace dlib
{
template <
unsigned long alphabet_size
>
class conditioning_class
{
conditioning_class() {}
typedef memory_manager<char>::kernel_2b mm;
public:
//----------- kernels ---------------
// kernel_1a
typedef conditioning_class_kernel_1<alphabet_size>
kernel_1a;
typedef conditioning_class_kernel_c<kernel_1a>
kernel_1a_c;
// kernel_2a
typedef conditioning_class_kernel_2<alphabet_size>
kernel_2a;
typedef conditioning_class_kernel_c<kernel_2a>
kernel_2a_c;
// kernel_3a
typedef conditioning_class_kernel_3<alphabet_size>
kernel_3a;
typedef conditioning_class_kernel_c<kernel_3a>
kernel_3a_c;
// -------- kernel_4 ---------
// kernel_4a
typedef conditioning_class_kernel_4<alphabet_size,10000,mm>
kernel_4a;
typedef conditioning_class_kernel_c<kernel_4a>
kernel_4a_c;
// kernel_4b
typedef conditioning_class_kernel_4<alphabet_size,100000,mm>
kernel_4b;
typedef conditioning_class_kernel_c<kernel_4b>
kernel_4b_c;
// kernel_4c
typedef conditioning_class_kernel_4<alphabet_size,1000000,mm>
kernel_4c;
typedef conditioning_class_kernel_c<kernel_4c>
kernel_4c_c;
// kernel_4d
typedef conditioning_class_kernel_4<alphabet_size,10000000,mm>
kernel_4d;
typedef conditioning_class_kernel_c<kernel_4d>
kernel_4d_c;
};
}
#endif // DLIB_CONDITIONING_CLASS_

View File

@@ -0,0 +1,333 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_1_
#define DLIB_CONDITIONING_CLASS_KERNEl_1_
#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"
namespace dlib
{
template <
unsigned long alphabet_size
>
class conditioning_class_kernel_1
{
/*!
INITIAL VALUE
total == 1
counts == pointer to an array of alphabet_size unsigned shorts
for all i except i == alphabet_size-1: counts[i] == 0
counts[alphabet_size-1] == 1
CONVENTION
counts == pointer to an array of alphabet_size unsigned shorts
get_total() == total
get_count(symbol) == counts[symbol]
LOW_COUNT(symbol) == sum of counts[0] though counts[symbol-1]
or 0 if symbol == 0
get_memory_usage() == global_state.memory_usage
!*/
public:
class global_state_type
{
public:
global_state_type () : memory_usage(0) {}
private:
unsigned long memory_usage;
friend class conditioning_class_kernel_1<alphabet_size>;
};
conditioning_class_kernel_1 (
global_state_type& global_state_
);
~conditioning_class_kernel_1 (
);
void clear(
);
bool increment_count (
unsigned long symbol,
unsigned short amount = 1
);
unsigned long get_count (
unsigned long symbol
) const;
unsigned long get_total (
) const;
unsigned long get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const;
void get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const;
unsigned long get_memory_usage (
) const;
global_state_type& get_global_state (
);
static unsigned long get_alphabet_size (
);
private:
// restricted functions
conditioning_class_kernel_1(conditioning_class_kernel_1<alphabet_size>&); // copy constructor
conditioning_class_kernel_1& operator=(conditioning_class_kernel_1<alphabet_size>&); // assignment operator
// data members
unsigned short total;
unsigned short* counts;
global_state_type& global_state;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
conditioning_class_kernel_1<alphabet_size>::
conditioning_class_kernel_1 (
global_state_type& global_state_
) :
total(1),
counts(new unsigned short[alphabet_size]),
global_state(global_state_)
{
COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );
unsigned short* start = counts;
unsigned short* end = counts+alphabet_size-1;
while (start != end)
{
*start = 0;
++start;
}
*start = 1;
// update memory usage
global_state.memory_usage += sizeof(unsigned short)*alphabet_size +
sizeof(conditioning_class_kernel_1);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
conditioning_class_kernel_1<alphabet_size>::
~conditioning_class_kernel_1 (
)
{
delete [] counts;
// update memory usage
global_state.memory_usage -= sizeof(unsigned short)*alphabet_size +
sizeof(conditioning_class_kernel_1);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
void conditioning_class_kernel_1<alphabet_size>::
clear(
)
{
total = 1;
unsigned short* start = counts;
unsigned short* end = counts+alphabet_size-1;
while (start != end)
{
*start = 0;
++start;
}
*start = 1;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_1<alphabet_size>::
get_memory_usage(
) const
{
return global_state.memory_usage;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
typename conditioning_class_kernel_1<alphabet_size>::global_state_type& conditioning_class_kernel_1<alphabet_size>::
get_global_state(
)
{
return global_state;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
bool conditioning_class_kernel_1<alphabet_size>::
increment_count (
unsigned long symbol,
unsigned short amount
)
{
// if we are going over a total of 65535 then scale down all counts by 2
if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)
{
total = 0;
unsigned short* start = counts;
unsigned short* end = counts+alphabet_size;
while (start != end)
{
*start >>= 1;
total += *start;
++start;
}
// make sure it is at least one
if (counts[alphabet_size-1]==0)
{
++total;
counts[alphabet_size-1] = 1;
}
}
counts[symbol] += amount;
total += amount;
return true;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_1<alphabet_size>::
get_count (
unsigned long symbol
) const
{
return counts[symbol];
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_1<alphabet_size>::
get_alphabet_size (
)
{
return alphabet_size;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_1<alphabet_size>::
get_total (
) const
{
return total;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_1<alphabet_size>::
get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const
{
if (counts[symbol] == 0)
return 0;
total_count = total;
const unsigned short* start = counts;
const unsigned short* end = counts+symbol;
unsigned short high_count_temp = *start;
while (start != end)
{
++start;
high_count_temp += *start;
}
low_count = high_count_temp - *start;
high_count = high_count_temp;
return *start;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
void conditioning_class_kernel_1<alphabet_size>::
get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const
{
unsigned long high_count_temp = *counts;
const unsigned short* start = counts;
while (target >= high_count_temp)
{
++start;
high_count_temp += *start;
}
low_count = high_count_temp - *start;
high_count = high_count_temp;
symbol = static_cast<unsigned long>(start-counts);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_

View File

@@ -0,0 +1,500 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_2_
#define DLIB_CONDITIONING_CLASS_KERNEl_2_
#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"
namespace dlib
{
template <
unsigned long alphabet_size
>
class conditioning_class_kernel_2
{
/*!
INITIAL VALUE
total == 1
symbols == pointer to array of alphabet_size data structs
for all i except i == alphabet_size-1: symbols[i].count == 0
symbols[i].left_count == 0
symbols[alphabet_size-1].count == 1
symbols[alpahbet_size-1].left_count == 0
CONVENTION
symbols == pointer to array of alphabet_size data structs
get_total() == total
get_count(symbol) == symbols[symbol].count
symbols is organized as a tree with symbols[0] as the root.
the left subchild of symbols[i] is symbols[i*2+1] and
the right subchild is symbols[i*2+2].
the partent of symbols[i] == symbols[(i-1)/2]
symbols[i].left_count == the sum of the counts of all the
symbols to the left of symbols[i]
get_memory_usage() == global_state.memory_usage
!*/
public:
class global_state_type
{
public:
global_state_type () : memory_usage(0) {}
private:
unsigned long memory_usage;
friend class conditioning_class_kernel_2<alphabet_size>;
};
conditioning_class_kernel_2 (
global_state_type& global_state_
);
~conditioning_class_kernel_2 (
);
void clear(
);
bool increment_count (
unsigned long symbol,
unsigned short amount = 1
);
unsigned long get_count (
unsigned long symbol
) const;
inline unsigned long get_total (
) const;
unsigned long get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const;
void get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const;
unsigned long get_memory_usage (
) const;
global_state_type& get_global_state (
);
static unsigned long get_alphabet_size (
);
private:
// restricted functions
conditioning_class_kernel_2(conditioning_class_kernel_2<alphabet_size>&); // copy constructor
conditioning_class_kernel_2& operator=(conditioning_class_kernel_2<alphabet_size>&); // assignment operator
// data members
unsigned short total;
struct data
{
unsigned short count;
unsigned short left_count;
};
data* symbols;
global_state_type& global_state;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
conditioning_class_kernel_2<alphabet_size>::
conditioning_class_kernel_2 (
global_state_type& global_state_
) :
total(1),
symbols(new data[alphabet_size]),
global_state(global_state_)
{
COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );
data* start = symbols;
data* end = symbols + alphabet_size-1;
while (start != end)
{
start->count = 0;
start->left_count = 0;
++start;
}
start->count = 1;
start->left_count = 0;
// update the left_counts for the symbol alphabet_size-1
unsigned short temp;
unsigned long symbol = alphabet_size-1;
while (symbol != 0)
{
// temp will be 1 if symbol is odd, 0 if it is even
temp = static_cast<unsigned short>(symbol&0x1);
// set symbol to its parent
symbol = (symbol-1)>>1;
// note that all left subchidren are odd and also that
// if symbol was a left subchild then we want to increment
// its parents left_count
if (temp)
++symbols[symbol].left_count;
}
global_state.memory_usage += sizeof(data)*alphabet_size +
sizeof(conditioning_class_kernel_2);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
conditioning_class_kernel_2<alphabet_size>::
~conditioning_class_kernel_2 (
)
{
delete [] symbols;
global_state.memory_usage -= sizeof(data)*alphabet_size +
sizeof(conditioning_class_kernel_2);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
void conditioning_class_kernel_2<alphabet_size>::
clear(
)
{
data* start = symbols;
data* end = symbols + alphabet_size-1;
total = 1;
while (start != end)
{
start->count = 0;
start->left_count = 0;
++start;
}
start->count = 1;
start->left_count = 0;
// update the left_counts
unsigned short temp;
unsigned long symbol = alphabet_size-1;
while (symbol != 0)
{
// temp will be 1 if symbol is odd, 0 if it is even
temp = static_cast<unsigned short>(symbol&0x1);
// set symbol to its parent
symbol = (symbol-1)>>1;
// note that all left subchidren are odd and also that
// if symbol was a left subchild then we want to increment
// its parents left_count
symbols[symbol].left_count += temp;
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_2<alphabet_size>::
get_memory_usage(
) const
{
return global_state.memory_usage;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
typename conditioning_class_kernel_2<alphabet_size>::global_state_type& conditioning_class_kernel_2<alphabet_size>::
get_global_state(
)
{
return global_state;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
bool conditioning_class_kernel_2<alphabet_size>::
increment_count (
unsigned long symbol,
unsigned short amount
)
{
// if we need to renormalize then do so
if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)
{
unsigned long s;
unsigned short temp;
for (unsigned short i = 0; i < alphabet_size-1; ++i)
{
s = i;
// divide the count for this symbol by 2
symbols[i].count >>= 1;
symbols[i].left_count = 0;
// bubble this change up though the tree
while (s != 0)
{
// temp will be 1 if symbol is odd, 0 if it is even
temp = static_cast<unsigned short>(s&0x1);
// set s to its parent
s = (s-1)>>1;
// note that all left subchidren are odd and also that
// if s was a left subchild then we want to increment
// its parents left_count
if (temp)
symbols[s].left_count += symbols[i].count;
}
}
// update symbols alphabet_size-1
{
s = alphabet_size-1;
// divide alphabet_size-1 symbol by 2 if it's > 1
if (symbols[alphabet_size-1].count > 1)
symbols[alphabet_size-1].count >>= 1;
// bubble this change up though the tree
while (s != 0)
{
// temp will be 1 if symbol is odd, 0 if it is even
temp = static_cast<unsigned short>(s&0x1);
// set s to its parent
s = (s-1)>>1;
// note that all left subchidren are odd and also that
// if s was a left subchild then we want to increment
// its parents left_count
if (temp)
symbols[s].left_count += symbols[alphabet_size-1].count;
}
}
// calculate the new total
total = 0;
unsigned long m = 0;
while (m < alphabet_size)
{
total += symbols[m].count + symbols[m].left_count;
m = (m<<1) + 2;
}
}
// increment the count for the specified symbol
symbols[symbol].count += amount;;
total += amount;
unsigned short temp;
while (symbol != 0)
{
// temp will be 1 if symbol is odd, 0 if it is even
temp = static_cast<unsigned short>(symbol&0x1);
// set symbol to its parent
symbol = (symbol-1)>>1;
// note that all left subchidren are odd and also that
// if symbol was a left subchild then we want to increment
// its parents left_count
if (temp)
symbols[symbol].left_count += amount;
}
return true;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_2<alphabet_size>::
get_count (
unsigned long symbol
) const
{
return symbols[symbol].count;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_2<alphabet_size>::
get_alphabet_size (
)
{
return alphabet_size;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_2<alphabet_size>::
get_total (
) const
{
return total;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_2<alphabet_size>::
get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const
{
if (symbols[symbol].count == 0)
return 0;
unsigned long current = symbol;
total_count = total;
unsigned long high_count_temp = 0;
bool came_from_right = true;
while (true)
{
if (came_from_right)
{
high_count_temp += symbols[current].count + symbols[current].left_count;
}
// note that if current is even then it is a right child
came_from_right = !(current&0x1);
if (current == 0)
break;
// set current to its parent
current = (current-1)>>1 ;
}
low_count = high_count_temp - symbols[symbol].count;
high_count = high_count_temp;
return symbols[symbol].count;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
void conditioning_class_kernel_2<alphabet_size>::
get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const
{
unsigned long current = 0;
unsigned long low_count_temp = 0;
while (true)
{
if (static_cast<unsigned short>(target) < symbols[current].left_count)
{
// we should go left
current = (current<<1) + 1;
}
else
{
target -= symbols[current].left_count;
low_count_temp += symbols[current].left_count;
if (static_cast<unsigned short>(target) < symbols[current].count)
{
// we have found our target
symbol = current;
high_count = low_count_temp + symbols[current].count;
low_count = low_count_temp;
break;
}
else
{
// go right
target -= symbols[current].count;
low_count_temp += symbols[current].count;
current = (current<<1) + 2;
}
}
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_

View File

@@ -0,0 +1,438 @@
// Copyright (C) 2004 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_3_
#define DLIB_CONDITIONING_CLASS_KERNEl_3_
#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"
namespace dlib
{
template <
unsigned long alphabet_size
>
class conditioning_class_kernel_3
{
/*!
INITIAL VALUE
total == 1
counts == pointer to an array of alphabet_size data structs
for all i except i == 0: counts[i].count == 0
counts[0].count == 1
counts[0].symbol == alphabet_size-1
for all i except i == alphabet_size-1: counts[i].present == false
counts[alphabet_size-1].present == true
CONVENTION
counts == pointer to an array of alphabet_size data structs
get_total() == total
get_count(symbol) == counts[x].count where
counts[x].symbol == symbol
LOW_COUNT(symbol) == sum of counts[0].count though counts[x-1].count
where counts[x].symbol == symbol
if (counts[0].symbol == symbol) LOW_COUNT(symbol)==0
if (counts[i].count == 0) then
counts[i].symbol == undefined value
if (symbol has a nonzero count) then
counts[symbol].present == true
get_memory_usage() == global_state.memory_usage
!*/
public:
class global_state_type
{
public:
global_state_type () : memory_usage(0) {}
private:
unsigned long memory_usage;
friend class conditioning_class_kernel_3<alphabet_size>;
};
conditioning_class_kernel_3 (
global_state_type& global_state_
);
~conditioning_class_kernel_3 (
);
void clear(
);
bool increment_count (
unsigned long symbol,
unsigned short amount = 1
);
unsigned long get_count (
unsigned long symbol
) const;
unsigned long get_total (
) const;
unsigned long get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const;
void get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const;
unsigned long get_memory_usage (
) const;
global_state_type& get_global_state (
);
static unsigned long get_alphabet_size (
);
private:
// restricted functions
conditioning_class_kernel_3(conditioning_class_kernel_3<alphabet_size>&); // copy constructor
conditioning_class_kernel_3& operator=(conditioning_class_kernel_3<alphabet_size>&); // assignment operator
struct data
{
unsigned short count;
unsigned short symbol;
bool present;
};
// data members
unsigned short total;
data* counts;
global_state_type& global_state;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
conditioning_class_kernel_3<alphabet_size>::
conditioning_class_kernel_3 (
global_state_type& global_state_
) :
total(1),
counts(new data[alphabet_size]),
global_state(global_state_)
{
COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );
data* start = counts;
data* end = counts+alphabet_size;
start->count = 1;
start->symbol = alphabet_size-1;
start->present = false;
++start;
while (start != end)
{
start->count = 0;
start->present = false;
++start;
}
counts[alphabet_size-1].present = true;
// update memory usage
global_state.memory_usage += sizeof(data)*alphabet_size +
sizeof(conditioning_class_kernel_3);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
conditioning_class_kernel_3<alphabet_size>::
~conditioning_class_kernel_3 (
)
{
delete [] counts;
// update memory usage
global_state.memory_usage -= sizeof(data)*alphabet_size +
sizeof(conditioning_class_kernel_3);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
void conditioning_class_kernel_3<alphabet_size>::
clear(
)
{
total = 1;
data* start = counts;
data* end = counts+alphabet_size;
start->count = 1;
start->symbol = alphabet_size-1;
start->present = false;
++start;
while (start != end)
{
start->count = 0;
start->present = false;
++start;
}
counts[alphabet_size-1].present = true;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
typename conditioning_class_kernel_3<alphabet_size>::global_state_type& conditioning_class_kernel_3<alphabet_size>::
get_global_state(
)
{
return global_state;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_3<alphabet_size>::
get_memory_usage(
) const
{
return global_state.memory_usage;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
bool conditioning_class_kernel_3<alphabet_size>::
increment_count (
unsigned long symbol,
unsigned short amount
)
{
// if we are going over a total of 65535 then scale down all counts by 2
if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)
{
total = 0;
data* start = counts;
data* end = counts+alphabet_size;
while (start != end)
{
if (start->count == 1)
{
if (start->symbol == alphabet_size-1)
{
// this symbol must never be zero so we will leave its count at 1
++total;
}
else
{
start->count = 0;
counts[start->symbol].present = false;
}
}
else
{
start->count >>= 1;
total += start->count;
}
++start;
}
}
data* start = counts;
data* swap_spot = counts;
if (counts[symbol].present)
{
while (true)
{
if (start->symbol == symbol && start->count!=0)
{
unsigned short temp = start->count + amount;
start->symbol = swap_spot->symbol;
start->count = swap_spot->count;
swap_spot->symbol = static_cast<unsigned short>(symbol);
swap_spot->count = temp;
break;
}
if ( (start->count) < (swap_spot->count))
{
swap_spot = start;
}
++start;
}
}
else
{
counts[symbol].present = true;
while (true)
{
if (start->count == 0)
{
start->symbol = swap_spot->symbol;
start->count = swap_spot->count;
swap_spot->symbol = static_cast<unsigned short>(symbol);
swap_spot->count = amount;
break;
}
if ((start->count) < (swap_spot->count))
{
swap_spot = start;
}
++start;
}
}
total += amount;
return true;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_3<alphabet_size>::
get_count (
unsigned long symbol
) const
{
if (counts[symbol].present == false)
return 0;
data* start = counts;
while (start->symbol != symbol)
{
++start;
}
return start->count;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_3<alphabet_size>::
get_alphabet_size (
)
{
return alphabet_size;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_3<alphabet_size>::
get_total (
) const
{
return total;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
unsigned long conditioning_class_kernel_3<alphabet_size>::
get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const
{
if (counts[symbol].present == false)
return 0;
total_count = total;
unsigned long low_count_temp = 0;
data* start = counts;
while (start->symbol != symbol)
{
low_count_temp += start->count;
++start;
}
low_count = low_count_temp;
high_count = low_count_temp + start->count;
return start->count;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size
>
void conditioning_class_kernel_3<alphabet_size>::
get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const
{
unsigned long high_count_temp = counts->count;
const data* start = counts;
while (target >= high_count_temp)
{
++start;
high_count_temp += start->count;
}
low_count = high_count_temp - start->count;
high_count = high_count_temp;
symbol = static_cast<unsigned long>(start->symbol);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONDITIONING_CLASS_KERNEl_3_

View File

@@ -0,0 +1,533 @@
// Copyright (C) 2004 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_4_
#define DLIB_CONDITIONING_CLASS_KERNEl_4_
#include "conditioning_class_kernel_abstract.h"
#include "../assert.h"
#include "../algs.h"
namespace dlib
{
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
class conditioning_class_kernel_4
{
/*!
REQUIREMENTS ON pool_size
pool_size > 0
this will be the number of nodes contained in our memory pool
REQUIREMENTS ON mem_manager
mem_manager is an implementation of memory_manager/memory_manager_kernel_abstract.h
INITIAL VALUE
total == 1
escapes == 1
next == 0
CONVENTION
get_total() == total
get_count(alphabet_size-1) == escapes
if (next != 0) then
next == pointer to the start of a linked list and the linked list
is terminated by a node with a next pointer of 0.
get_count(symbol) == node::count for the node where node::symbol==symbol
or 0 if no such node currently exists.
if (there is a node for the symbol) then
LOW_COUNT(symbol) == the sum of all node's counts in the linked list
up to but not including the node for the symbol.
get_memory_usage() == global_state.memory_usage
!*/
struct node
{
unsigned short symbol;
unsigned short count;
node* next;
};
public:
class global_state_type
{
public:
global_state_type (
) :
memory_usage(pool_size*sizeof(node)+sizeof(global_state_type))
{}
private:
unsigned long memory_usage;
typename mem_manager::template rebind<node>::other pool;
friend class conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>;
};
conditioning_class_kernel_4 (
global_state_type& global_state_
);
~conditioning_class_kernel_4 (
);
void clear(
);
bool increment_count (
unsigned long symbol,
unsigned short amount = 1
);
unsigned long get_count (
unsigned long symbol
) const;
inline unsigned long get_total (
) const;
unsigned long get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const;
void get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const;
unsigned long get_memory_usage (
) const;
global_state_type& get_global_state (
);
static unsigned long get_alphabet_size (
);
private:
void half_counts (
);
/*!
ensures
- divides all counts by 2 but ensures that escapes is always at least 1
!*/
// restricted functions
conditioning_class_kernel_4(conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>&); // copy constructor
conditioning_class_kernel_4& operator=(conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>&); // assignment operator
// data members
unsigned short total;
unsigned short escapes;
node* next;
global_state_type& global_state;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
conditioning_class_kernel_4 (
global_state_type& global_state_
) :
total(1),
escapes(1),
next(0),
global_state(global_state_)
{
COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );
// update memory usage
global_state.memory_usage += sizeof(conditioning_class_kernel_4);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
~conditioning_class_kernel_4 (
)
{
clear();
// update memory usage
global_state.memory_usage -= sizeof(conditioning_class_kernel_4);
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
clear(
)
{
total = 1;
escapes = 1;
while (next)
{
node* temp = next;
next = next->next;
global_state.pool.deallocate(temp);
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_memory_usage(
) const
{
return global_state.memory_usage;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
typename conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::global_state_type& conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_global_state(
)
{
return global_state;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
bool conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
increment_count (
unsigned long symbol,
unsigned short amount
)
{
if (symbol == alphabet_size-1)
{
// make sure we won't cause any overflow
if (total >= 65536 - amount )
half_counts();
escapes += amount;
total += amount;
return true;
}
// find the symbol and increment it or add a new node to the list
if (next)
{
node* temp = next;
node* previous = 0;
while (true)
{
if (temp->symbol == static_cast<unsigned short>(symbol))
{
// make sure we won't cause any overflow
if (total >= 65536 - amount )
half_counts();
// we have found the symbol
total += amount;
temp->count += amount;
// if this node now has a count greater than its parent node
if (previous && temp->count > previous->count)
{
// swap the nodes so that the nodes will be in semi-sorted order
swap(temp->count,previous->count);
swap(temp->symbol,previous->symbol);
}
return true;
}
else if (temp->next == 0)
{
// we did not find the symbol so try to add it to the list
if (global_state.pool.get_number_of_allocations() < pool_size)
{
// make sure we won't cause any overflow
if (total >= 65536 - amount )
half_counts();
node* t = global_state.pool.allocate();
t->next = 0;
t->symbol = static_cast<unsigned short>(symbol);
t->count = amount;
temp->next = t;
total += amount;
return true;
}
else
{
// no memory left
return false;
}
}
else if (temp->count == 0)
{
// remove nodes that have a zero count
if (previous)
{
previous->next = temp->next;
node* t = temp;
temp = temp->next;
global_state.pool.deallocate(t);
}
else
{
next = temp->next;
node* t = temp;
temp = temp->next;
global_state.pool.deallocate(t);
}
}
else
{
previous = temp;
temp = temp->next;
}
} // while (true)
}
// if there aren't any nodes in the list yet then do this instead
else
{
if (global_state.pool.get_number_of_allocations() < pool_size)
{
// make sure we won't cause any overflow
if (total >= 65536 - amount )
half_counts();
next = global_state.pool.allocate();
next->next = 0;
next->symbol = static_cast<unsigned short>(symbol);
next->count = amount;
total += amount;
return true;
}
else
{
// no memory left
return false;
}
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_count (
unsigned long symbol
) const
{
if (symbol == alphabet_size-1)
{
return escapes;
}
else
{
node* temp = next;
while (temp)
{
if (temp->symbol == symbol)
return temp->count;
temp = temp->next;
}
return 0;
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_alphabet_size (
)
{
return alphabet_size;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_total (
) const
{
return total;
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const
{
if (symbol != alphabet_size-1)
{
node* temp = next;
unsigned long low = 0;
while (temp)
{
if (temp->symbol == static_cast<unsigned short>(symbol))
{
high_count = temp->count + low;
low_count = low;
total_count = total;
return temp->count;
}
low += temp->count;
temp = temp->next;
}
return 0;
}
else
{
total_count = total;
high_count = total;
low_count = total-escapes;
return escapes;
}
}
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const
{
node* temp = next;
unsigned long high = 0;
while (true)
{
if (temp != 0)
{
high += temp->count;
if (target < high)
{
symbol = temp->symbol;
high_count = high;
low_count = high - temp->count;
return;
}
temp = temp->next;
}
else
{
// this must be the escape symbol
symbol = alphabet_size-1;
low_count = total-escapes;
high_count = total;
return;
}
}
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
unsigned long alphabet_size,
unsigned long pool_size,
typename mem_manager
>
void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::
half_counts (
)
{
total = 0;
if (escapes > 1)
escapes >>= 1;
//divide all counts by 2
node* temp = next;
while (temp)
{
temp->count >>= 1;
total += temp->count;
temp = temp->next;
}
total += escapes;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONDITIONING_CLASS_KERNEl_4_

View File

@@ -0,0 +1,228 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_
#ifdef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_
#include "../algs.h"
namespace dlib
{
template <
unsigned long alphabet_size
>
class conditioning_class
{
/*!
REQUIREMENTS ON alphabet_size
1 < alphabet_size < 65536
INITIAL VALUE
get_total() == 1
get_count(X) == 0 : for all valid values of X except alphabet_size-1
get_count(alphabet_size-1) == 1
WHAT THIS OBJECT REPRESENTS
This object represents a conditioning class used for arithmetic style
compression. It maintains the cumulative counts which are needed
by the entropy_coder and entropy_decoder objects.
At any moment a conditioning_class object represents a set of
alphabet_size symbols. Each symbol is associated with an integer
called its count.
All symbols start out with a count of zero except for alphabet_size-1.
This last symbol will always have a count of at least one. It is
intended to be used as an escape into a lower context when coding
and so it must never have a zero probability or the decoder won't
be able to identify the escape symbol.
NOTATION:
Let MAP(i) be a function which maps integers to symbols. MAP(i) is
one to one and onto. Its domain is 1 to alphabet_size inclusive.
Let RMAP(s) be the inverse of MAP(i).
( i.e. RMAP(MAP(i)) == i and MAP(RMAP(s)) == s )
Let COUNT(i) give the count for the symbol MAP(i).
( i.e. COUNT(i) == get_count(MAP(i)) )
Let LOW_COUNT(s) == the sum of COUNT(x) for x == 1 to x == RMAP(s)-1
(note that the sum of COUNT(x) for x == 1 to x == 0 is 0)
Let HIGH_COUNT(s) == LOW_COUNT(s) + get_count(s)
Basically what this is saying is just that you shoudln't assume you know
what order the symbols are placed in when calculating the cumulative
sums. The specific mapping provided by the MAP() function is unspecified.
THREAD SAFETY
This object can be used safely in a multithreaded program as long as the
global state is not shared between conditioning classes which run on
different threads.
GLOBAL_STATE_TYPE
The global_state_type obejct allows instances of the conditioning_class
object to share any kind of global state the implementer desires.
However, the global_state_type object exists primarily to facilitate the
sharing of a memory pool between many instances of a conditioning_class
object. But note that it is not required that there be any kind of
memory pool at all, it is just a possibility.
!*/
public:
class global_state_type
{
global_state_type (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
// my contents are implementation specific.
};
conditioning_class (
global_state_type& global_state
);
/*!
ensures
- #*this is properly initialized
- &#get_global_state() == &global_state
throws
- std::bad_alloc
!*/
~conditioning_class (
);
/*!
ensures
- all memory associated with *this has been released
!*/
void clear(
);
/*!
ensures
- #*this has its initial value
throws
- std::bad_alloc
!*/
bool increment_count (
unsigned long symbol,
unsigned short amount = 1
);
/*!
requires
- 0 <= symbol < alphabet_size
- 0 < amount < 32768
ensures
- if (sufficient memory is available to complete this operation) then
- returns true
- if (get_total()+amount < 65536) then
- #get_count(symbol) == get_count(symbol) + amount
- else
- #get_count(symbol) == get_count(symbol)/2 + amount
- if (get_count(alphabet_size-1) == 1) then
- #get_count(alphabet_size-1) == 1
- else
- #get_count(alphabet_size-1) == get_count(alphabet_size-1)/2
- for all X where (X != symbol)&&(X != alpahbet_size-1):
#get_count(X) == get_count(X)/2
- else
- returns false
!*/
unsigned long get_count (
unsigned long symbol
) const;
/*!
requires
- 0 <= symbol < alphabet_size
ensures
- returns the count for the specified symbol
!*/
unsigned long get_total (
) const;
/*!
ensures
- returns the sum of get_count(X) for all valid values of X
(i.e. returns the sum of the counts for all the symbols)
!*/
unsigned long get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const;
/*!
requires
- 0 <= symbol < alphabet_size
ensures
- returns get_count(symbol)
- if (get_count(symbol) != 0) then
- #total_count == get_total()
- #low_count == LOW_COUNT(symbol)
- #high_count == HIGH_COUNT(symbol)
- #low_count < #high_count <= #total_count
!*/
void get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const;
/*!
requires
- 0 <= target < get_total()
ensures
- LOW_COUNT(#symbol) <= target < HIGH_COUNT(#symbol)
- #low_count == LOW_COUNT(#symbol)
- #high_count == HIGH_COUNT(#symbol)
- #low_count < #high_count <= get_total()
!*/
global_state_type& get_global_state (
);
/*!
ensures
- returns a reference to the global state used by *this
!*/
unsigned long get_memory_usage (
) const;
/*!
ensures
- returns the number of bytes of memory allocated by all conditioning_class
objects that share the global state given by get_global_state()
!*/
static unsigned long get_alphabet_size (
);
/*!
ensures
- returns alphabet_size
!*/
private:
// restricted functions
conditioning_class(conditioning_class<alphabet_size>&); // copy constructor
conditioning_class<alphabet_size>& operator=(conditioning_class<alphabet_size>&); // assignment operator
};
}
#endif // DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_

View File

@@ -0,0 +1,162 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONDITIONING_CLASS_KERNEl_C_
#define DLIB_CONDITIONING_CLASS_KERNEl_C_
#include "conditioning_class_kernel_abstract.h"
#include "../algs.h"
#include "../assert.h"
#include <iostream>
namespace dlib
{
template <
typename cc_base
>
class conditioning_class_kernel_c : public cc_base
{
const unsigned long alphabet_size;
public:
conditioning_class_kernel_c (
typename cc_base::global_state_type& global_state
) : cc_base(global_state),alphabet_size(cc_base::get_alphabet_size()) {}
bool increment_count (
unsigned long symbol,
unsigned short amount = 1
);
unsigned long get_count (
unsigned long symbol
) const;
unsigned long get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const;
void get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename cc_base
>
bool conditioning_class_kernel_c<cc_base>::
increment_count (
unsigned long symbol,
unsigned short amount
)
{
// make sure requires clause is not broken
DLIB_CASSERT(symbol < alphabet_size &&
0 < amount && amount < 32768,
"\tvoid conditioning_class::increment_count()"
<< "\n\tthe symbol must be in the range 0 to alphabet_size-1. and"
<< "\n\tamount must be in the range 1 to 32767"
<< "\n\talphabet_size: " << alphabet_size
<< "\n\tsymbol: " << symbol
<< "\n\tamount: " << amount
<< "\n\tthis: " << this
);
// call the real function
return cc_base::increment_count(symbol,amount);
}
// ----------------------------------------------------------------------------------------
template <
typename cc_base
>
unsigned long conditioning_class_kernel_c<cc_base>::
get_count (
unsigned long symbol
) const
{
// make sure requires clause is not broken
DLIB_CASSERT(symbol < alphabet_size,
"\tvoid conditioning_class::get_count()"
<< "\n\tthe symbol must be in the range 0 to alphabet_size-1"
<< "\n\talphabet_size: " << alphabet_size
<< "\n\tsymbol: " << symbol
<< "\n\tthis: " << this
);
// call the real function
return cc_base::get_count(symbol);
}
// ----------------------------------------------------------------------------------------
template <
typename cc_base
>
unsigned long conditioning_class_kernel_c<cc_base>::
get_range (
unsigned long symbol,
unsigned long& low_count,
unsigned long& high_count,
unsigned long& total_count
) const
{
// make sure requires clause is not broken
DLIB_CASSERT(symbol < alphabet_size,
"\tvoid conditioning_class::get_range()"
<< "\n\tthe symbol must be in the range 0 to alphabet_size-1"
<< "\n\talphabet_size: " << alphabet_size
<< "\n\tsymbol: " << symbol
<< "\n\tthis: " << this
);
// call the real function
return cc_base::get_range(symbol,low_count,high_count,total_count);
}
// ----------------------------------------------------------------------------------------
template <
typename cc_base
>
void conditioning_class_kernel_c<cc_base>::
get_symbol (
unsigned long target,
unsigned long& symbol,
unsigned long& low_count,
unsigned long& high_count
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( target < this->get_total(),
"\tvoid conditioning_class::get_symbol()"
<< "\n\tthe target must be in the range 0 to get_total()-1"
<< "\n\tget_total(): " << this->get_total()
<< "\n\ttarget: " << target
<< "\n\tthis: " << this
);
// call the real function
cc_base::get_symbol(target,symbol,low_count,high_count);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONDITIONING_CLASS_KERNEl_C_

View File

@@ -0,0 +1,34 @@
// If you are compiling dlib as a shared library and installing it somewhere on your system
// then it is important that any programs that use dlib agree on the state of the
// DLIB_ASSERT statements (i.e. they are either always on or always off). Therefore,
// uncomment one of the following lines to force all DLIB_ASSERTs to either always on or
// always off. If you don't define one of these two macros then DLIB_ASSERT will toggle
// automatically depending on the state of certain other macros, which is not what you want
// when creating a shared library.
/* #undef ENABLE_ASSERTS */
#define DLIB_DISABLE_ASSERTS // asserts always disabled
/* #undef DLIB_ISO_CPP_ONLY */
#define DLIB_NO_GUI_SUPPORT
/* #undef DLIB_ENABLE_STACK_TRACE */
/* #undef LAPACK_FORCE_UNDERSCORE */
/* #undef LAPACK_FORCE_NOUNDERSCORE */
// You should also consider telling dlib to link against libjpeg, libpng, libgif, fftw, CUDA,
// and a BLAS and LAPACK library. To do this you need to uncomment the following #defines.
/* #undef DLIB_JPEG_SUPPORT */
/* #undef DLIB_PNG_SUPPORT */
/* #undef DLIB_GIF_SUPPORT */
/* #undef DLIB_USE_FFTW */
/* #undef DLIB_USE_BLAS */
/* #undef DLIB_USE_LAPACK */
/* #undef DLIB_USE_CUDA */
/* #undef DLIB_USE_MKL_FFT */
// This variable allows dlib/test_for_odr_violations.h to catch people who mistakenly use
// headers from one version of dlib with a compiled dlib binary from a different dlib version.
#define DLIB_CHECK_FOR_VERSION_MISMATCH DLIB_VERSION_MISMATCH_CHECK__EXPECTED_VERSION_19_13_0

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONFIG_READEr_
#define DLIB_CONFIG_READEr_
#include "config_reader/config_reader_kernel_1.h"
#include "map.h"
#include "tokenizer.h"
#include "cmd_line_parser/get_option.h"
#include "algs.h"
#include "is_kind.h"
namespace dlib
{
typedef config_reader_kernel_1<
map<std::string,std::string>::kernel_1b,
map<std::string,void*>::kernel_1b,
tokenizer::kernel_1a
> config_reader;
template <> struct is_config_reader<config_reader> { const static bool value = true; };
#ifndef DLIB_ISO_CPP_ONLY
typedef config_reader_thread_safe_1<
config_reader,
map<std::string,void*>::kernel_1b
> config_reader_thread_safe;
template <> struct is_config_reader<config_reader_thread_safe> { const static bool value = true; };
#endif // DLIB_ISO_CPP_ONLY
}
#endif // DLIB_CONFIG_READEr_

View File

@@ -0,0 +1,738 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONFIG_READER_KERNEl_1_
#define DLIB_CONFIG_READER_KERNEl_1_
#include "config_reader_kernel_abstract.h"
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include "../algs.h"
#include "../stl_checked/std_vector_c.h"
#ifndef DLIB_ISO_CPP_ONLY
#include "config_reader_thread_safe_1.h"
#endif
namespace dlib
{
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
class config_reader_kernel_1
{
/*!
REQUIREMENTS ON map_string_string
is an implementation of map/map_kernel_abstract.h that maps std::string to std::string
REQUIREMENTS ON map_string_void
is an implementation of map/map_kernel_abstract.h that maps std::string to void*
REQUIREMENTS ON tokenizer
is an implementation of tokenizer/tokenizer_kernel_abstract.h
CONVENTION
key_table.is_in_domain(x) == is_key_defined(x)
block_table.is_in_domain(x) == is_block_defined(x)
key_table[x] == operator[](x)
block_table[x] == (void*)&block(x)
!*/
public:
// These two typedefs are defined for backwards compatibility with older versions of dlib.
typedef config_reader_kernel_1 kernel_1a;
#ifndef DLIB_ISO_CPP_ONLY
typedef config_reader_thread_safe_1<
config_reader_kernel_1,
map_string_void
> thread_safe_1a;
#endif // DLIB_ISO_CPP_ONLY
config_reader_kernel_1();
class config_reader_error : public dlib::error
{
friend class config_reader_kernel_1;
config_reader_error(
unsigned long ln,
bool r = false
) :
dlib::error(ECONFIG_READER),
line_number(ln),
redefinition(r)
{
std::ostringstream sout;
sout << "Error in config_reader while parsing at line number " << line_number << ".";
if (redefinition)
sout << "\nThe identifier on this line has already been defined in this scope.";
const_cast<std::string&>(info) = sout.str();
}
public:
const unsigned long line_number;
const bool redefinition;
};
class file_not_found : public dlib::error
{
friend class config_reader_kernel_1;
file_not_found(
const std::string& file_name_
) :
dlib::error(ECONFIG_READER, "Error in config_reader, unable to open file " + file_name_),
file_name(file_name_)
{}
~file_not_found() throw() {}
public:
const std::string file_name;
};
class config_reader_access_error : public dlib::error
{
public:
config_reader_access_error(
const std::string& block_name_,
const std::string& key_name_
) :
dlib::error(ECONFIG_READER),
block_name(block_name_),
key_name(key_name_)
{
std::ostringstream sout;
sout << "Error in config_reader.\n";
if (block_name.size() > 0)
sout << " A block with the name '" << block_name << "' was expected but not found.";
else if (key_name.size() > 0)
sout << " A key with the name '" << key_name << "' was expected but not found.";
const_cast<std::string&>(info) = sout.str();
}
~config_reader_access_error() throw() {}
const std::string block_name;
const std::string key_name;
};
config_reader_kernel_1(
const std::string& config_file
);
config_reader_kernel_1(
std::istream& in
);
virtual ~config_reader_kernel_1(
);
void clear (
);
void load_from (
std::istream& in
);
void load_from (
const std::string& config_file
);
bool is_key_defined (
const std::string& key
) const;
bool is_block_defined (
const std::string& name
) const;
typedef config_reader_kernel_1 this_type;
const this_type& block (
const std::string& name
) const;
const std::string& operator[] (
const std::string& key
) const;
template <
typename queue_of_strings
>
void get_keys (
queue_of_strings& keys
) const;
template <
typename alloc
>
void get_keys (
std::vector<std::string,alloc>& keys
) const;
template <
typename alloc
>
void get_keys (
std_vector_c<std::string,alloc>& keys
) const;
template <
typename queue_of_strings
>
void get_blocks (
queue_of_strings& blocks
) const;
template <
typename alloc
>
void get_blocks (
std::vector<std::string,alloc>& blocks
) const;
template <
typename alloc
>
void get_blocks (
std_vector_c<std::string,alloc>& blocks
) const;
private:
static void parse_config_file (
config_reader_kernel_1& cr,
tokenizer& tok,
unsigned long& line_number,
const bool top_of_recursion = true
);
/*!
requires
- line_number == 1
- cr == *this
- top_of_recursion == true
ensures
- parses the data coming from tok and puts it into cr.
throws
- config_reader_error
!*/
map_string_string key_table;
map_string_void block_table;
// restricted functions
config_reader_kernel_1(config_reader_kernel_1&);
config_reader_kernel_1& operator=(config_reader_kernel_1&);
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
config_reader_kernel_1(
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
clear(
)
{
// free all our blocks
block_table.reset();
while (block_table.move_next())
{
delete static_cast<config_reader_kernel_1*>(block_table.element().value());
}
block_table.clear();
key_table.clear();
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
load_from(
std::istream& in
)
{
clear();
tokenizer tok;
tok.set_stream(in);
tok.set_identifier_token(
tok.lowercase_letters() + tok.uppercase_letters(),
tok.lowercase_letters() + tok.uppercase_letters() + tok.numbers() + "_-."
);
unsigned long line_number = 1;
try
{
parse_config_file(*this,tok,line_number);
}
catch (...)
{
clear();
throw;
}
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
load_from(
const std::string& config_file
)
{
clear();
std::ifstream fin(config_file.c_str());
if (!fin)
throw file_not_found(config_file);
load_from(fin);
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
config_reader_kernel_1(
std::istream& in
)
{
load_from(in);
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
config_reader_kernel_1(
const std::string& config_file
)
{
load_from(config_file);
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
parse_config_file(
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>& cr,
tokenizer& tok,
unsigned long& line_number,
const bool top_of_recursion
)
{
int type;
std::string token;
bool in_comment = false;
bool seen_identifier = false;
std::string identifier;
while (true)
{
tok.get_token(type,token);
// ignore white space
if (type == tokenizer::WHITE_SPACE)
continue;
// basically ignore end of lines
if (type == tokenizer::END_OF_LINE)
{
++line_number;
in_comment = false;
continue;
}
// we are in a comment still so ignore this
if (in_comment)
continue;
// if this is the start of a comment
if (type == tokenizer::CHAR && token[0] == '#')
{
in_comment = true;
continue;
}
// if this is the case then we have just finished parsing a block so we should
// quit this function
if ( (type == tokenizer::CHAR && token[0] == '}' && !top_of_recursion) ||
(type == tokenizer::END_OF_FILE && top_of_recursion) )
{
break;
}
if (seen_identifier)
{
seen_identifier = false;
// the next character should be either a '=' or a '{'
if (type != tokenizer::CHAR || (token[0] != '=' && token[0] != '{'))
throw config_reader_error(line_number);
if (token[0] == '=')
{
// we should parse the value out now
// first discard any white space
if (tok.peek_type() == tokenizer::WHITE_SPACE)
tok.get_token(type,token);
std::string value;
type = tok.peek_type();
token = tok.peek_token();
while (true)
{
if (type == tokenizer::END_OF_FILE || type == tokenizer::END_OF_LINE)
break;
if (type == tokenizer::CHAR && token[0] == '\\')
{
tok.get_token(type,token);
if (tok.peek_type() == tokenizer::CHAR &&
tok.peek_token()[0] == '#')
{
tok.get_token(type,token);
value += '#';
}
else if (tok.peek_type() == tokenizer::CHAR &&
tok.peek_token()[0] == '}')
{
tok.get_token(type,token);
value += '}';
}
else
{
value += '\\';
}
}
else if (type == tokenizer::CHAR &&
(token[0] == '#' || token[0] == '}'))
{
break;
}
else
{
value += token;
tok.get_token(type,token);
}
type = tok.peek_type();
token = tok.peek_token();
} // while(true)
// strip of any tailing white space from value
std::string::size_type pos = value.find_last_not_of(" \t\r\n");
if (pos == std::string::npos)
value.clear();
else
value.erase(pos+1);
// make sure this key isn't already in the key_table
if (cr.key_table.is_in_domain(identifier))
throw config_reader_error(line_number,true);
// add this key/value pair to the key_table
cr.key_table.add(identifier,value);
}
else // when token[0] == '{'
{
// make sure this identifier isn't already in the block_table
if (cr.block_table.is_in_domain(identifier))
throw config_reader_error(line_number,true);
config_reader_kernel_1* new_cr = new config_reader_kernel_1;
void* vtemp = new_cr;
try { cr.block_table.add(identifier,vtemp); }
catch (...) { delete new_cr; throw; }
// now parse this block
parse_config_file(*new_cr,tok,line_number,false);
}
}
else
{
// the next thing should be an identifier but if it isn't this is an error
if (type != tokenizer::IDENTIFIER)
throw config_reader_error(line_number);
seen_identifier = true;
identifier = token;
}
} // while (true)
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
~config_reader_kernel_1(
)
{
clear();
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
is_key_defined (
const std::string& key
) const
{
return key_table.is_in_domain(key);
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
is_block_defined (
const std::string& name
) const
{
return block_table.is_in_domain(name);
}
// ----------------------------------------------------------------------------------------
template <
typename mss,
typename msv,
typename tokenizer
>
const config_reader_kernel_1<mss,msv,tokenizer>& config_reader_kernel_1<mss,msv,tokenizer>::
block (
const std::string& name
) const
{
if (is_block_defined(name) == false)
{
throw config_reader_access_error(name,"");
}
return *static_cast<config_reader_kernel_1*>(block_table[name]);
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
const std::string& config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
operator[] (
const std::string& key
) const
{
if (is_key_defined(key) == false)
{
throw config_reader_access_error("",key);
}
return key_table[key];
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
template <
typename queue_of_strings
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
get_keys (
queue_of_strings& keys
) const
{
keys.clear();
key_table.reset();
std::string temp;
while (key_table.move_next())
{
temp = key_table.element().key();
keys.enqueue(temp);
}
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
template <
typename alloc
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
get_keys (
std::vector<std::string,alloc>& keys
) const
{
keys.clear();
key_table.reset();
while (key_table.move_next())
{
keys.push_back(key_table.element().key());
}
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
template <
typename alloc
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
get_keys (
std_vector_c<std::string,alloc>& keys
) const
{
keys.clear();
key_table.reset();
while (key_table.move_next())
{
keys.push_back(key_table.element().key());
}
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
template <
typename queue_of_strings
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
get_blocks (
queue_of_strings& blocks
) const
{
blocks.clear();
block_table.reset();
std::string temp;
while (block_table.move_next())
{
temp = block_table.element().key();
blocks.enqueue(temp);
}
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
template <
typename alloc
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
get_blocks (
std::vector<std::string,alloc>& blocks
) const
{
blocks.clear();
block_table.reset();
while (block_table.move_next())
{
blocks.push_back(block_table.element().key());
}
}
// ----------------------------------------------------------------------------------------
template <
typename map_string_string,
typename map_string_void,
typename tokenizer
>
template <
typename alloc
>
void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::
get_blocks (
std_vector_c<std::string,alloc>& blocks
) const
{
blocks.clear();
block_table.reset();
while (block_table.move_next())
{
blocks.push_back(block_table.element().key());
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONFIG_READER_KERNEl_1_

View File

@@ -0,0 +1,363 @@
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CONFIG_READER_KERNEl_ABSTRACT_
#ifdef DLIB_CONFIG_READER_KERNEl_ABSTRACT_
#include <string>
#include <iosfwd>
namespace dlib
{
class config_reader
{
/*!
INITIAL VALUE
- there aren't any keys defined for this object
- there aren't any blocks defined for this object
POINTERS AND REFERENCES TO INTERNAL DATA
The destructor, clear(), and load_from() invalidate pointers
and references to internal data. All other functions are guaranteed
to NOT invalidate pointers or references to internal data.
WHAT THIS OBJECT REPRESENTS
This object represents something which is intended to be used to read
text configuration files that are defined by the following EBNF (with
config_file as the starting symbol):
config_file = block;
block = { key_value_pair | sub_block };
key_value_pair = key_name, "=", value;
sub_block = block_name, "{", block, "}";
key_name = identifier;
block_name = identifier;
value = matches any string of text that ends with a newline character, # or }.
note that the trailing newline, # or } is not part of the value though.
identifier = Any string that matches the following regular expression:
[a-zA-Z][a-zA-Z0-9_-\.]*
i.e. Any string that starts with a letter and then is continued
with any number of letters, numbers, _ . or - characters.
Whitespace and comments are ignored. A comment is text that starts with # (but not \#
since the \ escapes the # so that you can have a # symbol in a value if you want) and
ends in a new line. You can also escape a } (e.g. "\}") if you want to have one in a
value.
Note that in a value the leading and trailing white spaces are stripped off but any
white space inside the value is preserved.
Also note that all key_names and block_names within a block syntax group must be unique
but don't have to be globally unique. I.e. different blocks can reuse names.
EXAMPLE CONFIG FILES:
Example 1:
#comment. This line is ignored because it starts with #
#here we have key1 which will have the value of "my value"
key1 = my value
another_key= another value # this is another key called "another_key" with
# a value of "another value"
# this key's value is the empty string. I.e. ""
key2=
Example 2:
#this example illustrates the use of blocks
some_key = blah blah
# now here is a block
our_block
{
# here we can define some keys and values that are local to this block.
a_key = something
foo = bar
some_key = more stuff # note that it is ok to name our key this even though
# there is a key called some_key above. This is because
# we are doing so inside a different block
}
another_block { foo = bar2 } # this block has only one key and is all on a single line
!*/
public:
// exception classes
class config_reader_error : public dlib::error
{
/*!
GENERAL
This exception is thrown if there is an error while parsing the
config file. The type member of this exception will be set
to ECONFIG_READER.
INTERPRETING THIS EXCEPTION
- line_number == the line number the parser was at when the
error occurred.
- if (redefinition) then
- The key or block name on line line_number has already
been defined in this scope which is an error.
- else
- Some other general syntax error was detected
!*/
public:
const unsigned long line_number;
const bool redefinition;
};
class file_not_found : public dlib::error
{
/*!
GENERAL
This exception is thrown if the config file can't be opened for
some reason. The type member of this exception will be set
to ECONFIG_READER.
INTERPRETING THIS EXCEPTION
- file_name == the name of the config file which we failed to open
!*/
public:
const std::string file_name;
};
class config_reader_access_error : public dlib::error
{
/*!
GENERAL
This exception is thrown if you try to access a key or
block that doesn't exist inside a config reader. The type
member of this exception will be set to ECONFIG_READER.
!*/
public:
config_reader_access_error(
const std::string& block_name_,
const std::string& key_name_
);
/*!
ensures
- #block_name == block_name_
- #key_name == key_name_
!*/
const std::string block_name;
const std::string key_name;
};
// --------------------------
config_reader(
);
/*!
ensures
- #*this is properly initialized
- This object will not have any keys or blocks defined in it.
throws
- std::bad_alloc
- config_reader_error
!*/
config_reader(
std::istream& in
);
/*!
ensures
- #*this is properly initialized
- reads the config file to parse from the given input stream,
parses it and loads this object up with all the sub blocks and
key/value pairs it finds.
- before the load is performed, the previous state of the config file
reader is erased. So after the load the config file reader will contain
only information from the given config file.
- This object will represent the top most block of the config file.
throws
- std::bad_alloc
- config_reader_error
!*/
config_reader(
const std::string& config_file
);
/*!
ensures
- #*this is properly initialized
- parses the config file named by the config_file string. Specifically,
parses it and loads this object up with all the sub blocks and
key/value pairs it finds in the file.
- before the load is performed, the previous state of the config file
reader is erased. So after the load the config file reader will contain
only information from the given config file.
- This object will represent the top most block of the config file.
throws
- std::bad_alloc
- config_reader_error
- file_not_found
!*/
virtual ~config_reader(
);
/*!
ensures
- all memory associated with *this has been released
!*/
void clear(
);
/*!
ensures
- #*this has its initial value
throws
- std::bad_alloc
If this exception is thrown then *this is unusable
until clear() is called and succeeds
!*/
void load_from (
std::istream& in
);
/*!
ensures
- reads the config file to parse from the given input stream,
parses it and loads this object up with all the sub blocks and
key/value pairs it finds.
- before the load is performed, the previous state of the config file
reader is erased. So after the load the config file reader will contain
only information from the given config file.
- *this will represent the top most block of the config file contained
in the input stream in.
throws
- std::bad_alloc
If this exception is thrown then *this is unusable
until clear() is called and succeeds
- config_reader_error
If this exception is thrown then this object will
revert to its initial value.
!*/
void load_from (
const std::string& config_file
);
/*!
ensures
- parses the config file named by the config_file string. Specifically,
parses it and loads this object up with all the sub blocks and
key/value pairs it finds in the file.
- before the load is performed, the previous state of the config file
reader is erased. So after the load the config file reader will contain
only information from the given config file.
- This object will represent the top most block of the config file.
throws
- std::bad_alloc
If this exception is thrown then *this is unusable
until clear() is called and succeeds
- config_reader_error
If this exception is thrown then this object will
revert to its initial value.
- file_not_found
If this exception is thrown then this object will
revert to its initial value.
!*/
bool is_key_defined (
const std::string& key_name
) const;
/*!
ensures
- if (there is a key with the given name defined within this config_reader's block) then
- returns true
- else
- returns false
!*/
bool is_block_defined (
const std::string& block_name
) const;
/*!
ensures
- if (there is a sub block with the given name defined within this config_reader's block) then
- returns true
- else
- returns false
!*/
typedef config_reader this_type;
const this_type& block (
const std::string& block_name
) const;
/*!
ensures
- if (is_block_defined(block_name) == true) then
- returns a const reference to the config_reader that represents the given named sub block
- else
- throws config_reader_access_error
throws
- config_reader_access_error
if this exception is thrown then its block_name field will be set to the
given block_name string.
!*/
const std::string& operator[] (
const std::string& key_name
) const;
/*!
ensures
- if (is_key_defined(key_name) == true) then
- returns a const reference to the value string associated with the given key in
this config_reader's block.
- else
- throws config_reader_access_error
throws
- config_reader_access_error
if this exception is thrown then its key_name field will be set to the
given key_name string.
!*/
template <
typename queue_of_strings
>
void get_keys (
queue_of_strings& keys
) const;
/*!
requires
- queue_of_strings is an implementation of queue/queue_kernel_abstract.h
with T set to std::string, or std::vector<std::string>, or
dlib::std_vector_c<std::string>
ensures
- #keys == a collection containing all the keys defined in this config_reader's block.
(i.e. for all strings str in keys it is the case that is_key_defined(str) == true)
!*/
template <
typename queue_of_strings
>
void get_blocks (
queue_of_strings& blocks
) const;
/*!
requires
- queue_of_strings is an implementation of queue/queue_kernel_abstract.h
with T set to std::string, or std::vector<std::string>, or
dlib::std_vector_c<std::string>
ensures
- #blocks == a collection containing the names of all the blocks defined in this
config_reader's block.
(i.e. for all strings str in blocks it is the case that is_block_defined(str) == true)
!*/
private:
// restricted functions
config_reader(config_reader&); // copy constructor
config_reader& operator=(config_reader&); // assignment operator
};
}
#endif // DLIB_CONFIG_READER_KERNEl_ABSTRACT_

Some files were not shown because too many files have changed in this diff Show More