Commit 0886042c authored by lishen's avatar lishen
Browse files

dlib from github, version=19.24

parent 5b127120
Pipeline #262 failed with stages
in 0 seconds
// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONFIG_READER_THREAD_SAFe_
#define DLIB_CONFIG_READER_THREAD_SAFe_
#include "config_reader_kernel_abstract.h"
#include <string>
#include <iostream>
#include <sstream>
#include "../algs.h"
#include "../interfaces/enumerable.h"
#include "../threads.h"
#include "config_reader_thread_safe_abstract.h"
namespace dlib
{
template <
typename config_reader_base,
typename map_string_void
>
class config_reader_thread_safe_1
{
/*!
CONVENTION
- get_mutex() == *m
- *cr == the config reader being extended
- block_table[x] == (void*)&block(x)
- block_table.size() == the number of blocks in *cr
- block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key)
- if (own_pointers) then
- this object owns the m and cr pointers and should delete them when destructed
!*/
public:
config_reader_thread_safe_1 (
const config_reader_base* base,
rmutex* m_
);
config_reader_thread_safe_1();
typedef typename config_reader_base::config_reader_error config_reader_error;
typedef typename config_reader_base::config_reader_access_error config_reader_access_error;
config_reader_thread_safe_1(
std::istream& in
);
config_reader_thread_safe_1(
const std::string& config_file
);
virtual ~config_reader_thread_safe_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_thread_safe_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 queue_of_strings
>
void get_blocks (
queue_of_strings& blocks
) const;
inline const rmutex& get_mutex (
) const;
private:
void fill_block_table (
);
/*!
ensures
- block_table.size() == the number of blocks in cr
- block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key)
!*/
rmutex* m;
config_reader_base* cr;
map_string_void block_table;
const bool own_pointers;
// restricted functions
config_reader_thread_safe_1(config_reader_thread_safe_1&);
config_reader_thread_safe_1& operator=(config_reader_thread_safe_1&);
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
config_reader_thread_safe_1<config_reader_base,map_string_void>::
config_reader_thread_safe_1(
const config_reader_base* base,
rmutex* m_
) :
m(m_),
cr(const_cast<config_reader_base*>(base)),
own_pointers(false)
{
fill_block_table();
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
config_reader_thread_safe_1<config_reader_base,map_string_void>::
config_reader_thread_safe_1(
) :
m(0),
cr(0),
own_pointers(true)
{
try
{
m = new rmutex;
cr = new config_reader_base;
}
catch (...)
{
if (m) delete m;
if (cr) delete cr;
throw;
}
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
void config_reader_thread_safe_1<config_reader_base,map_string_void>::
clear(
)
{
auto_mutex M(*m);
cr->clear();
fill_block_table();
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
void config_reader_thread_safe_1<config_reader_base,map_string_void>::
load_from(
std::istream& in
)
{
auto_mutex M(*m);
cr->load_from(in);
fill_block_table();
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
void config_reader_thread_safe_1<config_reader_base,map_string_void>::
load_from(
const std::string& config_file
)
{
auto_mutex M(*m);
cr->load_from(config_file);
fill_block_table();
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
config_reader_thread_safe_1<config_reader_base,map_string_void>::
config_reader_thread_safe_1(
std::istream& in
) :
m(0),
cr(0),
own_pointers(true)
{
try
{
m = new rmutex;
cr = new config_reader_base(in);
fill_block_table();
}
catch (...)
{
if (m) delete m;
if (cr) delete cr;
throw;
}
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
config_reader_thread_safe_1<config_reader_base,map_string_void>::
config_reader_thread_safe_1(
const std::string& config_file
) :
m(0),
cr(0),
own_pointers(true)
{
try
{
m = new rmutex;
cr = new config_reader_base(config_file);
fill_block_table();
}
catch (...)
{
if (m) delete m;
if (cr) delete cr;
throw;
}
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
config_reader_thread_safe_1<config_reader_base,map_string_void>::
~config_reader_thread_safe_1(
)
{
if (own_pointers)
{
delete m;
delete cr;
}
// clear out the block table
block_table.reset();
while (block_table.move_next())
{
delete static_cast<config_reader_thread_safe_1*>(block_table.element().value());
}
block_table.clear();
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
bool config_reader_thread_safe_1<config_reader_base,map_string_void>::
is_key_defined (
const std::string& key
) const
{
auto_mutex M(*m);
return cr->is_key_defined(key);
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
bool config_reader_thread_safe_1<config_reader_base,map_string_void>::
is_block_defined (
const std::string& name
) const
{
auto_mutex M(*m);
return cr->is_block_defined(name);
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
const config_reader_thread_safe_1<config_reader_base,map_string_void>& config_reader_thread_safe_1<config_reader_base,map_string_void>::
block (
const std::string& name
) const
{
auto_mutex M(*m);
if (block_table.is_in_domain(name) == false)
{
throw config_reader_access_error(name,"");
}
return *static_cast<config_reader_thread_safe_1*>(block_table[name]);
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
const std::string& config_reader_thread_safe_1<config_reader_base,map_string_void>::
operator[] (
const std::string& key
) const
{
auto_mutex M(*m);
return (*cr)[key];
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
template <
typename queue_of_strings
>
void config_reader_thread_safe_1<config_reader_base,map_string_void>::
get_keys (
queue_of_strings& keys
) const
{
auto_mutex M(*m);
cr->get_keys(keys);
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
template <
typename queue_of_strings
>
void config_reader_thread_safe_1<config_reader_base,map_string_void>::
get_blocks (
queue_of_strings& blocks
) const
{
auto_mutex M(*m);
cr->get_blocks(blocks);
}
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
const rmutex& config_reader_thread_safe_1<config_reader_base,map_string_void>::
get_mutex (
) const
{
return *m;
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename config_reader_base,
typename map_string_void
>
void config_reader_thread_safe_1<config_reader_base,map_string_void>::
fill_block_table (
)
{
using namespace std;
// first empty out the block table
block_table.reset();
while (block_table.move_next())
{
delete static_cast<config_reader_thread_safe_1*>(block_table.element().value());
}
block_table.clear();
std::vector<std::string> blocks;
cr->get_blocks(blocks);
// now fill the block table up to match what is in cr
for (unsigned long i = 0; i < blocks.size(); ++i)
{
config_reader_thread_safe_1* block = new config_reader_thread_safe_1(&cr->block(blocks[i]),m);
void* temp = block;
block_table.add(blocks[i],temp);
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONFIG_READER_THREAD_SAFe_
// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_
#ifdef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_
#include <string>
#include <iosfwd>
#include "config_reader_kernel_abstract.h"
#include "../threads/threads_kernel_abstract.h"
namespace dlib
{
class config_reader_thread_safe
{
/*!
WHAT THIS EXTENSION DOES FOR config_reader
This object extends a normal config_reader by simply wrapping all
its member functions inside mutex locks to make it safe to use
in a threaded program.
So this object provides an interface identical to the one defined
in the config_reader/config_reader_kernel_abstract.h file except that
the rmutex returned by get_mutex() is always locked when this
object's member functions are called.
!*/
public:
const rmutex& get_mutex (
) const;
/*!
ensures
- returns the rmutex used to make this object thread safe. i.e. returns
the rmutex that is locked when this object's functions are called.
!*/
};
}
#endif // DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_
#define DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_
#include <cmath>
#include <chrono>
#include <limits>
#include <iostream>
namespace dlib
{
// ----------------------------------------------------------------------------------------
class console_progress_indicator
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a tool for reporting how long a task will take
to complete.
For example, consider the following bit of code:
console_progress_indicator pbar(100)
for (int i = 1; i <= 100; ++i)
{
pbar.print_status(i);
long_running_operation();
}
The above code will print a message to the console each iteration
which shows the current progress and how much time is remaining until
the loop terminates.
!*/
public:
inline explicit console_progress_indicator (
double target_value
);
/*!
ensures
- #target() == target_value
!*/
inline void reset (
double target_value
);
/*!
ensures
- #target() == target_value
- performs the equivalent of:
*this = console_progress_indicator(target_value)
(i.e. resets this object with a new target value)
!*/
inline double target (
) const;
/*!
ensures
- This object attempts to measure how much time is
left until we reach a certain targeted value. This
function returns that targeted value.
!*/
inline bool print_status (
double cur,
bool always_print = false,
std::ostream& out = std::clog
);
/*!
ensures
- print_status() assumes it is called with values which are linearly
approaching target(). It will display the current progress and attempt
to predict how much time is remaining until cur becomes equal to target().
- prints a status message to out which indicates how much more time is
left until cur is equal to target()
- if (always_print) then
- This function prints to the screen each time it is called.
- else
- This function throttles the printing so that at most 1 message is
printed each second. Note that it won't print anything to the screen
until about one second has elapsed. This means that the first call
to print_status() never prints to the screen.
- This function returns true if it prints to the screen and false
otherwise.
!*/
inline void finish (
std::ostream& out = std::cout
) const;
/*!
ensures
- This object prints the completed progress and the elapsed time to out.
It is meant to be called after the loop we are tracking the progress of.
!*/
private:
double target_val;
std::chrono::time_point<std::chrono::steady_clock> start_time;
double first_val;
double seen_first_val;
std::chrono::time_point<std::chrono::steady_clock> last_time;
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// IMPLEMENTATION DETAILS
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
console_progress_indicator::
console_progress_indicator (
double target_value
) :
target_val(target_value),
start_time(std::chrono::steady_clock::now()),
first_val(0),
seen_first_val(false),
last_time(std::chrono::steady_clock::now())
{
}
// ----------------------------------------------------------------------------------------
bool console_progress_indicator::
print_status (
double cur,
bool always_print,
std::ostream& out
)
{
const auto cur_time = std::chrono::steady_clock::now();
// if this is the first time print_status has been called
// then collect some information and exit. We will print status
// on the next call.
if (!seen_first_val)
{
start_time = cur_time;
last_time = cur_time;
first_val = cur;
seen_first_val = true;
return false;
}
if ((cur_time - last_time) >= std::chrono::seconds(1) || always_print)
{
last_time = cur_time;
const auto delta_t = cur_time - start_time;
double delta_val = std::abs(cur - first_val);
// don't do anything if cur is equal to first_val
if (delta_val < std::numeric_limits<double>::epsilon())
return false;
const auto rem_time = delta_t / delta_val * std::abs(target_val - cur);
const auto oldflags = out.flags();
out.setf(std::ios::fixed,std::ios::floatfield);
std::streamsize ss;
// adapt the precision based on whether the target val is an integer
if (std::trunc(target_val) == target_val)
ss = out.precision(0);
else
ss = out.precision(2);
out << "Progress: " << cur << "/" << target_val;
ss = out.precision(2);
out << " (" << cur / target_val * 100. << "%). ";
const auto hours = std::chrono::duration_cast<std::chrono::hours>(rem_time);
const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(rem_time) - hours;
const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(rem_time) - hours - minutes;
out << "Time remaining: ";
if (rem_time >= std::chrono::hours(1))
out << hours.count() << "h ";
if (rem_time >= std::chrono::minutes(1))
out << minutes.count() << "min ";
out << seconds.count() << "s. \r" << std::flush;
// restore previous output flags and precision settings
out.flags(oldflags);
out.precision(ss);
return true;
}
return false;
}
// ----------------------------------------------------------------------------------------
double console_progress_indicator::
target (
) const
{
return target_val;
}
// ----------------------------------------------------------------------------------------
void console_progress_indicator::
reset (
double target_value
)
{
*this = console_progress_indicator(target_value);
}
// ----------------------------------------------------------------------------------------
void console_progress_indicator::
finish (
std::ostream& out
) const
{
const auto oldflags = out.flags();
out.setf(std::ios::fixed,std::ios::floatfield);
std::streamsize ss;
// adapt the precision based on whether the target val is an integer
if (std::trunc(target_val) == target_val)
ss = out.precision(0);
else
ss = out.precision(2);
out << "Progress: " << target_val << "/" << target_val;
out << " (100.00%). ";
const auto delta_t = std::chrono::steady_clock::now() - start_time;
const auto hours = std::chrono::duration_cast<std::chrono::hours>(delta_t);
const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(delta_t) - hours;
const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(delta_t) - hours - minutes;
out << "Time elapsed: ";
if (delta_t >= std::chrono::hours(1))
out << hours.count() << "h ";
if (delta_t >= std::chrono::minutes(1))
out << minutes.count() << "min ";
out << seconds.count() << "s. " << std::endl;
// restore previous output flags and precision settings
out.flags(oldflags);
out.precision(ss);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_
// Copyright (C) 2022 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_IF_CONSTEXPR_H
#define DLIB_IF_CONSTEXPR_H
#include "overloaded.h"
#include "type_traits.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace detail
{
const auto _ = [](auto&& arg) -> decltype(auto) { return std::forward<decltype(arg)>(arg); };
template<typename Void, template <class...> class Op, class... Args>
struct is_detected : std::false_type{};
template<template <class...> class Op, class... Args>
struct is_detected<dlib::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
}
// ----------------------------------------------------------------------------------------
template<typename... T>
struct types_ {};
/*!
WHAT THIS OBJECT REPRESENTS
This is a type list. Use this to pass types to the switch_() function as
compile-time initial conditions.
!*/
// ----------------------------------------------------------------------------------------
template<bool... v>
constexpr auto bools(std::integral_constant<bool, v>...)
/*!
ensures
- returns a type list of compile time booleans.
!*/
{
return types_<std::integral_constant<bool,v>...>{};
}
using true_t = types_<std::true_type>;
using false_t = types_<std::false_type>;
// ----------------------------------------------------------------------------------------
template <
typename... T,
typename... Cases
>
constexpr decltype(auto) switch_(
types_<T...> /*meta_obj*/,
Cases&&... cases
)
/*!
requires
- meta_obj combines a set of initial types. These are used as compile-time initial conditions.
- cases is a set of overload-able conditional branches.
- at least one of the cases is callable given meta_obj.
- each case statement has signature auto(types_<>..., auto _) where _ is an identity function
with identical behaviour to std::identity. This is used to make each generic lambda artificially
dependent on the function body. This allows semantic analysis of the lambdas to be performed AFTER
the correct lambda is chosen depending on meta_obj. This is the crucial bit that makes switch_() behave
in a similar way to "if constexpr()" in C++17. Make sure to use _ on one of the objects in the lambdas.
ensures
- calls the correct conditional branch.
- the correct conditional branch is selected at compile-time.
- Note, each branch can return different types, and the return type of the switch_() function
is that of the compile-time selected branch.
Here is an example:
template<typename T>
auto perform_correct_action(T& obj)
{
return switch(
types_<T>{},
[&](types_<A>, auto _) {
return _(obj).set_something_specific_to_A_and_return_something();
},
[&](types_<B>, auto _) {
return _(obj).set_something_specific_to_B_and_return_something();
},
[&](auto...) {
// Default case statement. Do something sensible.
return false;
}
);
}
Here is another example:
template<typename T>
auto transfer_state(T& a, T& b)
{
return switch(
bools(std::is_move_constructible<T>{}, std::is_copy_constructible<T>{}),
[&](true_t, auto, auto _) {
// T is both move-constructible. Copy semantics can be anything
a = std::move(_(b));
return move_tag{}; // Just for fun, we return different types in each branch.
},
[&](auto, true_t, auto _) {
// T is copy-constructible, Move semantics can be anything. Though in this case,
// if it had been move-constructible, the first branch would have been selected.
// So in this case, it is not move-constructible.
a = _(b);
return copy_tag{};
},
[&](auto...) {
// Default case statement
return dont_care_tag{};
}
);
}
!*/
{
return overloaded(std::forward<Cases>(cases)...)(types_<T>{}..., detail::_);
}
// ----------------------------------------------------------------------------------------
template<template <class...> class Op, class... Args>
using is_detected = detail::is_detected<void, Op, Args...>;
/*!
ensures
- This is exactly the same as std::experimental::is_detected from library fundamentals v
!*/
// ----------------------------------------------------------------------------------------
}
#endif //DLIB_IF_CONSTEXPR_H
\ No newline at end of file
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CONTRoL_
#define DLIB_CONTRoL_
#include "control/lspi.h"
#include "control/mpc.h"
#endif // DLIB_CONTRoL_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_APPROXIMATE_LINEAR_MODELS_Hh_
#define DLIB_APPROXIMATE_LINEAR_MODELS_Hh_
#include "approximate_linear_models_abstract.h"
#include "../matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
struct process_sample
{
typedef feature_extractor feature_extractor_type;
typedef typename feature_extractor::state_type state_type;
typedef typename feature_extractor::action_type action_type;
process_sample(){}
process_sample(
const state_type& s,
const action_type& a,
const state_type& n,
const double& r
) : state(s), action(a), next_state(n), reward(r) {}
state_type state;
action_type action;
state_type next_state;
double reward;
};
template < typename feature_extractor >
void serialize (const process_sample<feature_extractor>& item, std::ostream& out)
{
serialize(item.state, out);
serialize(item.action, out);
serialize(item.next_state, out);
serialize(item.reward, out);
}
template < typename feature_extractor >
void deserialize (process_sample<feature_extractor>& item, std::istream& in)
{
deserialize(item.state, in);
deserialize(item.action, in);
deserialize(item.next_state, in);
deserialize(item.reward, in);
}
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
class policy
{
public:
typedef feature_extractor feature_extractor_type;
typedef typename feature_extractor::state_type state_type;
typedef typename feature_extractor::action_type action_type;
policy (
)
{
w.set_size(fe.num_features());
w = 0;
}
policy (
const matrix<double,0,1>& weights_,
const feature_extractor& fe_
) : w(weights_), fe(fe_) {}
action_type operator() (
const state_type& state
) const
{
return fe.find_best_action(state,w);
}
const feature_extractor& get_feature_extractor (
) const { return fe; }
const matrix<double,0,1>& get_weights (
) const { return w; }
private:
matrix<double,0,1> w;
feature_extractor fe;
};
template < typename feature_extractor >
inline void serialize(const policy<feature_extractor>& item, std::ostream& out)
{
int version = 1;
serialize(version, out);
serialize(item.get_feature_extractor(), out);
serialize(item.get_weights(), out);
}
template < typename feature_extractor >
inline void deserialize(policy<feature_extractor>& item, std::istream& in)
{
int version = 0;
deserialize(version, in);
if (version != 1)
throw serialization_error("Unexpected version found while deserializing dlib::policy object.");
feature_extractor fe;
matrix<double,0,1> w;
deserialize(fe, in);
deserialize(w, in);
item = policy<feature_extractor>(w,fe);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_APPROXIMATE_LINEAR_MODELS_Hh_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_
#ifdef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_
#include "../matrix.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
struct example_feature_extractor
{
/*!
WHAT THIS OBJECT REPRESENTS
This object defines the interface a feature extractor must implement if it
is to be used with the process_sample and policy objects defined at the
bottom of this file. Moreover, it is meant to represent the core part
of a model used in a reinforcement learning algorithm.
In particular, this object models a Q(state,action) function where
Q(state,action) == dot(w, PSI(state,action))
where PSI(state,action) is a feature vector and w is a parameter
vector.
Therefore, a feature extractor defines how the PSI(x,y) feature vector is
calculated. It also defines the types used to represent the state and
action objects.
THREAD SAFETY
Instances of this object are required to be threadsafe, that is, it should
be safe for multiple threads to make concurrent calls to the member
functions of this object.
!*/
// The state and actions can be any types so long as you provide typedefs for them.
typedef T state_type;
typedef U action_type;
// We can also say that the last element in the weight vector w must be 1. This
// can be useful for including a prior into your model.
const static bool force_last_weight_to_1 = false;
example_feature_extractor(
);
/*!
ensures
- this object is properly initialized.
!*/
unsigned long num_features(
) const;
/*!
ensures
- returns the dimensionality of the PSI() feature vector.
!*/
action_type find_best_action (
const state_type& state,
const matrix<double,0,1>& w
) const;
/*!
ensures
- returns the action A that maximizes Q(state,A) = dot(w,PSI(state,A)).
That is, this function finds the best action to take in the given state
when our model is parameterized by the given weight vector w.
!*/
void get_features (
const state_type& state,
const action_type& action,
matrix<double,0,1>& feats
) const;
/*!
ensures
- #feats.size() == num_features()
- #feats == PSI(state,action)
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
struct process_sample
{
/*!
REQUIREMENTS ON feature_extractor
feature_extractor should implement the example_feature_extractor interface
defined at the top of this file.
WHAT THIS OBJECT REPRESENTS
This object holds a training sample for a reinforcement learning algorithm.
In particular, it should be a sample from some process where the process
was in state this->state, then took this->action action which resulted in
receiving this->reward and ending up in the state this->next_state.
!*/
typedef feature_extractor feature_extractor_type;
typedef typename feature_extractor::state_type state_type;
typedef typename feature_extractor::action_type action_type;
process_sample(){}
process_sample(
const state_type& s,
const action_type& a,
const state_type& n,
const double& r
) : state(s), action(a), next_state(n), reward(r) {}
state_type state;
action_type action;
state_type next_state;
double reward;
};
template < typename feature_extractor >
void serialize (const process_sample<feature_extractor>& item, std::ostream& out);
template < typename feature_extractor >
void deserialize (process_sample<feature_extractor>& item, std::istream& in);
/*!
provides serialization support.
!*/
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
class policy
{
/*!
REQUIREMENTS ON feature_extractor
feature_extractor should implement the example_feature_extractor interface
defined at the top of this file.
WHAT THIS OBJECT REPRESENTS
This is a policy based on the supplied feature_extractor model. In
particular, it maps from feature_extractor::state_type to the best action
to take in that state.
!*/
public:
typedef feature_extractor feature_extractor_type;
typedef typename feature_extractor::state_type state_type;
typedef typename feature_extractor::action_type action_type;
policy (
);
/*!
ensures
- #get_feature_extractor() == feature_extractor()
(i.e. it will have its default value)
- #get_weights().size() == #get_feature_extractor().num_features()
- #get_weights() == 0
!*/
policy (
const matrix<double,0,1>& weights,
const feature_extractor& fe
);
/*!
requires
- fe.num_features() == weights.size()
ensures
- #get_feature_extractor() == fe
- #get_weights() == weights
!*/
action_type operator() (
const state_type& state
) const;
/*!
ensures
- returns get_feature_extractor().find_best_action(state,w);
!*/
const feature_extractor& get_feature_extractor (
) const;
/*!
ensures
- returns the feature extractor used by this object
!*/
const matrix<double,0,1>& get_weights (
) const;
/*!
ensures
- returns the parameter vector (w) associated with this object. The length
of the vector is get_feature_extractor().num_features().
!*/
};
template < typename feature_extractor >
void serialize(const policy<feature_extractor>& item, std::ostream& out);
template < typename feature_extractor >
void deserialize(policy<feature_extractor>& item, std::istream& in);
/*!
provides serialization support.
!*/
// ----------------------------------------------------------------------------------------
#endif // DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_LSPI_Hh_
#define DLIB_LSPI_Hh_
#include "lspi_abstract.h"
#include "approximate_linear_models.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
class lspi
{
public:
typedef feature_extractor feature_extractor_type;
typedef typename feature_extractor::state_type state_type;
typedef typename feature_extractor::action_type action_type;
explicit lspi(
const feature_extractor& fe_
) : fe(fe_)
{
init();
}
lspi(
)
{
init();
}
double get_discount (
) const { return discount; }
void set_discount (
double value
)
{
// make sure requires clause is not broken
DLIB_ASSERT(0 < value && value <= 1,
"\t void lspi::set_discount(value)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t value: " << value
);
discount = value;
}
const feature_extractor& get_feature_extractor (
) const { return fe; }
void be_verbose (
)
{
verbose = true;
}
void be_quiet (
)
{
verbose = false;
}
void set_epsilon (
double eps_
)
{
// make sure requires clause is not broken
DLIB_ASSERT(eps_ > 0,
"\t void lspi::set_epsilon(eps_)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t eps_: " << eps_
);
eps = eps_;
}
double get_epsilon (
) const
{
return eps;
}
void set_lambda (
double lambda_
)
{
// make sure requires clause is not broken
DLIB_ASSERT(lambda_ >= 0,
"\t void lspi::set_lambda(lambda_)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t lambda_: " << lambda_
);
lambda = lambda_;
}
double get_lambda (
) const
{
return lambda;
}
void set_max_iterations (
unsigned long max_iter
) { max_iterations = max_iter; }
unsigned long get_max_iterations (
) { return max_iterations; }
template <typename vector_type>
policy<feature_extractor> train (
const vector_type& samples
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(samples.size() > 0,
"\t policy lspi::train(samples)"
<< "\n\t invalid inputs were given to this function"
);
matrix<double,0,1> w(fe.num_features());
w = 0;
matrix<double,0,1> prev_w, b, f1, f2;
matrix<double> A;
double change;
unsigned long iter = 0;
do
{
A = identity_matrix<double>(fe.num_features())*lambda;
b = 0;
for (unsigned long i = 0; i < samples.size(); ++i)
{
fe.get_features(samples[i].state, samples[i].action, f1);
fe.get_features(samples[i].next_state,
fe.find_best_action(samples[i].next_state,w),
f2);
A += f1*trans(f1 - discount*f2);
b += f1*samples[i].reward;
}
prev_w = w;
if (feature_extractor::force_last_weight_to_1)
w = join_cols(pinv(colm(A,range(0,A.nc()-2)))*(b-colm(A,A.nc()-1)),mat(1.0));
else
w = pinv(A)*b;
change = length(w-prev_w);
++iter;
if (verbose)
std::cout << "iteration: " << iter << "\tchange: " << change << std::endl;
} while(change > eps && iter < max_iterations);
return policy<feature_extractor>(w,fe);
}
private:
void init()
{
lambda = 0.01;
discount = 0.8;
eps = 0.01;
verbose = false;
max_iterations = 100;
}
double lambda;
double discount;
double eps;
bool verbose;
unsigned long max_iterations;
feature_extractor fe;
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_LSPI_Hh_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_LSPI_ABSTRACT_Hh_
#ifdef DLIB_LSPI_ABSTRACT_Hh_
#include "approximate_linear_models_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename feature_extractor
>
class lspi
{
/*!
REQUIREMENTS ON feature_extractor
feature_extractor should implement the example_feature_extractor interface
defined at the top of dlib/control/approximate_linear_models_abstract.h
WHAT THIS OBJECT REPRESENTS
This object is an implementation of the reinforcement learning algorithm
described in the following paper:
Lagoudakis, Michail G., and Ronald Parr. "Least-squares policy
iteration." The Journal of Machine Learning Research 4 (2003):
1107-1149.
This means that it takes a bunch of training data in the form of
process_samples and outputs a policy that hopefully performs well when run
on the process that generated those samples.
!*/
public:
typedef feature_extractor feature_extractor_type;
typedef typename feature_extractor::state_type state_type;
typedef typename feature_extractor::action_type action_type;
explicit lspi(
const feature_extractor& fe_
);
/*!
ensures
- #get_feature_extractor() == fe_
- #get_lambda() == 0.01
- #get_discount == 0.8
- #get_epsilon() == 0.01
- is not verbose
- #get_max_iterations() == 100
!*/
lspi(
);
/*!
ensures
- #get_feature_extractor() == feature_extractor()
(i.e. it will have its default value)
- #get_lambda() == 0.01
- #get_discount == 0.8
- #get_epsilon() == 0.01
- is not verbose
- #get_max_iterations() == 100
!*/
double get_discount (
) const;
/*!
ensures
- returns the discount applied to the sum of rewards in the Bellman
equation.
!*/
void set_discount (
double value
);
/*!
requires
- 0 < value <= 1
ensures
- #get_discount() == value
!*/
const feature_extractor& get_feature_extractor (
) const;
/*!
ensures
- returns the feature extractor used by this object
!*/
void be_verbose (
);
/*!
ensures
- This object will print status messages to standard out so that a
user can observe the progress of the algorithm.
!*/
void be_quiet (
);
/*!
ensures
- this object will not print anything to standard out
!*/
void set_epsilon (
double eps
);
/*!
requires
- eps > 0
ensures
- #get_epsilon() == eps
!*/
double get_epsilon (
) const;
/*!
ensures
- returns the error epsilon that determines when training should stop.
Smaller values may result in a more accurate solution but take longer to
train.
!*/
void set_lambda (
double lambda_
);
/*!
requires
- lambda >= 0
ensures
- #get_lambda() == lambda
!*/
double get_lambda (
) const;
/*!
ensures
- returns the regularization parameter. It is the parameter that
determines the trade off between trying to fit the training data
exactly or allowing more errors but hopefully improving the
generalization ability of the resulting function. Smaller values
encourage exact fitting while larger values of lambda may encourage
better generalization.
!*/
void set_max_iterations (
unsigned long max_iter
);
/*!
ensures
- #get_max_iterations() == max_iter
!*/
unsigned long get_max_iterations (
);
/*!
ensures
- returns the maximum number of iterations the SVM optimizer is allowed to
run before it is required to stop and return a result.
!*/
template <
typename vector_type
>
policy<feature_extractor> train (
const vector_type& samples
) const;
/*!
requires
- samples.size() > 0
- samples is something with an interface that looks like
std::vector<process_sample<feature_extractor>>. That is, it should
be some kind of array of process_sample objects.
ensures
- Trains a policy based on the given data and returns the results. The
idea is to find a policy that will obtain the largest possible reward
when run on the process that generated the samples. In particular,
if the returned policy is P then:
- P(S) == the best action to take when in state S.
- if (feature_extractor::force_last_weight_to_1) then
- The last element of P.get_weights() is 1.
!*/
};
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_LSPI_ABSTRACT_Hh_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_MPC_Hh_
#define DLIB_MPC_Hh_
#include "mpc_abstract.h"
#include "../matrix.h"
#include "../algs.h"
namespace dlib
{
template <
long S_,
long I_,
unsigned long horizon_
>
class mpc
{
public:
const static long S = S_;
const static long I = I_;
const static unsigned long horizon = horizon_;
mpc(
)
{
A = 0;
B = 0;
C = 0;
Q = 0;
R = 0;
lower = 0;
upper = 0;
max_iterations = 0;
eps = 0.01;
for (unsigned long i = 0; i < horizon; ++i)
{
target[i].set_size(A.nr());
target[i] = 0;
controls[i].set_size(B.nc());
controls[i] = 0;
}
lambda = 0;
}
mpc (
const matrix<double,S,S>& A_,
const matrix<double,S,I>& B_,
const matrix<double,S,1>& C_,
const matrix<double,S,1>& Q_,
const matrix<double,I,1>& R_,
const matrix<double,I,1>& lower_,
const matrix<double,I,1>& upper_
) : A(A_), B(B_), C(C_), Q(Q_), R(R_), lower(lower_), upper(upper_)
{
// make sure requires clause is not broken
DLIB_ASSERT(A.nr() > 0 && B.nc() > 0,
"\t mpc::mpc()"
<< "\n\t invalid inputs were given to this function"
<< "\n\t A.nr(): " << A.nr()
<< "\n\t B.nc(): " << B.nc()
);
DLIB_ASSERT(A.nr() == A.nc() &&
A.nr() == B.nr() &&
A.nr() == C.nr() &&
A.nr() == Q.nr(),
"\t mpc::mpc()"
<< "\n\t invalid inputs were given to this function"
<< "\n\t A.nr(): " << A.nr()
<< "\n\t A.nc(): " << A.nc()
<< "\n\t B.nr(): " << B.nr()
<< "\n\t C.nr(): " << C.nr()
<< "\n\t Q.nr(): " << Q.nr()
);
DLIB_ASSERT(
B.nc() == R.nr() &&
B.nc() == lower.nr() &&
B.nc() == upper.nr() ,
"\t mpc::mpc()"
<< "\n\t invalid inputs were given to this function"
<< "\n\t B.nr(): " << B.nr()
<< "\n\t B.nc(): " << B.nc()
<< "\n\t lower.nr(): " << lower.nr()
<< "\n\t upper.nr(): " << upper.nr()
);
DLIB_ASSERT(min(Q) >= 0 &&
min(R) > 0 &&
min(upper-lower) >= 0,
"\t mpc::mpc()"
<< "\n\t invalid inputs were given to this function"
<< "\n\t min(Q): " << min(Q)
<< "\n\t min(R): " << min(R)
<< "\n\t min(upper-lower): " << min(upper-lower)
);
max_iterations = 10000;
eps = 0.01;
for (unsigned long i = 0; i < horizon; ++i)
{
target[i].set_size(A.nr());
target[i] = 0;
controls[i].set_size(B.nc());
controls[i] = 0;
}
// Bound the maximum eigenvalue of the hessian by computing the trace of the
// hessian matrix.
lambda = sum(R)*horizon;
matrix<double,S,S> temp = diagm(Q);
for (unsigned long c = 0; c < horizon; ++c)
{
lambda += trace(trans(B)*temp*B);
Q_diag[horizon-c-1] = diag(trans(B)*temp*B);
temp = trans(A)*temp*A + diagm(Q);
}
}
const matrix<double,S,S>& get_A (
) const { return A; }
const matrix<double,S,I>& get_B (
) const { return B; }
const matrix<double,S,1>& get_C (
) const { return C; }
const matrix<double,S,1>& get_Q (
) const { return Q; }
const matrix<double,I,1>& get_R (
) const { return R; }
const matrix<double,I,1>& get_lower_constraints (
) const { return lower; }
const matrix<double,I,1>& get_upper_constraints (
) const { return upper; }
void set_target (
const matrix<double,S,1>& val,
const unsigned long time
)
{
DLIB_ASSERT(time < horizon,
"\t void mpc::set_target(eps_)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t time: " << time
<< "\n\t horizon: " << horizon
);
target[time] = val;
}
void set_target (
const matrix<double,S,1>& val
)
{
for (unsigned long i = 0; i < horizon; ++i)
target[i] = val;
}
void set_last_target (
const matrix<double,S,1>& val
)
{
set_target(val, horizon-1);
}
const matrix<double,S,1>& get_target (
const unsigned long time
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(time < horizon,
"\t matrix mpc::get_target(eps_)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t time: " << time
<< "\n\t horizon: " << horizon
);
return target[time];
}
double get_target_error_threshold (
) const
{
return target_error_threshold;
}
void set_target_error_threshold (
const double thresh
)
{
target_error_threshold = thresh;
}
unsigned long get_max_iterations (
) const { return max_iterations; }
void set_max_iterations (
unsigned long max_iter
)
{
max_iterations = max_iter;
}
void set_epsilon (
double eps_
)
{
// make sure requires clause is not broken
DLIB_ASSERT(eps_ > 0,
"\t void mpc::set_epsilon(eps_)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t eps_: " << eps_
);
eps = eps_;
}
double get_epsilon (
) const
{
return eps;
}
matrix<double,I,1> operator() (
const matrix<double,S,1>& current_state
)
{
// make sure requires clause is not broken
DLIB_ASSERT(min(R) > 0 && A.nr() == current_state.size(),
"\t matrix mpc::operator(current_state)"
<< "\n\t invalid inputs were given to this function"
<< "\n\t min(R): " << min(R)
<< "\n\t A.nr(): " << A.nr()
<< "\n\t current_state.size(): " << current_state.size()
);
// Shift the inputs over by one time step so we can use them to warm start the
// optimizer.
for (unsigned long i = 1; i < horizon; ++i)
controls[i-1] = controls[i];
solve_linear_mpc(current_state);
for (unsigned long i = 1; i < horizon; ++i)
target[i-1] = target[i];
return controls[0];
}
private:
// These temporary variables here just to avoid reallocating them on each call to
// operator().
matrix<double,S,1> M[horizon];
matrix<double,I,1> MM[horizon];
matrix<double,I,1> df[horizon];
matrix<double,I,1> v[horizon];
matrix<double,I,1> v_old[horizon];
void solve_linear_mpc (
const matrix<double,S,1>& initial_state
)
{
// make it so MM == trans(K)*Q*(M-target)
M[0] = A*initial_state + C;
for (unsigned long i = 1; i < horizon; ++i)
M[i] = A*M[i-1] + C;
double min_error_seen = std::numeric_limits<double>::infinity();
for (unsigned long i = 0; i < horizon; ++i) {
M[i] = diagm(Q)*(M[i]-target[i]);
if (target_error_threshold >= 0) {
const double current_error = dot(M[i]-target[i], M[i]);
min_error_seen = std::min(current_error, min_error_seen);
// Once our trajectory gets us within target_error_threshold of the target at any time
// then we essentially stop caring about what happens at times after that. This
// gives us a "just hit the target, I don't care what happens after the hit" model.
if (min_error_seen < target_error_threshold)
{
// Make it so all future errors now appear to be 0. E.g. it is as if target[i]
// was equal to the state the current control sequence generates at time i.
M[i] = 0;
}
}
}
for (long i = (long)horizon-2; i >= 0; --i)
M[i] += trans(A)*M[i+1];
for (unsigned long i = 0; i < horizon; ++i)
MM[i] = trans(B)*M[i];
unsigned long iter = 0;
for (; iter < max_iterations; ++iter)
{
// compute current gradient and put it into df.
// df == H*controls + MM;
M[0] = B*controls[0];
for (unsigned long i = 1; i < horizon; ++i)
M[i] = A*M[i-1] + B*controls[i];
for (unsigned long i = 0; i < horizon; ++i)
M[i] = diagm(Q)*M[i];
for (long i = (long)horizon-2; i >= 0; --i)
M[i] += trans(A)*M[i+1];
for (unsigned long i = 0; i < horizon; ++i)
df[i] = MM[i] + trans(B)*M[i] + diagm(R)*controls[i];
// Check the stopping condition, which is the magnitude of the largest element
// of the gradient.
double max_df = 0;
unsigned long max_t = 0;
long max_v = 0;
for (unsigned long i = 0; i < horizon; ++i)
{
for (long j = 0; j < controls[i].size(); ++j)
{
// if this variable isn't an active constraint then we care about it's
// derivative.
if (!((controls[i](j) <= lower(j) && df[i](j) > 0) ||
(controls[i](j) >= upper(j) && df[i](j) < 0)))
{
if (std::abs(df[i](j)) > max_df)
{
max_df = std::abs(df[i](j));
max_t = i;
max_v = j;
}
}
}
}
if (max_df < eps)
break;
// We will start out by doing a little bit of coordinate descent because it
// allows us to optimize individual variables exactly. Since we are warm
// starting each iteration with a really good solution this helps speed
// things up a lot.
const unsigned long smo_iters = 50;
if (iter < smo_iters)
{
if (Q_diag[max_t](max_v) == 0) continue;
// Take the optimal step but just for one variable.
controls[max_t](max_v) = -(df[max_t](max_v)-Q_diag[max_t](max_v)*controls[max_t](max_v))/Q_diag[max_t](max_v);
controls[max_t](max_v) = put_in_range(lower(max_v), upper(max_v), controls[max_t](max_v));
// If this is the last SMO iteration then don't forget to initialize v
// for the gradient steps.
if (iter+1 == smo_iters)
{
for (unsigned long i = 0; i < horizon; ++i)
v[i] = controls[i];
}
}
else
{
// Take a projected gradient step.
for (unsigned long i = 0; i < horizon; ++i)
{
v_old[i] = v[i];
v[i] = dlib::clamp(controls[i] - 1.0/lambda * df[i], lower, upper);
controls[i] = dlib::clamp(v[i] + (std::sqrt(lambda)-1)/(std::sqrt(lambda)+1)*(v[i]-v_old[i]), lower, upper);
}
}
}
}
unsigned long max_iterations;
double eps;
double target_error_threshold = -1;
matrix<double,S,S> A;
matrix<double,S,I> B;
matrix<double,S,1> C;
matrix<double,S,1> Q;
matrix<double,I,1> R;
matrix<double,I,1> lower;
matrix<double,I,1> upper;
matrix<double,S,1> target[horizon];
double lambda; // abound on the largest eigenvalue of the hessian matrix.
matrix<double,I,1> Q_diag[horizon];
matrix<double,I,1> controls[horizon];
};
}
#endif // DLIB_MPC_Hh_
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_MPC_ABSTRACT_Hh_
#ifdef DLIB_MPC_ABSTRACT_Hh_
#include "../matrix.h"
namespace dlib
{
template <
long S_,
long I_,
unsigned long horizon_
>
class mpc
{
/*!
REQUIREMENTS ON horizon_
horizon_ > 0
REQUIREMENTS ON S_
S_ >= 0
REQUIREMENTS ON I_
I_ >= 0
WHAT THIS OBJECT REPRESENTS
This object implements a linear model predictive controller. To explain
what that means, suppose you have some process you want to control and the
process dynamics are described by the linear equation:
x_{i+1} = A*x_i + B*u_i + C
That is, the next state the system goes into is a linear function of its
current state (x_i) and the current control (u_i) plus some constant bias
or disturbance.
A model predictive controller can find the control (u) you should apply to
drive the state (x) to some reference value, or alternatively to make the
state track some reference time-varying sequence. It does this by
simulating the process for horizon_ time steps and selecting the control
that leads to the best performance over the next horizon_ steps.
To be precise, each time you ask this object for a control, it solves the
following quadratic program:
min sum_i trans(x_i-target_i)*Q*(x_i-target_i) + trans(u_i)*R*u_i
x_i,u_i
such that: x_0 == current_state
x_{i+1} == A*x_i + B*u_i + C
lower <= u_i <= upper
0 <= i < horizon_
and reports u_0 as the control you should take given that you are currently
in current_state. Q and R are user supplied matrices that define how we
penalize variations away from the target state as well as how much we want
to avoid generating large control signals.
Finally, the algorithm we use to solve this quadratic program is based
largely on the method described in:
A Fast Gradient method for embedded linear predictive control (2011)
by Markus Kogel and Rolf Findeisen
!*/
public:
const static long S = S_;
const static long I = I_;
const static unsigned long horizon = horizon_;
mpc(
);
/*!
ensures
- #get_max_iterations() == 0
- The A,B,C,Q,R,lower, and upper parameter matrices are filled with zeros.
Therefore, to use this object you must initialize it via the constructor
that supplies these parameters.
- #get_target_error_threshold() == -1
!*/
mpc (
const matrix<double,S,S>& A,
const matrix<double,S,I>& B,
const matrix<double,S,1>& C,
const matrix<double,S,1>& Q,
const matrix<double,I,1>& R,
const matrix<double,I,1>& lower,
const matrix<double,I,1>& upper
);
/*!
requires
- A.nr() > 0
- B.nc() > 0
- A.nr() == A.nc() == B.nr() == C.nr() == Q.nr()
- B.nc() == R.nr() == lower.nr() == upper.nr()
- min(Q) >= 0
- min(R) > 0
- min(upper-lower) >= 0
ensures
- #get_A() == A
- #get_B() == B
- #get_C() == C
- #get_Q() == Q
- #get_R() == R
- #get_lower_constraints() == lower
- #get_upper_constraints() == upper
- for all valid i:
- get_target(i) == a vector of all zeros
- get_target(i).size() == A.nr()
- #get_max_iterations() == 10000
- #get_epsilon() == 0.01
- #get_target_error_threshold() == -1
!*/
const matrix<double,S,S>& get_A (
) const;
/*!
ensures
- returns the A matrix from the quadratic program defined above.
!*/
const matrix<double,S,I>& get_B (
) const;
/*!
ensures
- returns the B matrix from the quadratic program defined above.
!*/
const matrix<double,S,1>& get_C (
) const;
/*!
ensures
- returns the C matrix from the quadratic program defined above.
!*/
const matrix<double,S,1>& get_Q (
) const;
/*!
ensures
- returns the diagonal of the Q matrix from the quadratic program defined
above.
!*/
const matrix<double,I,1>& get_R (
) const;
/*!
ensures
- returns the diagonal of the R matrix from the quadratic program defined
above.
!*/
const matrix<double,I,1>& get_lower_constraints (
) const;
/*!
ensures
- returns the lower matrix from the quadratic program defined above. All
controls generated by this object will have values no less than this
lower bound. That is, any control u will satisfy min(u-lower) >= 0.
!*/
const matrix<double,I,1>& get_upper_constraints (
) const;
/*!
ensures
- returns the upper matrix from the quadratic program defined above. All
controls generated by this object will have values no larger than this
upper bound. That is, any control u will satisfy min(upper-u) >= 0.
!*/
const matrix<double,S,1>& get_target (
const unsigned long time
) const;
/*!
requires
- time < horizon
ensures
- This object will try to find the control sequence that results in the
process obtaining get_target(time) state at the indicated time. Note
that the next time instant after "right now" is time 0.
!*/
void set_target (
const matrix<double,S,1>& val,
const unsigned long time
);
/*!
requires
- time < horizon
ensures
- #get_target(time) == val
!*/
void set_target (
const matrix<double,S,1>& val
);
/*!
ensures
- for all valid t:
- #get_target(t) == val
!*/
void set_last_target (
const matrix<double,S,1>& val
);
/*!
ensures
- performs: set_target(val, horizon-1)
!*/
double get_target_error_threshold (
) const;
/*!
ensures
- The target error terms in the objective function with values less than
get_target_error_threshold() are ignored. That is, the
trans(x_i-target_i)*Q*(x_i-target_i) terms with values less than this are dropped
from the objective function. Therefore, setting get_target_error_threshold() to a
value >= 0 allows you to encode a control law that says "find me the controls that
make the target error less than or equal to this at some point, but I don't care
what happens at times after that."
!*/
void set_target_error_threshold (
const double thresh
);
/*!
ensures
- #target_error_threshold() == thresh
!*/
unsigned long get_max_iterations (
) const;
/*!
ensures
- When operator() is called it solves an optimization problem to
get_epsilon() precision to determine the next control action. In
particular, we run the optimizer until the magnitude of each element of
the gradient vector is less than get_epsilon() or until
get_max_iterations() solver iterations have been executed.
!*/
void set_max_iterations (
unsigned long max_iter
);
/*!
ensures
- #get_max_iterations() == max_iter
!*/
void set_epsilon (
double eps
);
/*!
requires
- eps > 0
ensures
- #get_epsilon() == eps
!*/
double get_epsilon (
) const;
/*!
ensures
- When operator() is called it solves an optimization problem to
get_epsilon() precision to determine the next control action. In
particular, we run the optimizer until the magnitude of each element of
the gradient vector is less than get_epsilon() or until
get_max_iterations() solver iterations have been executed. This means
that smaller epsilon values will give more accurate outputs but may take
longer to compute.
!*/
matrix<double,I,1> operator() (
const matrix<double,S,1>& current_state
);
/*!
requires
- min(R) > 0
- A.nr() == current_state.size()
ensures
- Solves the model predictive control problem defined by the arguments to
this object's constructor, assuming that the starting state is given by
current_state. Then we return the control that should be taken in the
current state that best optimizes the quadratic objective function
defined above.
- We also shift over the target states so that you only need to update the
last one (if you are using non-zero target states) via a call to
set_last_target()). In particular, for all valid t, it will be the case
that:
- #get_target(t) == get_target(t+1)
- #get_target(horizon-1) == get_target(horizon-1)
!*/
};
}
#endif // DLIB_MPC_ABSTRACT_Hh_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_PRETTY_PRINTEr_
#define DLIB_CPP_PRETTY_PRINTEr_
#include "cpp_pretty_printer/cpp_pretty_printer_kernel_1.h"
#include "cpp_pretty_printer/cpp_pretty_printer_kernel_2.h"
#include "cpp_tokenizer.h"
#include "stack.h"
namespace dlib
{
class cpp_pretty_printer
{
cpp_pretty_printer() {}
typedef stack<unsigned long>::kernel_1a stack;
typedef cpp_tokenizer::kernel_1a tok;
public:
//----------- kernels ---------------
// kernel_1a
typedef cpp_pretty_printer_kernel_1<stack,tok>
kernel_1a;
// kernel_2a
typedef cpp_pretty_printer_kernel_2<stack,tok>
kernel_2a;
};
}
#endif // DLIB_CPP_PRETTY_PRINTEr_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_1_
#define DLIB_CPP_PRETTY_PRINTER_KERNEl_1_
#include <string>
#include <iostream>
#include <sstream>
#include "cpp_pretty_printer_kernel_abstract.h"
#include "../algs.h"
namespace dlib
{
template <
typename stack,
typename tok
>
class cpp_pretty_printer_kernel_1
{
/*!
REQUIREMENTS ON stack
must be an implementation of stack/stack_kernel_abstract.h and
stack::type == unsigned long
REQUIREMENTS ON tok
must be an implementation of tokenizer/tokenizer_kernel_abstract.h
INFO
This implementation applies a color scheme, turns include directives
such as #include "file.h" into links to file.h.html, and it also puts
HTML anchor points on function and class declarations.
!*/
public:
cpp_pretty_printer_kernel_1 (
);
virtual ~cpp_pretty_printer_kernel_1 (
);
void print (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
void print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
private:
const std::string htmlify (
const std::string& str
) const;
/*!
ensures
- str == str but with any '<' replaced with '&lt;', any '>' replaced
with '&gt;', and any '&' replaced with '&amp;'
!*/
// data members
mutable tok t;
void number (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- prints in to out and adds line numbers
!*/
// restricted functions
cpp_pretty_printer_kernel_1(const cpp_pretty_printer_kernel_1&); // copy constructor
cpp_pretty_printer_kernel_1& operator=(const cpp_pretty_printer_kernel_1&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
cpp_pretty_printer_kernel_1<stack,tok>::
cpp_pretty_printer_kernel_1 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
cpp_pretty_printer_kernel_1<stack,tok>::
~cpp_pretty_printer_kernel_1 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_1<stack,tok>::
print (
std::istream& in,
std::ostream& out,
const std::string& title
) const
{
using namespace std;
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
t.set_stream(in);
out << "<html><!-- "
<< "Created using the cpp_pretty_printer from the dlib C++ library. See http://dlib.net for updates."
<< " --><head><title>" << title << "</title></head><body bgcolor='white'><pre>\n";
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
unsigned long scope = 0; // counts the number of new scopes we have entered
// since we were at a scope where functions can be declared
bool recently_seen_class_keyword = false;
// true if we have seen the keywords class, struct, or enum and
// we have not seen any identifiers or { characters
bool recently_seen_include = false;
// true if we have seen the #include keyword and have not seen double
// quoted text or >
bool recently_seen_new_scope = false;
// true if we have seen the keywords class, namespace, or struct and
// we have not seen the characters {, ), or ; since then
bool recently_seen_paren = false;
// true if we have seen a ) and we have only seen white_space or comments since
bool in_initialization_list = false;
// true if we have seen a ) followed by any white space or comments and then
// followed by a : (in scope==0 with recently_seen_preprocessor==false) and we
// have not yet seen the character { or ;
bool recently_seen_preprocessor = false;
// true if we have seen the #pragma or #if or #define or #elif keywords and have
// not seen an end of line.
bool recently_seen_extern = false;
// true if we have seen the extern keyword and haven't seen a ; or { yet.
unsigned long paren_count = 0;
// this is the number of ( we have seen minus the number of ) we have
// seen.
int type;
stack scopes; // a stack to hold old scopes
string token, temp;
t.get_token(type,token);
while (type != tok::END_OF_FILE)
{
switch (type)
{
case tok::IDENTIFIER: // ------------------------------------------
if ( recently_seen_class_keyword)
{
// this might be a class name so check if there is a
// ; or identifier or * or & coming up.
type = t.peek_type();
temp.clear();
if (type == tok::WHITE_SPACE)
{
t.get_token(type,temp);
if (temp.find_first_of("\n\r") != string::npos)
recently_seen_preprocessor = false;
}
if (t.peek_type() != tok::IDENTIFIER &&
t.peek_token() != "*" && t.peek_token() != "&")
{
// this is the name of a class or struct in a class or
// struct declaration.
out << "<b><a name='" << token << "'></a>" << token << "</b>" << temp;
}
else
{
out << token << temp;
}
}
else if ( !in_initialization_list &&
!recently_seen_preprocessor )
{
// this might be a function name so check if there is a
// ( coming up.
type = t.peek_type();
temp.clear();
if (type == tok::WHITE_SPACE)
{
t.get_token(type,temp);
type = t.peek_type();
}
if (type == tok::OTHER && t.peek_token() == "(")
{
if (scope == 0 && paren_count == 0)
{
// this is a function definition or prototype
out << "<b><a name='" << token << "'></a>" << token << "</b>" << temp;
}
else
{
// this is a function call (probably)
out << "<font color='#BB00BB'>" << token << "</font>" << temp;
}
}
else
{
out << token << temp;
}
}
else
{
out << token;
}
recently_seen_class_keyword = false;
recently_seen_paren = false;
break;
case tok::KEYWORD: // ---------------------------------------------
if (scope == 0 && token == "operator")
{
// Doing this is sort of weird since operator is really a keyword
// but I just like how this looks.
out << "<b><a name='" << token << "'></a>" << token << "</b>";
}
// this isn't a keyword if it is something like #include <new>
else if ( token == "true" || token == "false")
{
// color 'true' and 'false' the same way we color numbers
out << "<font color='#979000'>" << token << "</font>";
}
else if (!recently_seen_include)
{
// This is a normal keyword
if (token == "char" || token == "unsigned" || token == "signed" ||
token == "short" || token == "int" || token == "long" ||
token == "float" || token == "double" || token == "bool" ||
token == "void" || token == "size_t" || token == "wchar_t")
{
out << "<font color='#0000FF'><u>" << token << "</u></font>";
}
else
{
out << "<font color='#0000FF'>" << token << "</font>";
}
}
else
{
out << token;
}
if (token == "#include")
{
recently_seen_include = true;
}
else if (token == "class")
{
recently_seen_new_scope = true;
recently_seen_class_keyword = true;
}
else if (token == "namespace")
{
recently_seen_new_scope = true;
}
else if (token == "enum")
{
recently_seen_class_keyword = true;
}
else if (token == "struct")
{
recently_seen_new_scope = true;
recently_seen_class_keyword = true;
}
else if (token == "#pragma" || token == "#if" || token == "#define" || token == "#elif")
{
recently_seen_preprocessor = true;
}
else if (token == "extern")
{
recently_seen_extern = true;
}
recently_seen_paren = false;
break;
case tok::COMMENT: // ---------------------------------------------
{
// if this is a special anchor comment
if (token.size() > 4 &&
token[0] == '/' &&
token[1] == '*' &&
token[2] == '!' &&
token[3] == 'A' &&
token[4] == ' '
)
{
temp = token;
istringstream sin(token);
sin >> temp;
sin >> temp;
sin.get();
// if there was still more stuff in the token then we are ok.
if (sin)
out << "<a name='" << temp << "'/>";
}
out << "<font color='#009900'>" << htmlify(token) << "</font>";
}
break;
case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
{
out << "<font color='#FF0000'>" << htmlify(token) << "</font>";
recently_seen_paren = false;
}
break;
case tok::NUMBER: // -----------------------------------------
{
out << "<font color='#979000'>" << token << "</font>";
recently_seen_include = false;
}
break;
case tok::WHITE_SPACE: // -----------------------------------------
{
out << token;
if (token.find_first_of("\n\r") != string::npos)
recently_seen_preprocessor = false;
}
break;
case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
{
if (recently_seen_include)
{
// this is the name of an included file
recently_seen_include = false;
out << "<a style='text-decoration:none' href='" << htmlify(token) << ".html'>" << htmlify(token) << "</a>";
}
else
{
// this is just a normal quoted string
out << "<font color='#CC0000'>" << htmlify(token) << "</font>";
}
recently_seen_paren = false;
}
break;
case tok::OTHER: // -----------------------------------------------
switch (token[0])
{
case '{':
out << "<b>{</b>";
// if we are entering a new scope
if (recently_seen_new_scope || recently_seen_extern)
{
recently_seen_new_scope = false;
scopes.push(scope);
scope = 0;
}
else
{
++scope;
}
in_initialization_list = false;
recently_seen_paren = false;
recently_seen_class_keyword = false;
recently_seen_extern = false;
break;
case '}':
out << "<b>}</b>";
if (scope > 0)
{
--scope;
}
else if (scopes.size())
{
scopes.pop(scope);
}
recently_seen_paren = false;
break;
case ':':
out << ':';
if (recently_seen_paren && scope == 0 &&
recently_seen_preprocessor == false)
{
in_initialization_list = true;
}
recently_seen_paren = false;
break;
case ';':
out << ';';
recently_seen_new_scope = false;
recently_seen_paren = false;
recently_seen_extern = false;
break;
case ')':
out << "<font face='Lucida Console'>)</font>";
recently_seen_paren = true;
recently_seen_new_scope = false;
--paren_count;
break;
case '(':
out << "<font face='Lucida Console'>(</font>";
recently_seen_paren = false;
++paren_count;
break;
case '>':
recently_seen_include = false;
out << "<font color='#5555FF'>&gt;</font>";
recently_seen_paren = false;
break;
case '<':
out << "<font color='#5555FF'>&lt;</font>";
recently_seen_paren = false;
break;
case '&':
out << "<font color='#5555FF'>&amp;</font>";
recently_seen_paren = false;
break;
case '=':
case '+':
case '-':
case '/':
case '*':
case '!':
case '|':
case '%':
out << "<font color='#5555FF'>" << token << "</font>";
recently_seen_paren = false;
break;
default:
out << token;
recently_seen_paren = false;
break;
} // switch (token[0])
break;
} // switch (type)
t.get_token(type,token);
} // while (type != tok::END_OF_FILE)
out << "\n</pre></body></html>";
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_1<stack,tok>::
print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const
{
using namespace std;
ostringstream sout;
print(in,sout,title);
istringstream sin(sout.str());
number(sin,out);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_1<stack,tok>::
number (
std::istream& in,
std::ostream& out
) const
{
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number");
std::string space = "&nbsp;&nbsp;&nbsp;";
std::ios::int_type ch;
unsigned long count = 1;
while ((ch=in.get()) != EOF)
{
if (ch != '\n')
{
out << (char)ch;
}
else
{
out << "\n<font color='555555'>" << count << " </font> " + space;
++count;
if (count == 10)
space = "&nbsp;&nbsp;";
if (count == 100)
space = "&nbsp;";
if (count == 1000)
space = "";
}
}
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number");
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
const std::string cpp_pretty_printer_kernel_1<stack,tok>::
htmlify (
const std::string& str
) const
{
std::string::size_type i;
std::string temp;
for (i = 0; i < str.size(); ++i)
{
if (str[i] == '<')
temp += "&lt;";
else if (str[i] == '>')
temp += "&gt;";
else if (str[i] == '&')
temp += "&amp;";
else
temp += str[i];
}
return temp;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_1_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_2_
#define DLIB_CPP_PRETTY_PRINTER_KERNEl_2_
#include <string>
#include <iostream>
#include <sstream>
#include "cpp_pretty_printer_kernel_abstract.h"
#include "../algs.h"
namespace dlib
{
template <
typename stack,
typename tok
>
class cpp_pretty_printer_kernel_2
{
/*!
REQUIREMENTS ON stack
must be an implementation of stack/stack_kernel_abstract.h and
stack::type == unsigned long
REQUIREMENTS ON tok
must be an implementation of tokenizer/tokenizer_kernel_abstract.h
INFO
This implementation applies a black and white color scheme suitable
for printing on a black and white printer. It also places the document
title prominently at the top of the pretty printed source file.
!*/
public:
cpp_pretty_printer_kernel_2 (
);
virtual ~cpp_pretty_printer_kernel_2 (
);
void print (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
void print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
private:
// data members
mutable tok t;
const std::string htmlify (
const std::string& str
) const;
/*!
ensures
- str == str but with any '<' replaced with '&lt;', any '>' replaced
with '&gt;', and any '&' replaced with '&amp;'
!*/
void number (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- prints in to out and adds line numbers
!*/
// restricted functions
cpp_pretty_printer_kernel_2(const cpp_pretty_printer_kernel_2&); // copy constructor
cpp_pretty_printer_kernel_2& operator=(const cpp_pretty_printer_kernel_2&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
cpp_pretty_printer_kernel_2<stack,tok>::
cpp_pretty_printer_kernel_2 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
cpp_pretty_printer_kernel_2<stack,tok>::
~cpp_pretty_printer_kernel_2 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_2<stack,tok>::
print (
std::istream& in,
std::ostream& out,
const std::string& title
) const
{
using namespace std;
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");
t.set_stream(in);
out << "<html><!-- "
<< "Created using the cpp_pretty_printer from the dlib C++ library. See http://dlib.net for updates."
<< " --><head>"
<< "<title>" << title << "</title></head><body bgcolor='white'>"
<< "<h1><center>" << title << "</center></h1><pre>\n"
<< "<font style='font-size:9pt' face='Lucida Console'>\n";
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");
unsigned long scope = 0; // counts the number of new scopes we have entered
// since we were at a scope where functions can be declared
bool recently_seen_class_keyword = false;
// true if we have seen the keywords class or struct and
// we have not seen any identifiers or { characters
bool recently_seen_include = false;
// true if we have seen the #include keyword and have not seen double
// quoted text or >
bool recently_seen_new_scope = false;
// true if we have seen the keywords class, namespace, or struct and
// we have not seen the characters {, ), or ; since then
bool recently_seen_paren = false;
// true if we have seen a ) and we have only seen white_space or comments since
bool in_initialization_list = false;
// true if we have seen a ) followed by any white space or comments and then
// followed by a : (in scope==0 with recently_seen_preprocessor==false) and we
// have not yet seen the character { or ;
bool recently_seen_preprocessor = false;
// true if we have seen the #pragma or #if or #define or #elif keyword and
// have not seen an identifier.
bool recently_seen_extern = false;
// true if we have seen the extern keyword and haven't yet seen a
// { or ; character.
unsigned long paren_count = 0;
// this is the number of ( we have seen minus the number of ) we have
// seen.
int type;
stack scopes; // a stack to hold old scopes
string token, temp;
t.get_token(type,token);
while (type != tok::END_OF_FILE)
{
switch (type)
{
case tok::IDENTIFIER: // ------------------------------------------
if ( recently_seen_class_keyword)
{
// this might be a class name so check if there is a
// ; or identifier or * or &amp; coming up.
type = t.peek_type();
temp.clear();
if (type == tok::WHITE_SPACE)
{
t.get_token(type,temp);
if (temp.find_first_of("\n\r") != string::npos)
recently_seen_preprocessor = false;
}
if (t.peek_token() != ";" && t.peek_type() != tok::IDENTIFIER &&
t.peek_token() != "*" && t.peek_token() != "&amp;")
{
// this is the name of a class or struct in a class or
// struct declaration.
out << "<b><i>" << token << "</i></b>" << temp;
}
else
{
out << token << temp;
}
}
else if ( !in_initialization_list &&
!recently_seen_preprocessor &&
scope == 0 &&
paren_count == 0)
{
// this might be a function name so check if there is a
// ( coming up.
type = t.peek_type();
temp.clear();
if (type == tok::WHITE_SPACE)
{
t.get_token(type,temp);
type = t.peek_type();
}
if (type == tok::OTHER && t.peek_token() == "(")
{
// this is a function definition or prototype
out << "<b><i>" << token << "</i></b>" << temp;
}
else
{
out << token << temp;
}
}
else
{
out << token;
}
recently_seen_class_keyword = false;
recently_seen_paren = false;
break;
case tok::KEYWORD: // ---------------------------------------------
if (scope == 0 && token == "operator")
{
// Doing this is sort of weird since operator is really a keyword
// but I just like how this looks.
out << "<b><i>" << token << "</i></b>";
}
// this isn't a keyword if it is something like #include <new>
else if (!recently_seen_include)
{
// This is a normal keyword
out << "<u><font face='Fixedsys'>" << token << "</font></u>";
}
else
{
out << token;
}
if (token == "#include")
{
recently_seen_include = true;
}
else if (token == "class")
{
recently_seen_new_scope = true;
recently_seen_class_keyword = true;
}
else if (token == "namespace")
{
recently_seen_new_scope = true;
}
else if (token == "struct")
{
recently_seen_new_scope = true;
recently_seen_class_keyword = true;
}
else if (token == "#pragma" || token == "#define" || token == "#elif" || token == "#if")
{
recently_seen_preprocessor = true;
}
else if (token == "extern")
{
recently_seen_extern = true;
}
recently_seen_paren = false;
break;
case tok::COMMENT: // ---------------------------------------------
{
out << "<font face='Courier New'>" << htmlify(token) << "</font>";
}
break;
case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
{
out << htmlify(token);
recently_seen_paren = false;
}
break;
case tok::WHITE_SPACE: // -----------------------------------------
{
out << token;
if (token.find_first_of("\n\r") != string::npos)
recently_seen_preprocessor = false;
}
break;
case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
{
out << htmlify(token);
recently_seen_paren = false;
recently_seen_include = false;
}
break;
case tok::NUMBER:
case tok::OTHER: // -----------------------------------------------
switch (token[0])
{
case '{':
out << "<b>{</b>";
// if we are entering a new scope
if (recently_seen_new_scope || recently_seen_extern)
{
recently_seen_new_scope = false;
scopes.push(scope);
scope = 0;
}
else
{
++scope;
}
in_initialization_list = false;
recently_seen_paren = false;
recently_seen_class_keyword = false;
recently_seen_extern = false;
break;
case '}':
out << "<b>}</b>";
if (scope > 0)
{
--scope;
}
else if (scopes.size())
{
scopes.pop(scope);
}
recently_seen_paren = false;
break;
case ':':
out << ':';
if (recently_seen_paren && scope == 0 &&
recently_seen_preprocessor == false)
{
in_initialization_list = true;
}
recently_seen_paren = false;
break;
case ';':
out << ';';
recently_seen_new_scope = false;
recently_seen_paren = false;
recently_seen_extern = false;
break;
case ')':
out << ')';
recently_seen_paren = true;
recently_seen_new_scope = false;
--paren_count;
break;
case '(':
out << '(';
recently_seen_paren = false;
++paren_count;
break;
case '>':
recently_seen_include = false;
out << "&gt;";
recently_seen_paren = true;
break;
case '<':
out << "&lt;";
recently_seen_paren = true;
break;
case '&':
out << "&amp;";
recently_seen_paren = true;
break;
default:
out << token;
recently_seen_paren = false;
if (token == "&gt;")
recently_seen_include = false;
break;
} // switch (token[0])
break;
} // switch (type)
t.get_token(type,token);
} // while (type != tok::END_OF_FILE)
out << "</font></pre></body></html>";
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_2<stack,tok>::
print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const
{
using namespace std;
ostringstream sout;
print(in,sout,title);
istringstream sin(sout.str());
number(sin,out);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_2<stack,tok>::
number (
std::istream& in,
std::ostream& out
) const
{
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::number");
std::string space = "&nbsp;&nbsp;&nbsp;";
std::ios::int_type ch;
unsigned long count = 1;
while ((ch=in.get()) != EOF)
{
if (ch != '\n')
{
out << (char)ch;
}
else
{
out << "\n<i><font face='Courier New'>" << count << " </font></i> " + space;
++count;
if (count == 10)
space = "&nbsp;&nbsp;";
if (count == 100)
space = "&nbsp;";
if (count == 1000)
space = "";
}
}
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::number");
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
const std::string cpp_pretty_printer_kernel_2<stack,tok>::
htmlify (
const std::string& str
) const
{
std::string::size_type i;
std::string temp;
for (i = 0; i < str.size(); ++i)
{
if (str[i] == '<')
temp += "&lt;";
else if (str[i] == '>')
temp += "&gt;";
else if (str[i] == '&')
temp += "&amp;";
else
temp += str[i];
}
return temp;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_2_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_
#ifdef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_
#include <string>
#include <ioswfd>
namespace dlib
{
class cpp_pretty_printer
{
/*!
INITIAL VALUE
This object does not have any state associated with it.
WHAT THIS OBJECT REPRESENTS
This object represents an HTML pretty printer for C++ source code.
!*/
public:
cpp_pretty_printer (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~cpp_pretty_printer (
);
/*!
ensures
- any resources associated with *this have been released
!*/
void print (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
/*!
ensures
- treats data from in as C++ source code and pretty prints it in
HTML and writes it to out.
- The title of the HTML document written to out will be title
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 print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
/*!
ensures
- treats data from in as C++ source code and pretty prints it in
HTML with line numbers and writes it to out.
- The title of the HTML document written to out will be title
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.
!*/
private:
// restricted functions
cpp_pretty_printer(const cpp_pretty_printer&); // copy constructor
cpp_pretty_printer& operator=(const cpp_pretty_printer&); // assignment operator
};
}
#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_TOKENIZEr_
#define DLIB_CPP_TOKENIZEr_
#include <string>
#include "cpp_tokenizer/cpp_tokenizer_kernel_1.h"
#include "cpp_tokenizer/cpp_tokenizer_kernel_c.h"
#include "tokenizer.h"
#include "queue.h"
#include "set.h"
namespace dlib
{
class cpp_tokenizer
{
cpp_tokenizer() {}
typedef set<std::string>::kernel_1a set;
typedef queue<cpp_tok_kernel_1_helper::token_text_pair>::kernel_2a queue;
typedef tokenizer::kernel_1a tok;
public:
//----------- kernels ---------------
// kernel_1a
typedef cpp_tokenizer_kernel_1<tok,queue,set>
kernel_1a;
typedef cpp_tokenizer_kernel_c<kernel_1a>
kernel_1a_c;
};
}
#endif // DLIB_CPP_TOKENIZEr_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_TOKENIZER_KERNEl_1_
#define DLIB_CPP_TOKENIZER_KERNEl_1_
#include <string>
#include <iostream>
#include "cpp_tokenizer_kernel_abstract.h"
#include "../algs.h"
namespace dlib
{
namespace cpp_tok_kernel_1_helper
{
struct token_text_pair
{
std::string token;
int type=0;
};
}
template <
typename tok,
typename queue,
typename set
>
class cpp_tokenizer_kernel_1
{
/*!
REQUIREMENTS ON tok
tok must be an implementation of tokenizer/tokenizer_kernel_abstract.h
REQUIREMENTS ON queue
queue must be an implementation of queue/queue_kernel_abstract.h
and must have T==cpp_tok_kernel_1_helper::token_text_pair
REQUIREMENTS ON set
set must be an implemention of set/set_kernel_abstract.h or
hash_set/hash_set_kernel_abstract.h and must have T==std::string.
INITIAL VALUE
- keywords == a set of all the C++ keywords
- tokenizer.stream_is_set() == false
- buffer.size() == 0
- tokenizer.get_identifier_head() == "$_" + tokenizer.lowercase_letters() +
tokenizer.uppercase_letters()
- tokenizer.get_identifier_body() == "$_" + tokenizer.lowercase_letters() +
tokenizer.uppercase_letters() + tokenizer.numbers()
- have_peeked == false
CONVENTION
- tokenizer.stream_is_set() == stream_is_set()
- tokenizer.get_stream() == get_stream()
- keywords == a set of all the C++ keywords
- tokenizer.get_identifier_head() == "$_" + tokenizer.lowercase_letters() +
tokenizer.uppercase_letters()
- tokenizer.get_identifier_body() == "$_" + tokenizer.lowercase_letters() +
tokenizer.uppercase_letters() + tokenizer.numbers()
- buffer == a queue of tokens. This is where we put tokens
we gathered early due to looking ahead.
- if (have_peeked) then
- next_token == the next token to be returned from get_token()
- next_type == the type of token in peek_token
!*/
typedef cpp_tok_kernel_1_helper::token_text_pair token_text_pair;
public:
enum
{
END_OF_FILE,
KEYWORD,
COMMENT,
SINGLE_QUOTED_TEXT,
DOUBLE_QUOTED_TEXT,
IDENTIFIER,
OTHER,
NUMBER,
WHITE_SPACE
};
cpp_tokenizer_kernel_1 (
);
virtual ~cpp_tokenizer_kernel_1 (
);
void clear(
);
void set_stream (
std::istream& in
);
bool stream_is_set (
) const;
std::istream& get_stream (
) const;
void get_token (
int& type,
std::string& token
);
int peek_type (
) const;
const std::string& peek_token (
) const;
void swap (
cpp_tokenizer_kernel_1<tok,queue,set>& item
);
private:
void buffer_token(
int type,
const std::string& token
)
/*!
ensures
- stores the token and its type into buffer
!*/
{
token_text_pair temp;
temp.token = token;
temp.type = type;
buffer.enqueue(temp);
}
void buffer_token(
int type,
char token
)
/*!
ensures
- stores the token and its type into buffer
!*/
{
token_text_pair temp;
temp.token = token;
temp.type = type;
buffer.enqueue(temp);
}
// restricted functions
cpp_tokenizer_kernel_1(const cpp_tokenizer_kernel_1<tok,queue,set>&); // copy constructor
cpp_tokenizer_kernel_1<tok,queue,set>& operator=(const cpp_tokenizer_kernel_1<tok,queue,set>&); // assignment operator
// data members
set keywords;
queue buffer;
tok tokenizer;
mutable std::string next_token;
mutable int next_type;
mutable bool have_peeked;
};
template <
typename tok,
typename queue,
typename set
>
inline void swap (
cpp_tokenizer_kernel_1<tok,queue,set>& a,
cpp_tokenizer_kernel_1<tok,queue,set>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
cpp_tokenizer_kernel_1<tok,queue,set>::
cpp_tokenizer_kernel_1(
) :
have_peeked(false)
{
// add C++ keywords to keywords
std::string temp;
temp = "#include"; keywords.add(temp);
temp = "__asm"; keywords.add(temp);
temp = "_asm"; keywords.add(temp);
temp = "if"; keywords.add(temp);
temp = "int"; keywords.add(temp);
temp = "else"; keywords.add(temp);
temp = "template"; keywords.add(temp);
temp = "void"; keywords.add(temp);
temp = "false"; keywords.add(temp);
temp = "class"; keywords.add(temp);
temp = "public"; keywords.add(temp);
temp = "while"; keywords.add(temp);
temp = "bool"; keywords.add(temp);
temp = "new"; keywords.add(temp);
temp = "delete"; keywords.add(temp);
temp = "true"; keywords.add(temp);
temp = "typedef"; keywords.add(temp);
temp = "const"; keywords.add(temp);
temp = "virtual"; keywords.add(temp);
temp = "inline"; keywords.add(temp);
temp = "for"; keywords.add(temp);
temp = "break"; keywords.add(temp);
temp = "struct"; keywords.add(temp);
temp = "float"; keywords.add(temp);
temp = "case"; keywords.add(temp);
temp = "enum"; keywords.add(temp);
temp = "this"; keywords.add(temp);
temp = "typeid"; keywords.add(temp);
temp = "double"; keywords.add(temp);
temp = "char"; keywords.add(temp);
temp = "typename"; keywords.add(temp);
temp = "signed"; keywords.add(temp);
temp = "friend"; keywords.add(temp);
temp = "wint_t"; keywords.add(temp);
temp = "default"; keywords.add(temp);
temp = "asm"; keywords.add(temp);
temp = "reinterpret_cast"; keywords.add(temp);
temp = "#define"; keywords.add(temp);
temp = "do"; keywords.add(temp);
temp = "continue"; keywords.add(temp);
temp = "auto"; keywords.add(temp);
temp = "unsigned"; keywords.add(temp);
temp = "size_t"; keywords.add(temp);
temp = "#undef"; keywords.add(temp);
temp = "#pragma"; keywords.add(temp);
temp = "namespace"; keywords.add(temp);
temp = "private"; keywords.add(temp);
temp = "#endif"; keywords.add(temp);
temp = "catch"; keywords.add(temp);
temp = "#else"; keywords.add(temp);
temp = "register"; keywords.add(temp);
temp = "volatile"; keywords.add(temp);
temp = "const_cast"; keywords.add(temp);
temp = "#end"; keywords.add(temp);
temp = "mutable"; keywords.add(temp);
temp = "static_cast"; keywords.add(temp);
temp = "wchar_t"; keywords.add(temp);
temp = "#if"; keywords.add(temp);
temp = "protected"; keywords.add(temp);
temp = "throw"; keywords.add(temp);
temp = "using"; keywords.add(temp);
temp = "dynamic_cast"; keywords.add(temp);
temp = "#ifdef"; keywords.add(temp);
temp = "return"; keywords.add(temp);
temp = "short"; keywords.add(temp);
temp = "#error"; keywords.add(temp);
temp = "#line"; keywords.add(temp);
temp = "explicit"; keywords.add(temp);
temp = "union"; keywords.add(temp);
temp = "#ifndef"; keywords.add(temp);
temp = "try"; keywords.add(temp);
temp = "sizeof"; keywords.add(temp);
temp = "goto"; keywords.add(temp);
temp = "long"; keywords.add(temp);
temp = "#elif"; keywords.add(temp);
temp = "static"; keywords.add(temp);
temp = "operator"; keywords.add(temp);
temp = "switch"; keywords.add(temp);
temp = "extern"; keywords.add(temp);
// set the tokenizer's IDENTIFIER token for C++ identifiers
tokenizer.set_identifier_token(
"$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(),
"$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() +
tokenizer.numbers()
);
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
cpp_tokenizer_kernel_1<tok,queue,set>::
~cpp_tokenizer_kernel_1 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
void cpp_tokenizer_kernel_1<tok,queue,set>::
clear(
)
{
tokenizer.clear();
buffer.clear();
have_peeked = false;
// set the tokenizer's IDENTIFIER token for C++ identifiers
tokenizer.set_identifier_token(
"$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(),
"$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() +
tokenizer.numbers()
);
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
void cpp_tokenizer_kernel_1<tok,queue,set>::
set_stream (
std::istream& in
)
{
tokenizer.set_stream(in);
buffer.clear();
have_peeked = false;
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
bool cpp_tokenizer_kernel_1<tok,queue,set>::
stream_is_set (
) const
{
return tokenizer.stream_is_set();
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
std::istream& cpp_tokenizer_kernel_1<tok,queue,set>::
get_stream (
) const
{
return tokenizer.get_stream();
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
void cpp_tokenizer_kernel_1<tok,queue,set>::
get_token (
int& type,
std::string& token
)
{
using namespace std;
if (!have_peeked)
{
if (buffer.size() > 0)
{
// just return what is in the buffer
token_text_pair temp;
buffer.dequeue(temp);
type = temp.type;
token = temp.token;
return;
}
tokenizer.get_token(type,token);
switch (type)
{
case tok::END_OF_FILE:
{
type = END_OF_FILE;
} break;
case tok::END_OF_LINE:
case tok::WHITE_SPACE:
{
type = tokenizer.peek_type();
if (type == tok::END_OF_LINE || type == tok::WHITE_SPACE)
{
std::string temp;
do
{
tokenizer.get_token(type,temp);
token += temp;
type = tokenizer.peek_type();
}while (type == tok::END_OF_LINE || type == tok::WHITE_SPACE);
}
type = WHITE_SPACE;
} break;
case tok::NUMBER:
{
// this could be a hex number such as 0xa33. we should check for this.
if (tokenizer.peek_type() == tok::IDENTIFIER && token == "0" &&
(tokenizer.peek_token()[0] == 'x' || tokenizer.peek_token()[0] == 'X'))
{
// this is a hex number so accumulate all the numbers and identifiers that follow
// because they have to be part of the number
std::string temp;
tokenizer.get_token(type,temp);
token = "0" + temp;
// get the rest of the hex number
while (tokenizer.peek_type() == tok::IDENTIFIER ||
tokenizer.peek_type() == tok::NUMBER
)
{
tokenizer.get_token(type,temp);
token += temp;
}
}
// or this could be a floating point value or something with an 'e' or 'E' in it.
else if ((tokenizer.peek_type() == tok::CHAR && tokenizer.peek_token()[0] == '.') ||
(tokenizer.peek_type() == tok::IDENTIFIER && std::tolower(tokenizer.peek_token()[0]) == 'e'))
{
std::string temp;
tokenizer.get_token(type,temp);
token += temp;
// now get the rest of the floating point value
while (tokenizer.peek_type() == tok::IDENTIFIER ||
tokenizer.peek_type() == tok::NUMBER
)
{
tokenizer.get_token(type,temp);
token += temp;
}
}
type = NUMBER;
} break;
case tok::IDENTIFIER:
{
if (keywords.is_member(token))
{
type = KEYWORD;
}
else
{
type = IDENTIFIER;
}
} break;
case tok::CHAR:
type = OTHER;
switch (token[0])
{
case '#':
{
// this might be a preprocessor keyword so we should check the
// next token
if (tokenizer.peek_type() == tok::IDENTIFIER &&
keywords.is_member('#'+tokenizer.peek_token()))
{
tokenizer.get_token(type,token);
token = '#' + token;
type = KEYWORD;
}
else
{
token = '#';
type = OTHER;
}
}
break;
case '"':
{
string temp;
tokenizer.get_token(type,token);
while (type != tok::END_OF_FILE)
{
// if this is the end of the quoted string
if (type == tok::CHAR && token[0] == '"' &&
(temp.size() == 0 || temp[temp.size()-1] != '\\' ||
(temp.size() > 1 && temp[temp.size()-2] == '\\') ))
{
buffer_token(DOUBLE_QUOTED_TEXT,temp);
buffer_token(OTHER,"\"");
break;
}
else
{
temp += token;
}
tokenizer.get_token(type,token);
}
type = OTHER;
token = '"';
} break;
case '\'':
{
string temp;
tokenizer.get_token(type,token);
if (type == tok::CHAR && token[0] == '\\')
{
temp += '\\';
tokenizer.get_token(type,token);
}
temp += token;
buffer_token(SINGLE_QUOTED_TEXT,temp);
// The next character should be a ' so take it out and put it in
// the buffer.
tokenizer.get_token(type,token);
buffer_token(OTHER,token);
type = OTHER;
token = '\'';
} break;
case '/':
{
// look ahead to see if this is the start of a comment
if (tokenizer.peek_type() == tok::CHAR)
{
if (tokenizer.peek_token()[0] == '/')
{
tokenizer.get_token(type,token);
// this is the start of a line comment
token = "//";
string temp;
tokenizer.get_token(type,temp);
while (type != tok::END_OF_FILE)
{
// if this is the end of the comment
if (type == tok::END_OF_LINE &&
token[token.size()-1] != '\\' )
{
token += '\n';
break;
}
else
{
token += temp;
}
tokenizer.get_token(type,temp);
}
type = COMMENT;
}
else if (tokenizer.peek_token()[0] == '*')
{
tokenizer.get_token(type,token);
// this is the start of a block comment
token = "/*";
string temp;
tokenizer.get_token(type,temp);
while (type != tok::END_OF_FILE)
{
// if this is the end of the comment
if (type == tok::CHAR && temp[0] == '/' &&
token[token.size()-1] == '*')
{
token += '/';
break;
}
else
{
token += temp;
}
tokenizer.get_token(type,temp);
}
type = COMMENT;
}
}
} break;
default:
break;
} // switch (token[0])
} // switch (type)
}
else
{
// if we get this far it means we have peeked so we should
// return the peek data.
type = next_type;
token = next_token;
have_peeked = false;
}
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
int cpp_tokenizer_kernel_1<tok,queue,set>::
peek_type (
) const
{
const_cast<cpp_tokenizer_kernel_1<tok,queue,set>*>(this)->get_token(next_type,next_token);
have_peeked = true;
return next_type;
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
const std::string& cpp_tokenizer_kernel_1<tok,queue,set>::
peek_token (
) const
{
const_cast<cpp_tokenizer_kernel_1<tok,queue,set>*>(this)->get_token(next_type,next_token);
have_peeked = true;
return next_token;
}
// ----------------------------------------------------------------------------------------
template <
typename tok,
typename queue,
typename set
>
void cpp_tokenizer_kernel_1<tok,queue,set>::
swap (
cpp_tokenizer_kernel_1& item
)
{
tokenizer.swap(item.tokenizer);
buffer.swap(item.buffer);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CPP_TOKENIZER_KERNEl_1_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_
#ifdef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_
#include <string>
#include <ioswfd>
namespace dlib
{
class cpp_tokenizer
{
/*!
INITIAL VALUE
stream_is_set() == false
WHAT THIS OBJECT REPRESENTS
This object represents a simple tokenizer for C++ source code.
BUFFERING
This object is allowed to buffer data from the input stream.
Thus if you clear it or switch streams (via calling set_stream())
any buffered data will be lost.
TOKENS
When picking out tokens the cpp_tokenizer will always extract the
longest token it can. For example, if faced with the string
"AAA" it will consider the three As to be a single IDENTIFIER
token not three smaller IDENTIFIER tokens.
Also note that no characters in the input stream are discarded.
They will all be returned in the text of some token.
Additionally, each character will never be returned more than once.
This means that if you concatenated all returned tokens it would exactly
reproduce the contents of the input stream.
The tokens are defined as follows:
END_OF_FILE
This token represents the end of file. It doesn't have any
actual characters associated with it.
KEYWORD
This token matches a C++ keyword. (This includes the preprocessor
directives).
COMMENT
This token matches a C++ comment.
SINGLE_QUOTED_TEXT
This token matches the text of any single quoted literal.
For example, 'a' would be a match and the text of this token
would be the single character a.
DOUBLE_QUOTED_TEXT
This token matches the text of any double quoted string.
For example, "C++" would be a match and the text of this token
would be the three character string C++.
WHITE_SPACE
This is a multi character token. It is defined as a sequence of
one or more spaces, carrage returns, newlines, and tabs. I.e. It
is composed of characters from the following string " \r\n\t".
IDENTIFIER
This token matches any C++ identifier that isn't matched by any
of the above tokens. (A C++ identifier being a string matching
the regular expression [_$a-zA-Z][_$a-zA-Z0-9]*).
NUMBER
This token matches any C++ numerical constant.
OTHER
This matches anything that isn't part of one of the above tokens.
It is always a single character.
!*/
public:
enum
{
END_OF_FILE,
KEYWORD,
COMMENT,
SINGLE_QUOTED_TEXT,
DOUBLE_QUOTED_TEXT,
IDENTIFIER,
OTHER,
NUMBER,
WHITE_SPACE
};
cpp_tokenizer (
);
/*!
ensures
- #*this is properly initialized
throws
- std::bad_alloc
!*/
virtual ~cpp_tokenizer (
);
/*!
ensures
- any resources associated with *this have 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_stream (
std::istream& in
);
/*!
ensures
- #*this will read data from in and tokenize it
- #stream_is_set() == true
- #get_stream() == in
!*/
bool stream_is_set (
) const;
/*!
ensures
- returns true if a stream has been associated with *this by calling
set_stream()
!*/
std::istream& get_stream (
) const;
/*!
requires
- stream_is_set() == true
ensures
- returns a reference to the istream object that *this is reading
from.
!*/
void get_token (
int& type,
std::string& token
);
/*!
requires
- stream_is_set() == true
ensures
- #token == the next token from the input stream get_stream()
- #type == the type of the token in #token
throws
- bad_alloc
If this exception is thrown then the call to this function will
have no effect on *this but the values of #type and #token will be
undefined. Additionally, some characters may have been read
from the stream get_stream() and lost.
!*/
int peek_type (
) const;
/*!
requires
- stream_is_set() == true
ensures
- returns the type of the token that will be returned from
the next call to get_token()
throws
- bad_alloc
If this exception is thrown then the call to this function will
have no effect on *this. However, some characters may have been
read from the stream get_stream() and lost.
!*/
const std::string& peek_token (
) const;
/*!
requires
- stream_is_set() == true
ensures
- returns the text of the token that will be returned from
the next call to get_token()
throws
- bad_alloc
If this exception is thrown then the call to this function will
have no effect on *this. However, some characters may have been
read from the stream get_stream() and lost.
!*/
void swap (
cpp_tokenizer& item
);
/*!
ensures
- swaps *this and item
!*/
private:
// restricted functions
cpp_tokenizer(const cpp_tokenizer&); // copy constructor
cpp_tokenizer& operator=(const cpp_tokenizer&); // assignment operator
};
inline void swap (
cpp_tokenizer& a,
cpp_tokenizer& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
}
#endif // DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_TOKENIZER_KERNEl_C_
#define DLIB_CPP_TOKENIZER_KERNEl_C_
#include "cpp_tokenizer_kernel_abstract.h"
#include "../assert.h"
#include <string>
#include <iostream>
namespace dlib
{
template <
typename tokenizer
>
class cpp_tokenizer_kernel_c : public tokenizer
{
public:
std::istream& get_stream (
) const;
void get_token (
int& type,
std::string& token
);
int peek_type (
) const;
const std::string& peek_token (
) const;
};
template <
typename tokenizer
>
inline void swap (
cpp_tokenizer_kernel_c<tokenizer>& a,
cpp_tokenizer_kernel_c<tokenizer>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename tokenizer
>
std::istream& cpp_tokenizer_kernel_c<tokenizer>::
get_stream (
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->stream_is_set() == true,
"\tstd::istream& cpp_tokenizer::get_stream()"
<< "\n\tyou must set a stream for this object before you can get it"
<< "\n\tthis: " << this
);
// call the real function
return tokenizer::get_stream();
}
// ----------------------------------------------------------------------------------------
template <
typename tokenizer
>
const std::string& cpp_tokenizer_kernel_c<tokenizer>::
peek_token (
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->stream_is_set() == true,
"\tconst std::string& cpp_tokenizer::peek_token()"
<< "\n\tyou must set a stream for this object before you can peek at what it contains"
<< "\n\tthis: " << this
);
// call the real function
return tokenizer::peek_token();
}
// ----------------------------------------------------------------------------------------
template <
typename tokenizer
>
int cpp_tokenizer_kernel_c<tokenizer>::
peek_type (
) const
{
// make sure requires clause is not broken
DLIB_CASSERT( this->stream_is_set() == true,
"\tint cpp_tokenizer::peek_type()"
<< "\n\tyou must set a stream for this object before you can peek at what it contains"
<< "\n\tthis: " << this
);
// call the real function
return tokenizer::peek_type();
}
// ----------------------------------------------------------------------------------------
template <
typename tokenizer
>
void cpp_tokenizer_kernel_c<tokenizer>::
get_token (
int& type,
std::string& token
)
{
// make sure requires clause is not broken
DLIB_CASSERT( this->stream_is_set() == true,
"\tvoid cpp_tokenizer::get_token()"
<< "\n\tyou must set a stream for this object before you can get tokens from it."
<< "\n\tthis: " << this
);
// call the real function
tokenizer::get_token(type,token);
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_TOKENIZER_KERNEl_C_
// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CRc32_
#define DLIB_CRc32_
#include "crc32/crc32_kernel_1.h"
#endif // DLIB_CRc32_
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment