Squashed 'boost/' changes from b4feb19f2..d9443bc48

d9443bc48 Add the multi_index, intrusive and date_time libraries

git-subtree-dir: boost
git-subtree-split: d9443bc4849970cd15c886aae652bb3fcd8e1c6e
This commit is contained in:
Bill Somerville 2018-10-19 02:58:34 +01:00
parent 4ebe6417a5
commit edd0930758
2282 changed files with 38788 additions and 258352 deletions

View File

@ -9,6 +9,7 @@ upstream and master. To upgrade the content do the following:
git checkout upstream
rm -r *
# use the bcp tool to populate with the new Boost libraries
# use git add to stage any new files and directories
git commit -a -m "Updated Boost v1.63 libraries including ..."
git tag boost_1_63
git push origin

View File

@ -0,0 +1,767 @@
#ifndef _DATE_TIME_DATE_FACET__HPP___
#define _DATE_TIME_DATE_FACET__HPP___
/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Martin Andrian, Jeff Garland, Bart Garst
* $Date$
*/
#include <locale>
#include <string>
#include <vector>
#include <iterator> // ostreambuf_iterator
#include <boost/throw_exception.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/date_time/compiler_config.hpp>
#include <boost/date_time/period.hpp>
#include <boost/date_time/special_defs.hpp>
#include <boost/date_time/special_values_formatter.hpp>
#include <boost/date_time/period_formatter.hpp>
#include <boost/date_time/period_parser.hpp>
#include <boost/date_time/date_generator_formatter.hpp>
#include <boost/date_time/date_generator_parser.hpp>
#include <boost/date_time/format_date_parser.hpp>
namespace boost { namespace date_time {
/*! Class that provides format based I/O facet for date types.
*
* This class allows the formatting of dates by using format string.
* Format strings are:
*
* - %A => long_weekday_format - Full name Ex: Tuesday
* - %a => short_weekday_format - Three letter abbreviation Ex: Tue
* - %B => long_month_format - Full name Ex: October
* - %b => short_month_format - Three letter abbreviation Ex: Oct
* - %x => standard_format_specifier - defined by the locale
* - %Y-%b-%d => default_date_format - YYYY-Mon-dd
*
* Default month format == %b
* Default weekday format == %a
*/
template <class date_type,
class CharT,
class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
class date_facet : public std::locale::facet {
public:
typedef typename date_type::duration_type duration_type;
// greg_weekday is gregorian_calendar::day_of_week_type
typedef typename date_type::day_of_week_type day_of_week_type;
typedef typename date_type::day_type day_type;
typedef typename date_type::month_type month_type;
typedef boost::date_time::period<date_type,duration_type> period_type;
typedef std::basic_string<CharT> string_type;
typedef CharT char_type;
typedef boost::date_time::period_formatter<CharT> period_formatter_type;
typedef boost::date_time::special_values_formatter<CharT> special_values_formatter_type;
typedef std::vector<std::basic_string<CharT> > input_collection_type;
// used for the output of the date_generators
typedef date_generator_formatter<date_type, CharT> date_gen_formatter_type;
typedef partial_date<date_type> partial_date_type;
typedef nth_kday_of_month<date_type> nth_kday_type;
typedef first_kday_of_month<date_type> first_kday_type;
typedef last_kday_of_month<date_type> last_kday_type;
typedef first_kday_after<date_type> kday_after_type;
typedef first_kday_before<date_type> kday_before_type;
static const char_type long_weekday_format[3];
static const char_type short_weekday_format[3];
static const char_type long_month_format[3];
static const char_type short_month_format[3];
static const char_type default_period_separator[4];
static const char_type standard_format_specifier[3];
static const char_type iso_format_specifier[7];
static const char_type iso_format_extended_specifier[9];
static const char_type default_date_format[9]; // YYYY-Mon-DD
static std::locale::id id;
#if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
std::locale::id& __get_id (void) const { return id; }
#endif
explicit date_facet(::size_t a_ref = 0)
: std::locale::facet(a_ref),
//m_format(standard_format_specifier)
m_format(default_date_format),
m_month_format(short_month_format),
m_weekday_format(short_weekday_format)
{}
explicit date_facet(const char_type* format_str,
const input_collection_type& short_names,
::size_t ref_count = 0)
: std::locale::facet(ref_count),
m_format(format_str),
m_month_format(short_month_format),
m_weekday_format(short_weekday_format),
m_month_short_names(short_names)
{}
explicit date_facet(const char_type* format_str,
period_formatter_type per_formatter = period_formatter_type(),
special_values_formatter_type sv_formatter = special_values_formatter_type(),
date_gen_formatter_type dg_formatter = date_gen_formatter_type(),
::size_t ref_count = 0)
: std::locale::facet(ref_count),
m_format(format_str),
m_month_format(short_month_format),
m_weekday_format(short_weekday_format),
m_period_formatter(per_formatter),
m_date_gen_formatter(dg_formatter),
m_special_values_formatter(sv_formatter)
{}
void format(const char_type* const format_str) {
m_format = format_str;
}
virtual void set_iso_format()
{
m_format = iso_format_specifier;
}
virtual void set_iso_extended_format()
{
m_format = iso_format_extended_specifier;
}
void month_format(const char_type* const format_str) {
m_month_format = format_str;
}
void weekday_format(const char_type* const format_str) {
m_weekday_format = format_str;
}
void period_formatter(period_formatter_type per_formatter) {
m_period_formatter= per_formatter;
}
void special_values_formatter(const special_values_formatter_type& svf)
{
m_special_values_formatter = svf;
}
void short_weekday_names(const input_collection_type& short_names)
{
m_weekday_short_names = short_names;
}
void long_weekday_names(const input_collection_type& long_names)
{
m_weekday_long_names = long_names;
}
void short_month_names(const input_collection_type& short_names)
{
m_month_short_names = short_names;
}
void long_month_names(const input_collection_type& long_names)
{
m_month_long_names = long_names;
}
void date_gen_phrase_strings(const input_collection_type& new_strings,
typename date_gen_formatter_type::phrase_elements beg_pos=date_gen_formatter_type::first)
{
m_date_gen_formatter.elements(new_strings, beg_pos);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const date_type& d) const
{
if (d.is_special()) {
return do_put_special(next, a_ios, fill_char, d.as_special());
}
//The following line of code required the date to support a to_tm function
return do_put_tm(next, a_ios, fill_char, to_tm(d), m_format);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const duration_type& dd) const
{
if (dd.is_special()) {
return do_put_special(next, a_ios, fill_char, dd.get_rep().as_special());
}
typedef std::num_put<CharT, OutItrT> num_put;
if (std::has_facet<num_put>(a_ios.getloc())) {
return std::use_facet<num_put>(a_ios.getloc()).put(next, a_ios, fill_char, dd.get_rep().as_number());
}
else {
num_put* f = new num_put();
std::locale l = std::locale(a_ios.getloc(), f);
a_ios.imbue(l);
return f->put(next, a_ios, fill_char, dd.get_rep().as_number());
}
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const month_type& m) const
{
//if (d.is_special()) {
// return do_put_special(next, a_ios, fill_char, d.as_special());
//}
//The following line of code required the date to support a to_tm function
std::tm dtm;
std::memset(&dtm, 0, sizeof(dtm));
dtm.tm_mon = m - 1;
return do_put_tm(next, a_ios, fill_char, dtm, m_month_format);
}
//! puts the day of month
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const day_type& day) const
{
std::tm dtm;
std::memset(&dtm, 0, sizeof(dtm));
dtm.tm_mday = day.as_number();
char_type tmp[3] = {'%','d'};
string_type temp_format(tmp);
return do_put_tm(next, a_ios, fill_char, dtm, temp_format);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const day_of_week_type& dow) const
{
//if (d.is_special()) {
// return do_put_special(next, a_ios, fill_char, d.as_special());
//}
//The following line of code required the date to support a to_tm function
std::tm dtm;
std::memset(&dtm, 0, sizeof(dtm));
dtm.tm_wday = dow;
return do_put_tm(next, a_ios, fill_char, dtm, m_weekday_format);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const period_type& p) const
{
return m_period_formatter.put_period(next, a_ios, fill_char, p, *this);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const partial_date_type& pd) const
{
return m_date_gen_formatter.put_partial_date(next, a_ios, fill_char, pd, *this);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const nth_kday_type& nkd) const
{
return m_date_gen_formatter.put_nth_kday(next, a_ios, fill_char, nkd, *this);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const first_kday_type& fkd) const
{
return m_date_gen_formatter.put_first_kday(next, a_ios, fill_char, fkd, *this);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const last_kday_type& lkd) const
{
return m_date_gen_formatter.put_last_kday(next, a_ios, fill_char, lkd, *this);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const kday_before_type& fkb) const
{
return m_date_gen_formatter.put_kday_before(next, a_ios, fill_char, fkb, *this);
}
OutItrT put(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const kday_after_type& fka) const
{
return m_date_gen_formatter.put_kday_after(next, a_ios, fill_char, fka, *this);
}
protected:
virtual OutItrT do_put_special(OutItrT next,
std::ios_base& /*a_ios*/,
char_type /*fill_char*/,
const boost::date_time::special_values sv) const
{
m_special_values_formatter.put_special(next, sv);
return next;
}
virtual OutItrT do_put_tm(OutItrT next,
std::ios_base& a_ios,
char_type fill_char,
const tm& tm_value,
string_type a_format) const
{
// update format string with custom names
if (m_weekday_long_names.size()) {
boost::algorithm::replace_all(a_format,
long_weekday_format,
m_weekday_long_names[tm_value.tm_wday]);
}
if (m_weekday_short_names.size()) {
boost::algorithm::replace_all(a_format,
short_weekday_format,
m_weekday_short_names[tm_value.tm_wday]);
}
if (m_month_long_names.size()) {
boost::algorithm::replace_all(a_format,
long_month_format,
m_month_long_names[tm_value.tm_mon]);
}
if (m_month_short_names.size()) {
boost::algorithm::replace_all(a_format,
short_month_format,
m_month_short_names[tm_value.tm_mon]);
}
// use time_put facet to create final string
const char_type* p_format = a_format.c_str();
return std::use_facet<std::time_put<CharT> >(a_ios.getloc()).put(next, a_ios,
fill_char,
&tm_value,
p_format,
p_format + a_format.size());
}
protected:
string_type m_format;
string_type m_month_format;
string_type m_weekday_format;
period_formatter_type m_period_formatter;
date_gen_formatter_type m_date_gen_formatter;
special_values_formatter_type m_special_values_formatter;
input_collection_type m_month_short_names;
input_collection_type m_month_long_names;
input_collection_type m_weekday_short_names;
input_collection_type m_weekday_long_names;
private:
};
template <class date_type, class CharT, class OutItrT>
std::locale::id date_facet<date_type, CharT, OutItrT>::id;
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::long_weekday_format[3] = {'%','A'};
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::short_weekday_format[3] = {'%','a'};
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::long_month_format[3] = {'%','B'};
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::short_month_format[3] = {'%','b'};
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::default_period_separator[4] = { ' ', '/', ' '};
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::standard_format_specifier[3] =
{'%', 'x' };
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::iso_format_specifier[7] =
{'%', 'Y', '%', 'm', '%', 'd' };
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::iso_format_extended_specifier[9] =
{'%', 'Y', '-', '%', 'm', '-', '%', 'd' };
template <class date_type, class CharT, class OutItrT>
const typename date_facet<date_type, CharT, OutItrT>::char_type
date_facet<date_type, CharT, OutItrT>::default_date_format[9] =
{'%','Y','-','%','b','-','%','d'};
//! Input facet
template <class date_type,
class CharT,
class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > >
class date_input_facet : public std::locale::facet {
public:
typedef typename date_type::duration_type duration_type;
// greg_weekday is gregorian_calendar::day_of_week_type
typedef typename date_type::day_of_week_type day_of_week_type;
typedef typename date_type::day_type day_type;
typedef typename date_type::month_type month_type;
typedef typename date_type::year_type year_type;
typedef boost::date_time::period<date_type,duration_type> period_type;
typedef std::basic_string<CharT> string_type;
typedef CharT char_type;
typedef boost::date_time::period_parser<date_type, CharT> period_parser_type;
typedef boost::date_time::special_values_parser<date_type,CharT> special_values_parser_type;
typedef std::vector<std::basic_string<CharT> > input_collection_type;
typedef format_date_parser<date_type, CharT> format_date_parser_type;
// date_generators stuff goes here
typedef date_generator_parser<date_type, CharT> date_gen_parser_type;
typedef partial_date<date_type> partial_date_type;
typedef nth_kday_of_month<date_type> nth_kday_type;
typedef first_kday_of_month<date_type> first_kday_type;
typedef last_kday_of_month<date_type> last_kday_type;
typedef first_kday_after<date_type> kday_after_type;
typedef first_kday_before<date_type> kday_before_type;
static const char_type long_weekday_format[3];
static const char_type short_weekday_format[3];
static const char_type long_month_format[3];
static const char_type short_month_format[3];
static const char_type four_digit_year_format[3];
static const char_type two_digit_year_format[3];
static const char_type default_period_separator[4];
static const char_type standard_format_specifier[3];
static const char_type iso_format_specifier[7];
static const char_type iso_format_extended_specifier[9];
static const char_type default_date_format[9]; // YYYY-Mon-DD
static std::locale::id id;
explicit date_input_facet(::size_t a_ref = 0)
: std::locale::facet(a_ref),
m_format(default_date_format),
m_month_format(short_month_format),
m_weekday_format(short_weekday_format),
m_year_format(four_digit_year_format),
m_parser(m_format, std::locale::classic())
// default period_parser & special_values_parser used
{}
explicit date_input_facet(const string_type& format_str,
::size_t a_ref = 0)
: std::locale::facet(a_ref),
m_format(format_str),
m_month_format(short_month_format),
m_weekday_format(short_weekday_format),
m_year_format(four_digit_year_format),
m_parser(m_format, std::locale::classic())
// default period_parser & special_values_parser used
{}
explicit date_input_facet(const string_type& format_str,
const format_date_parser_type& date_parser,
const special_values_parser_type& sv_parser,
const period_parser_type& per_parser,
const date_gen_parser_type& date_gen_parser,
::size_t ref_count = 0)
: std::locale::facet(ref_count),
m_format(format_str),
m_month_format(short_month_format),
m_weekday_format(short_weekday_format),
m_year_format(four_digit_year_format),
m_parser(date_parser),
m_date_gen_parser(date_gen_parser),
m_period_parser(per_parser),
m_sv_parser(sv_parser)
{}
void format(const char_type* const format_str) {
m_format = format_str;
}
virtual void set_iso_format()
{
m_format = iso_format_specifier;
}
virtual void set_iso_extended_format()
{
m_format = iso_format_extended_specifier;
}
void month_format(const char_type* const format_str) {
m_month_format = format_str;
}
void weekday_format(const char_type* const format_str) {
m_weekday_format = format_str;
}
void year_format(const char_type* const format_str) {
m_year_format = format_str;
}
void period_parser(period_parser_type per_parser) {
m_period_parser = per_parser;
}
void short_weekday_names(const input_collection_type& weekday_names)
{
m_parser.short_weekday_names(weekday_names);
}
void long_weekday_names(const input_collection_type& weekday_names)
{
m_parser.long_weekday_names(weekday_names);
}
void short_month_names(const input_collection_type& month_names)
{
m_parser.short_month_names(month_names);
}
void long_month_names(const input_collection_type& month_names)
{
m_parser.long_month_names(month_names);
}
void date_gen_element_strings(const input_collection_type& col)
{
m_date_gen_parser.element_strings(col);
}
void date_gen_element_strings(const string_type& first,
const string_type& second,
const string_type& third,
const string_type& fourth,
const string_type& fifth,
const string_type& last,
const string_type& before,
const string_type& after,
const string_type& of)
{
m_date_gen_parser.element_strings(first,second,third,fourth,fifth,last,before,after,of);
}
void special_values_parser(special_values_parser_type sv_parser)
{
m_sv_parser = sv_parser;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& /*a_ios*/,
date_type& d) const
{
d = m_parser.parse_date(from, to, m_format, m_sv_parser);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& /*a_ios*/,
month_type& m) const
{
m = m_parser.parse_month(from, to, m_month_format);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& /*a_ios*/,
day_of_week_type& wd) const
{
wd = m_parser.parse_weekday(from, to, m_weekday_format);
return from;
}
//! Expects 1 or 2 digit day range: 1-31
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& /*a_ios*/,
day_type& d) const
{
d = m_parser.parse_var_day_of_month(from, to);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& /*a_ios*/,
year_type& y) const
{
y = m_parser.parse_year(from, to, m_year_format);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
duration_type& dd) const
{
// skip leading whitespace
while(std::isspace(*from) && from != to) { ++from; }
/* num_get.get() will always consume the first character if it
* is a sign indicator (+/-). Special value strings may begin
* with one of these signs so we'll need a copy of it
* in case num_get.get() fails. */
char_type c = '\0';
// TODO Are these characters somewhere in the locale?
if(*from == '-' || *from == '+') {
c = *from;
}
typedef std::num_get<CharT, InItrT> num_get;
typename duration_type::duration_rep_type val = 0;
std::ios_base::iostate err = std::ios_base::goodbit;
if (std::has_facet<num_get>(a_ios.getloc())) {
from = std::use_facet<num_get>(a_ios.getloc()).get(from, to, a_ios, err, val);
}
else {
num_get* ng = new num_get();
std::locale l = std::locale(a_ios.getloc(), ng);
a_ios.imbue(l);
from = ng->get(from, to, a_ios, err, val);
}
if(err & std::ios_base::failbit){
typedef typename special_values_parser_type::match_results match_results;
match_results mr;
if(c == '-' || c == '+') { // was the first character consumed?
mr.cache += c;
}
m_sv_parser.match(from, to, mr);
if(mr.current_match == match_results::PARSE_ERROR) {
boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'"));
BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return from); // should never reach
}
dd = duration_type(static_cast<special_values>(mr.current_match));
}
else {
dd = duration_type(val);
}
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
period_type& p) const
{
p = m_period_parser.get_period(from, to, a_ios, p, duration_type::unit(), *this);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
nth_kday_type& nkd) const
{
nkd = m_date_gen_parser.get_nth_kday_type(from, to, a_ios, *this);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
partial_date_type& pd) const
{
pd = m_date_gen_parser.get_partial_date_type(from, to, a_ios, *this);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
first_kday_type& fkd) const
{
fkd = m_date_gen_parser.get_first_kday_type(from, to, a_ios, *this);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
last_kday_type& lkd) const
{
lkd = m_date_gen_parser.get_last_kday_type(from, to, a_ios, *this);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
kday_before_type& fkb) const
{
fkb = m_date_gen_parser.get_kday_before_type(from, to, a_ios, *this);
return from;
}
InItrT get(InItrT& from,
InItrT& to,
std::ios_base& a_ios,
kday_after_type& fka) const
{
fka = m_date_gen_parser.get_kday_after_type(from, to, a_ios, *this);
return from;
}
protected:
string_type m_format;
string_type m_month_format;
string_type m_weekday_format;
string_type m_year_format;
format_date_parser_type m_parser;
date_gen_parser_type m_date_gen_parser;
period_parser_type m_period_parser;
special_values_parser_type m_sv_parser;
private:
};
template <class date_type, class CharT, class OutItrT>
std::locale::id date_input_facet<date_type, CharT, OutItrT>::id;
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::long_weekday_format[3] = {'%','A'};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::short_weekday_format[3] = {'%','a'};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::long_month_format[3] = {'%','B'};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::short_month_format[3] = {'%','b'};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::four_digit_year_format[3] = {'%','Y'};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::two_digit_year_format[3] = {'%','y'};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::default_period_separator[4] = { ' ', '/', ' '};
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::standard_format_specifier[3] =
{'%', 'x' };
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::iso_format_specifier[7] =
{'%', 'Y', '%', 'm', '%', 'd' };
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::iso_format_extended_specifier[9] =
{'%', 'Y', '-', '%', 'm', '-', '%', 'd' };
template <class date_type, class CharT, class OutItrT>
const typename date_input_facet<date_type, CharT, OutItrT>::char_type
date_input_facet<date_type, CharT, OutItrT>::default_date_format[9] =
{'%','Y','-','%','b','-','%','d'};
} } // namespaces
#endif

View File

@ -0,0 +1,265 @@
#ifndef _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___
#define _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___
/* Copyright (c) 2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "boost/date_time/date_generators.hpp"
namespace boost {
namespace date_time {
//! Formats date_generators for output
/*! Formatting of date_generators follows specific orders for the
* various types of date_generators.
* - partial_date => "dd Month"
* - nth_day_of_the_week_in_month => "nth weekday of month"
* - first_day_of_the_week_in_month => "first weekday of month"
* - last_day_of_the_week_in_month => "last weekday of month"
* - first_day_of_the_week_after => "weekday after"
* - first_day_of_the_week_before => "weekday before"
* While the order of the elements in these phrases cannot be changed,
* the elements themselves can be. Weekday and Month get their formats
* and names from the date_facet. The remaining elements are stored in
* the date_generator_formatter and can be customized upon construction
* or via a member function. The default elements are those shown in the
* examples above.
*/
template <class date_type, class CharT, class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
class date_generator_formatter {
public:
typedef partial_date<date_type> partial_date_type;
typedef nth_kday_of_month<date_type> nth_kday_type;
typedef first_kday_of_month<date_type> first_kday_type;
typedef last_kday_of_month<date_type> last_kday_type;
typedef first_kday_after<date_type> kday_after_type;
typedef first_kday_before<date_type> kday_before_type;
typedef CharT char_type;
typedef std::basic_string<char_type> string_type;
typedef std::vector<string_type> collection_type;
static const char_type first_string[6];
static const char_type second_string[7];
static const char_type third_string[6];
static const char_type fourth_string[7];
static const char_type fifth_string[6];
static const char_type last_string[5];
static const char_type before_string[8];
static const char_type after_string[6];
static const char_type of_string[3];
enum phrase_elements {first=0, second, third, fourth, fifth, last,
before, after, of, number_of_phrase_elements};
//! Default format elements used
date_generator_formatter()
{
phrase_strings.reserve(number_of_phrase_elements);
phrase_strings.push_back(string_type(first_string));
phrase_strings.push_back(string_type(second_string));
phrase_strings.push_back(string_type(third_string));
phrase_strings.push_back(string_type(fourth_string));
phrase_strings.push_back(string_type(fifth_string));
phrase_strings.push_back(string_type(last_string));
phrase_strings.push_back(string_type(before_string));
phrase_strings.push_back(string_type(after_string));
phrase_strings.push_back(string_type(of_string));
}
//! Constructor that allows for a custom set of phrase elements
date_generator_formatter(const string_type& first_str,
const string_type& second_str,
const string_type& third_str,
const string_type& fourth_str,
const string_type& fifth_str,
const string_type& last_str,
const string_type& before_str,
const string_type& after_str,
const string_type& of_str)
{
phrase_strings.reserve(number_of_phrase_elements);
phrase_strings.push_back(first_str);
phrase_strings.push_back(second_str);
phrase_strings.push_back(third_str);
phrase_strings.push_back(fourth_str);
phrase_strings.push_back(fifth_str);
phrase_strings.push_back(last_str);
phrase_strings.push_back(before_str);
phrase_strings.push_back(after_str);
phrase_strings.push_back(of_str);
}
//! Replace the set of phrase elements with those contained in new_strings
/*! The order of the strings in the given collection is important.
* They must follow:
* - first, second, third, fourth, fifth, last, before, after, of.
*
* It is not necessary to send in a complete set if only a few
* elements are to be replaced as long as the correct beg_pos is used.
*
* Ex: To keep the default first through fifth elements, but replace
* the rest with a collection of:
* - "final", "prior", "following", "in".
* The beg_pos of date_generator_formatter::last would be used.
*/
void elements(const collection_type& new_strings,
phrase_elements beg_pos=first)
{
if(beg_pos < number_of_phrase_elements) {
typename collection_type::iterator itr = phrase_strings.begin();
itr += beg_pos;
std::copy(new_strings.begin(), new_strings.end(),
itr);
//phrase_strings.begin());
}
}
//!Put a partial_date => "dd Month"
template<class facet_type>
OutItrT put_partial_date(OutItrT next, std::ios_base& a_ios,
CharT a_fill, const partial_date_type& pd,
const facet_type& facet) const
{
facet.put(next, a_ios, a_fill, pd.day());
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, pd.month());
return next;
}
//! Put an nth_day_of_the_week_in_month => "nth weekday of month"
template<class facet_type>
OutItrT put_nth_kday(OutItrT next, std::ios_base& a_ios,
CharT a_fill, const nth_kday_type& nkd,
const facet_type& facet) const
{
put_string(next, phrase_strings[nkd.nth_week() -1]);
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, nkd.day_of_week());
next = a_fill; //TODO change this ???
put_string(next, string_type(of_string));
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, nkd.month());
return next;
}
//! Put a first_day_of_the_week_in_month => "first weekday of month"
template<class facet_type>
OutItrT put_first_kday(OutItrT next, std::ios_base& a_ios,
CharT a_fill, const first_kday_type& fkd,
const facet_type& facet) const
{
put_string(next, phrase_strings[first]);
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, fkd.day_of_week());
next = a_fill; //TODO change this ???
put_string(next, string_type(of_string));
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, fkd.month());
return next;
}
//! Put a last_day_of_the_week_in_month => "last weekday of month"
template<class facet_type>
OutItrT put_last_kday(OutItrT next, std::ios_base& a_ios,
CharT a_fill, const last_kday_type& lkd,
const facet_type& facet) const
{
put_string(next, phrase_strings[last]);
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, lkd.day_of_week());
next = a_fill; //TODO change this ???
put_string(next, string_type(of_string));
next = a_fill; //TODO change this ???
facet.put(next, a_ios, a_fill, lkd.month());
return next;
}
//! Put a first_day_of_the_week_before => "weekday before"
template<class facet_type>
OutItrT put_kday_before(OutItrT next, std::ios_base& a_ios,
CharT a_fill, const kday_before_type& fkb,
const facet_type& facet) const
{
facet.put(next, a_ios, a_fill, fkb.day_of_week());
next = a_fill; //TODO change this ???
put_string(next, phrase_strings[before]);
return next;
}
//! Put a first_day_of_the_week_after => "weekday after"
template<class facet_type>
OutItrT put_kday_after(OutItrT next, std::ios_base& a_ios,
CharT a_fill, const kday_after_type& fka,
const facet_type& facet) const
{
facet.put(next, a_ios, a_fill, fka.day_of_week());
next = a_fill; //TODO change this ???
put_string(next, phrase_strings[after]);
return next;
}
private:
collection_type phrase_strings;
//! helper function to put the various member string into stream
OutItrT put_string(OutItrT next, const string_type& str) const
{
typename string_type::const_iterator itr = str.begin();
while(itr != str.end()) {
*next = *itr;
++itr;
++next;
}
return next;
}
};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::first_string[6] =
{'f','i','r','s','t'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::second_string[7] =
{'s','e','c','o','n','d'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::third_string[6] =
{'t','h','i','r','d'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::fourth_string[7] =
{'f','o','u','r','t','h'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::fifth_string[6] =
{'f','i','f','t','h'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::last_string[5] =
{'l','a','s','t'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::before_string[8] =
{'b','e','f','o','r','e'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::after_string[6] =
{'a','f','t','e','r'};
template<class date_type, class CharT, class OutItrT>
const typename date_generator_formatter<date_type, CharT, OutItrT>::char_type
date_generator_formatter<date_type, CharT, OutItrT>::of_string[3] =
{'o','f'};
} } // namespaces
#endif // _DATE_TIME_DATE_GENERATOR_FORMATTER__HPP___

View File

@ -0,0 +1,330 @@
#ifndef DATE_TIME_DATE_GENERATOR_PARSER_HPP__
#define DATE_TIME_DATE_GENERATOR_PARSER_HPP__
/* Copyright (c) 2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <string>
#include <vector>
#include <iterator> // istreambuf_iterator
#include <boost/throw_exception.hpp>
#include <boost/date_time/compiler_config.hpp>
#include <boost/date_time/string_parse_tree.hpp>
#include <boost/date_time/date_generators.hpp>
#include <boost/date_time/format_date_parser.hpp>
namespace boost { namespace date_time {
//! Class for date_generator parsing
/*! The elements of a date_generator "phrase" are parsed from the input stream in a
* particular order. All elements are required and the order in which they appear
* cannot change, however, the elements themselves can be changed. The default
* elements and their order are as follows:
*
* - partial_date => "dd Month"
* - nth_day_of_the_week_in_month => "nth weekday of month"
* - first_day_of_the_week_in_month => "first weekday of month"
* - last_day_of_the_week_in_month => "last weekday of month"
* - first_day_of_the_week_after => "weekday after"
* - first_day_of_the_week_before => "weekday before"
*
* Weekday and Month names and formats are handled via the date_input_facet.
*
*/
template<class date_type, typename charT>
class date_generator_parser
{
public:
typedef std::basic_string<charT> string_type;
typedef std::istreambuf_iterator<charT> stream_itr_type;
typedef typename date_type::month_type month_type;
typedef typename date_type::day_of_week_type day_of_week_type;
typedef typename date_type::day_type day_type;
typedef string_parse_tree<charT> parse_tree_type;
typedef typename parse_tree_type::parse_match_result_type match_results;
typedef std::vector<std::basic_string<charT> > collection_type;
typedef partial_date<date_type> partial_date_type;
typedef nth_kday_of_month<date_type> nth_kday_type;
typedef first_kday_of_month<date_type> first_kday_type;
typedef last_kday_of_month<date_type> last_kday_type;
typedef first_kday_after<date_type> kday_after_type;
typedef first_kday_before<date_type> kday_before_type;
typedef charT char_type;
static const char_type first_string[6];
static const char_type second_string[7];
static const char_type third_string[6];
static const char_type fourth_string[7];
static const char_type fifth_string[6];
static const char_type last_string[5];
static const char_type before_string[8];
static const char_type after_string[6];
static const char_type of_string[3];
enum phrase_elements {first=0, second, third, fourth, fifth, last,
before, after, of, number_of_phrase_elements};
//! Creates a date_generator_parser with the default set of "element_strings"
date_generator_parser()
{
element_strings(string_type(first_string),
string_type(second_string),
string_type(third_string),
string_type(fourth_string),
string_type(fifth_string),
string_type(last_string),
string_type(before_string),
string_type(after_string),
string_type(of_string));
}
//! Creates a date_generator_parser using a user defined set of element strings
date_generator_parser(const string_type& first_str,
const string_type& second_str,
const string_type& third_str,
const string_type& fourth_str,
const string_type& fifth_str,
const string_type& last_str,
const string_type& before_str,
const string_type& after_str,
const string_type& of_str)
{
element_strings(first_str, second_str, third_str, fourth_str, fifth_str,
last_str, before_str, after_str, of_str);
}
//! Replace strings that determine nth week for generator
void element_strings(const string_type& first_str,
const string_type& second_str,
const string_type& third_str,
const string_type& fourth_str,
const string_type& fifth_str,
const string_type& last_str,
const string_type& before_str,
const string_type& after_str,
const string_type& of_str)
{
collection_type phrases;
phrases.push_back(first_str);
phrases.push_back(second_str);
phrases.push_back(third_str);
phrases.push_back(fourth_str);
phrases.push_back(fifth_str);
phrases.push_back(last_str);
phrases.push_back(before_str);
phrases.push_back(after_str);
phrases.push_back(of_str);
m_element_strings = parse_tree_type(phrases, this->first); // enum first
}
void element_strings(const collection_type& col)
{
m_element_strings = parse_tree_type(col, this->first); // enum first
}
//! returns partial_date parsed from stream
template<class facet_type>
partial_date_type
get_partial_date_type(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
day_type d(1);
month_type m(1);
facet.get(sitr, stream_end, a_ios, d);
facet.get(sitr, stream_end, a_ios, m);
return partial_date_type(d,m);
}
//! returns nth_kday_of_week parsed from stream
template<class facet_type>
nth_kday_type
get_nth_kday_type(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
typename nth_kday_type::week_num wn;
day_of_week_type wd(0); // no default constructor
month_type m(1); // no default constructor
match_results mr = m_element_strings.match(sitr, stream_end);
switch(mr.current_match) {
case first : { wn = nth_kday_type::first; break; }
case second : { wn = nth_kday_type::second; break; }
case third : { wn = nth_kday_type::third; break; }
case fourth : { wn = nth_kday_type::fourth; break; }
case fifth : { wn = nth_kday_type::fifth; break; }
default:
{
boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'"));
BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(wn = nth_kday_type::first);
}
} // week num
facet.get(sitr, stream_end, a_ios, wd); // day_of_week
extract_element(sitr, stream_end, of); // "of" element
facet.get(sitr, stream_end, a_ios, m); // month
return nth_kday_type(wn, wd, m);
}
//! returns first_kday_of_week parsed from stream
template<class facet_type>
first_kday_type
get_first_kday_type(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
day_of_week_type wd(0); // no default constructor
month_type m(1); // no default constructor
extract_element(sitr, stream_end, first); // "first" element
facet.get(sitr, stream_end, a_ios, wd); // day_of_week
extract_element(sitr, stream_end, of); // "of" element
facet.get(sitr, stream_end, a_ios, m); // month
return first_kday_type(wd, m);
}
//! returns last_kday_of_week parsed from stream
template<class facet_type>
last_kday_type
get_last_kday_type(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
day_of_week_type wd(0); // no default constructor
month_type m(1); // no default constructor
extract_element(sitr, stream_end, last); // "last" element
facet.get(sitr, stream_end, a_ios, wd); // day_of_week
extract_element(sitr, stream_end, of); // "of" element
facet.get(sitr, stream_end, a_ios, m); // month
return last_kday_type(wd, m);
}
//! returns first_kday_of_week parsed from stream
template<class facet_type>
kday_before_type
get_kday_before_type(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
day_of_week_type wd(0); // no default constructor
facet.get(sitr, stream_end, a_ios, wd); // day_of_week
extract_element(sitr, stream_end, before);// "before" element
return kday_before_type(wd);
}
//! returns first_kday_of_week parsed from stream
template<class facet_type>
kday_after_type
get_kday_after_type(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
day_of_week_type wd(0); // no default constructor
facet.get(sitr, stream_end, a_ios, wd); // day_of_week
extract_element(sitr, stream_end, after); // "after" element
return kday_after_type(wd);
}
private:
parse_tree_type m_element_strings;
//! Extracts phrase element from input. Throws ios_base::failure on error.
void extract_element(stream_itr_type& sitr,
stream_itr_type& stream_end,
typename date_generator_parser::phrase_elements ele) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
match_results mr = m_element_strings.match(sitr, stream_end);
if(mr.current_match != ele) {
boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'"));
}
}
};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::first_string[6] =
{'f','i','r','s','t'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::second_string[7] =
{'s','e','c','o','n','d'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::third_string[6] =
{'t','h','i','r','d'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::fourth_string[7] =
{'f','o','u','r','t','h'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::fifth_string[6] =
{'f','i','f','t','h'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::last_string[5] =
{'l','a','s','t'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::before_string[8] =
{'b','e','f','o','r','e'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::after_string[6] =
{'a','f','t','e','r'};
template<class date_type, class CharT>
const typename date_generator_parser<date_type, CharT>::char_type
date_generator_parser<date_type, CharT>::of_string[3] =
{'o','f'};
} } //namespace
#endif // DATE_TIME_DATE_GENERATOR_PARSER_HPP__

View File

@ -0,0 +1,731 @@
#ifndef DATE_TIME_FORMAT_DATE_PARSER_HPP__
#define DATE_TIME_FORMAT_DATE_PARSER_HPP__
/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include "boost/lexical_cast.hpp"
#include "boost/date_time/string_parse_tree.hpp"
#include "boost/date_time/strings_from_facet.hpp"
#include "boost/date_time/special_values_parser.hpp"
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#ifndef BOOST_NO_STDC_NAMESPACE
# include <cctype>
#else
# include <ctype.h>
#endif
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std {
using ::isspace;
using ::isdigit;
}
#endif
namespace boost { namespace date_time {
//! Helper function for parsing fixed length strings into integers
/*! Will consume 'length' number of characters from stream. Consumed
* character are transfered to parse_match_result struct.
* Returns '-1' if no number can be parsed or incorrect number of
* digits in stream. */
template<typename int_type, typename charT>
inline
int_type
fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
std::istreambuf_iterator<charT>& stream_end,
parse_match_result<charT>& mr,
unsigned int length,
const charT& fill_char)
{
//typedef std::basic_string<charT> string_type;
unsigned int j = 0;
//string_type s;
while (j < length && itr != stream_end &&
(std::isdigit(*itr) || *itr == fill_char)) {
if(*itr == fill_char) {
/* Since a fill_char can be anything, we convert it to a zero.
* lexical_cast will behave predictably when zero is used as fill. */
mr.cache += ('0');
}
else {
mr.cache += (*itr);
}
itr++;
j++;
}
int_type i = static_cast<int_type>(-1);
// mr.cache will hold leading zeros. size() tells us when input is too short.
if(mr.cache.size() < length) {
return i;
}
try {
i = boost::lexical_cast<int_type>(mr.cache);
}catch(bad_lexical_cast&){
// we want to return -1 if the cast fails so nothing to do here
}
return i;
}
//! Helper function for parsing fixed length strings into integers
/*! Will consume 'length' number of characters from stream. Consumed
* character are transfered to parse_match_result struct.
* Returns '-1' if no number can be parsed or incorrect number of
* digits in stream. */
template<typename int_type, typename charT>
inline
int_type
fixed_string_to_int(std::istreambuf_iterator<charT>& itr,
std::istreambuf_iterator<charT>& stream_end,
parse_match_result<charT>& mr,
unsigned int length)
{
return fixed_string_to_int<int_type, charT>(itr, stream_end, mr, length, '0');
}
//! Helper function for parsing varied length strings into integers
/*! Will consume 'max_length' characters from stream only if those
* characters are digits. Returns '-1' if no number can be parsed.
* Will not parse a number preceeded by a '+' or '-'. */
template<typename int_type, typename charT>
inline
int_type
var_string_to_int(std::istreambuf_iterator<charT>& itr,
const std::istreambuf_iterator<charT>& stream_end,
unsigned int max_length)
{
typedef std::basic_string<charT> string_type;
unsigned int j = 0;
string_type s;
while (itr != stream_end && (j < max_length) && std::isdigit(*itr)) {
s += (*itr);
++itr;
++j;
}
int_type i = static_cast<int_type>(-1);
if(!s.empty()) {
i = boost::lexical_cast<int_type>(s);
}
return i;
}
//! Class with generic date parsing using a format string
/*! The following is the set of recognized format specifiers
- %a - Short weekday name
- %A - Long weekday name
- %b - Abbreviated month name
- %B - Full month name
- %d - Day of the month as decimal 01 to 31
- %j - Day of year as decimal from 001 to 366
- %m - Month name as a decimal 01 to 12
- %U - Week number 00 to 53 with first Sunday as the first day of week 1?
- %w - Weekday as decimal number 0 to 6 where Sunday == 0
- %W - Week number 00 to 53 where Monday is first day of week 1
- %x - facet default date representation
- %y - Year without the century - eg: 04 for 2004
- %Y - Year with century
The weekday specifiers (%a and %A) do not add to the date construction,
but they provide a way to skip over the weekday names for formats that
provide them.
todo -- Another interesting feature that this approach could provide is
an option to fill in any missing fields with the current values
from the clock. So if you have %m-%d the parser would detect
the missing year value and fill it in using the clock.
todo -- What to do with the %x. %x in the classic facet is just bad...
*/
template<class date_type, typename charT>
class format_date_parser
{
public:
typedef std::basic_string<charT> string_type;
typedef std::basic_istringstream<charT> stringstream_type;
typedef std::istreambuf_iterator<charT> stream_itr_type;
typedef typename string_type::const_iterator const_itr;
typedef typename date_type::year_type year_type;
typedef typename date_type::month_type month_type;
typedef typename date_type::day_type day_type;
typedef typename date_type::duration_type duration_type;
typedef typename date_type::day_of_week_type day_of_week_type;
typedef typename date_type::day_of_year_type day_of_year_type;
typedef string_parse_tree<charT> parse_tree_type;
typedef typename parse_tree_type::parse_match_result_type match_results;
typedef std::vector<std::basic_string<charT> > input_collection_type;
// TODO sv_parser uses its default constructor - write the others
format_date_parser(const string_type& format_str,
const input_collection_type& month_short_names,
const input_collection_type& month_long_names,
const input_collection_type& weekday_short_names,
const input_collection_type& weekday_long_names) :
m_format(format_str),
m_month_short_names(month_short_names, 1),
m_month_long_names(month_long_names, 1),
m_weekday_short_names(weekday_short_names),
m_weekday_long_names(weekday_long_names)
{}
format_date_parser(const string_type& format_str,
const std::locale& locale) :
m_format(format_str),
m_month_short_names(gather_month_strings<charT>(locale), 1),
m_month_long_names(gather_month_strings<charT>(locale, false), 1),
m_weekday_short_names(gather_weekday_strings<charT>(locale)),
m_weekday_long_names(gather_weekday_strings<charT>(locale, false))
{}
format_date_parser(const format_date_parser<date_type,charT>& fdp)
{
this->m_format = fdp.m_format;
this->m_month_short_names = fdp.m_month_short_names;
this->m_month_long_names = fdp.m_month_long_names;
this->m_weekday_short_names = fdp.m_weekday_short_names;
this->m_weekday_long_names = fdp.m_weekday_long_names;
}
string_type format() const
{
return m_format;
}
void format(string_type format_str)
{
m_format = format_str;
}
void short_month_names(const input_collection_type& month_names)
{
m_month_short_names = parse_tree_type(month_names, 1);
}
void long_month_names(const input_collection_type& month_names)
{
m_month_long_names = parse_tree_type(month_names, 1);
}
void short_weekday_names(const input_collection_type& weekday_names)
{
m_weekday_short_names = parse_tree_type(weekday_names);
}
void long_weekday_names(const input_collection_type& weekday_names)
{
m_weekday_long_names = parse_tree_type(weekday_names);
}
date_type
parse_date(const string_type& value,
const string_type& format_str,
const special_values_parser<date_type,charT>& sv_parser) const
{
stringstream_type ss(value);
stream_itr_type sitr(ss);
stream_itr_type stream_end;
return parse_date(sitr, stream_end, format_str, sv_parser);
}
date_type
parse_date(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
const special_values_parser<date_type,charT>& sv_parser) const
{
return parse_date(sitr, stream_end, m_format, sv_parser);
}
/*! Of all the objects that the format_date_parser can parse, only a
* date can be a special value. Therefore, only parse_date checks
* for special_values. */
date_type
parse_date(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str,
const special_values_parser<date_type,charT>& sv_parser) const
{
bool use_current_char = false;
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
short year(0), month(0), day(0), day_of_year(0);// wkday(0);
/* Initialized the following to their minimum values. These intermediate
* objects are used so we get specific exceptions when part of the input
* is unparsable.
* Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/
year_type t_year(1400);
month_type t_month(1);
day_type t_day(1);
day_of_week_type wkday(0);
const_itr itr(format_str.begin());
while (itr != format_str.end() && (sitr != stream_end)) {
if (*itr == '%') {
if ( ++itr == format_str.end())
break;
if (*itr != '%') {
switch(*itr) {
case 'a':
{
//this value is just throw away. It could be used for
//error checking potentially, but it isn't helpful in
//actually constructing the date - we just need to get it
//out of the stream
match_results mr = m_weekday_short_names.match(sitr, stream_end);
if(mr.current_match == match_results::PARSE_ERROR) {
// check special_values
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
wkday = mr.current_match;
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'A':
{
//this value is just throw away. It could be used for
//error checking potentially, but it isn't helpful in
//actually constructing the date - we just need to get it
//out of the stream
match_results mr = m_weekday_long_names.match(sitr, stream_end);
if(mr.current_match == match_results::PARSE_ERROR) {
// check special_values
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
wkday = mr.current_match;
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'b':
{
match_results mr = m_month_short_names.match(sitr, stream_end);
if(mr.current_match == match_results::PARSE_ERROR) {
// check special_values
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
t_month = month_type(mr.current_match);
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'B':
{
match_results mr = m_month_long_names.match(sitr, stream_end);
if(mr.current_match == match_results::PARSE_ERROR) {
// check special_values
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
t_month = month_type(mr.current_match);
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'd':
{
match_results mr;
day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
if(day == -1) {
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
t_day = day_type(day);
break;
}
case 'e':
{
match_results mr;
day = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2, ' ');
if(day == -1) {
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
t_day = day_type(day);
break;
}
case 'j':
{
match_results mr;
day_of_year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 3);
if(day_of_year == -1) {
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
// these next two lines are so we get an exception with bad input
day_of_year_type t_day_of_year(1);
t_day_of_year = day_of_year_type(day_of_year);
break;
}
case 'm':
{
match_results mr;
month = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
if(month == -1) {
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
t_month = month_type(month);
break;
}
case 'Y':
{
match_results mr;
year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
if(year == -1) {
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
t_year = year_type(year);
break;
}
case 'y':
{
match_results mr;
year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
if(year == -1) {
if(sv_parser.match(sitr, stream_end, mr)) {
return date_type(static_cast<special_values>(mr.current_match));
}
}
year += 2000; //make 2 digit years in this century
t_year = year_type(year);
break;
}
default:
{} //ignore those we don't understand
}//switch
}
else { // itr == '%', second consecutive
sitr++;
}
itr++; //advance past format specifier
}
else { //skip past chars in format and in buffer
itr++;
if (use_current_char) {
use_current_char = false;
}
else {
sitr++;
}
}
}
if (day_of_year > 0) {
date_type d(static_cast<unsigned short>(year-1),12,31); //end of prior year
return d + duration_type(day_of_year);
}
return date_type(t_year, t_month, t_day); // exceptions were thrown earlier
// if input was no good
}
//! Throws bad_month if unable to parse
month_type
parse_month(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str) const
{
match_results mr;
return parse_month(sitr, stream_end, format_str, mr);
}
//! Throws bad_month if unable to parse
month_type
parse_month(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str,
match_results& mr) const
{
bool use_current_char = false;
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
short month(0);
const_itr itr(format_str.begin());
while (itr != format_str.end() && (sitr != stream_end)) {
if (*itr == '%') {
if ( ++itr == format_str.end())
break;
if (*itr != '%') {
switch(*itr) {
case 'b':
{
mr = m_month_short_names.match(sitr, stream_end);
month = mr.current_match;
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'B':
{
mr = m_month_long_names.match(sitr, stream_end);
month = mr.current_match;
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'm':
{
month = var_string_to_int<short, charT>(sitr, stream_end, 2);
// var_string_to_int returns -1 if parse failed. That will
// cause a bad_month exception to be thrown so we do nothing here
break;
}
default:
{} //ignore those we don't understand
}//switch
}
else { // itr == '%', second consecutive
sitr++;
}
itr++; //advance past format specifier
}
else { //skip past chars in format and in buffer
itr++;
if (use_current_char) {
use_current_char = false;
}
else {
sitr++;
}
}
}
return month_type(month); // throws bad_month exception when values are zero
}
//! Expects 1 or 2 digits 1-31. Throws bad_day_of_month if unable to parse
day_type
parse_var_day_of_month(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
}
//! Expects 2 digits 01-31. Throws bad_day_of_month if unable to parse
day_type
parse_day_of_month(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
//return day_type(var_string_to_int<short, charT>(sitr, stream_end, 2));
match_results mr;
return day_type(fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2));
}
day_of_week_type
parse_weekday(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str) const
{
match_results mr;
return parse_weekday(sitr, stream_end, format_str, mr);
}
day_of_week_type
parse_weekday(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str,
match_results& mr) const
{
bool use_current_char = false;
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
short wkday(0);
const_itr itr(format_str.begin());
while (itr != format_str.end() && (sitr != stream_end)) {
if (*itr == '%') {
if ( ++itr == format_str.end())
break;
if (*itr != '%') {
switch(*itr) {
case 'a':
{
//this value is just throw away. It could be used for
//error checking potentially, but it isn't helpful in
//actually constructing the date - we just need to get it
//out of the stream
mr = m_weekday_short_names.match(sitr, stream_end);
wkday = mr.current_match;
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'A':
{
//this value is just throw away. It could be used for
//error checking potentially, but it isn't helpful in
//actually constructing the date - we just need to get it
//out of the stream
mr = m_weekday_long_names.match(sitr, stream_end);
wkday = mr.current_match;
if (mr.has_remaining()) {
use_current_char = true;
}
break;
}
case 'w':
{
// weekday as number 0-6, Sunday == 0
wkday = var_string_to_int<short, charT>(sitr, stream_end, 2);
break;
}
default:
{} //ignore those we don't understand
}//switch
}
else { // itr == '%', second consecutive
sitr++;
}
itr++; //advance past format specifier
}
else { //skip past chars in format and in buffer
itr++;
if (use_current_char) {
use_current_char = false;
}
else {
sitr++;
}
}
}
return day_of_week_type(wkday); // throws bad_day_of_month exception
// when values are zero
}
//! throws bad_year if unable to parse
year_type
parse_year(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str) const
{
match_results mr;
return parse_year(sitr, stream_end, format_str, mr);
}
//! throws bad_year if unable to parse
year_type
parse_year(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
string_type format_str,
match_results& mr) const
{
bool use_current_char = false;
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
unsigned short year(0);
const_itr itr(format_str.begin());
while (itr != format_str.end() && (sitr != stream_end)) {
if (*itr == '%') {
if ( ++itr == format_str.end())
break;
if (*itr != '%') {
//match_results mr;
switch(*itr) {
case 'Y':
{
// year from 4 digit string
year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 4);
break;
}
case 'y':
{
// year from 2 digit string (no century)
year = fixed_string_to_int<short, charT>(sitr, stream_end, mr, 2);
year += 2000; //make 2 digit years in this century
break;
}
default:
{} //ignore those we don't understand
}//switch
}
else { // itr == '%', second consecutive
sitr++;
}
itr++; //advance past format specifier
}
else { //skip past chars in format and in buffer
itr++;
if (use_current_char) {
use_current_char = false;
}
else {
sitr++;
}
}
}
return year_type(year); // throws bad_year exception when values are zero
}
private:
string_type m_format;
parse_tree_type m_month_short_names;
parse_tree_type m_month_long_names;
parse_tree_type m_weekday_short_names;
parse_tree_type m_weekday_long_names;
};
} } //namespace
#endif

View File

@ -0,0 +1,38 @@
#ifndef GREGORIAN_HPP__
#define GREGORIAN_HPP__
/* Copyright (c) 2002-2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
/*! @file gregorian.hpp
Single file header that provides overall include for all elements of
the gregorian date-time system. This includes the various types
defined, but also other functions for formatting and parsing.
*/
#include "boost/date_time/compiler_config.hpp"
#include "boost/date_time/gregorian/gregorian_types.hpp"
#include "boost/date_time/gregorian/conversion.hpp"
#if defined(BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS)
#include "boost/date_time/gregorian/formatters_limited.hpp"
#else
#include "boost/date_time/gregorian/formatters.hpp"
#endif
#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
#include "boost/date_time/gregorian/greg_facet.hpp"
#else
#include "boost/date_time/gregorian/gregorian_io.hpp"
#endif // USE_DATE_TIME_PRE_1_33_FACET_IO
#include "boost/date_time/gregorian/parsers.hpp"
#endif

View File

@ -0,0 +1,784 @@
#ifndef DATE_TIME_GREGORIAN_IO_HPP__
#define DATE_TIME_GREGORIAN_IO_HPP__
/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <locale>
#include <iostream>
#include <iterator> // i/ostreambuf_iterator
#include <boost/io/ios_state.hpp>
#include <boost/date_time/date_facet.hpp>
#include <boost/date_time/period_parser.hpp>
#include <boost/date_time/period_formatter.hpp>
#include <boost/date_time/special_values_parser.hpp>
#include <boost/date_time/special_values_formatter.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/gregorian/conversion.hpp> // to_tm will be needed in the facets
namespace boost {
namespace gregorian {
typedef boost::date_time::period_formatter<wchar_t> wperiod_formatter;
typedef boost::date_time::period_formatter<char> period_formatter;
typedef boost::date_time::date_facet<date,wchar_t> wdate_facet;
typedef boost::date_time::date_facet<date,char> date_facet;
typedef boost::date_time::period_parser<date,char> period_parser;
typedef boost::date_time::period_parser<date,wchar_t> wperiod_parser;
typedef boost::date_time::special_values_formatter<char> special_values_formatter;
typedef boost::date_time::special_values_formatter<wchar_t> wspecial_values_formatter;
typedef boost::date_time::special_values_parser<date,char> special_values_parser;
typedef boost::date_time::special_values_parser<date,wchar_t> wspecial_values_parser;
typedef boost::date_time::date_input_facet<date,char> date_input_facet;
typedef boost::date_time::date_input_facet<date,wchar_t> wdate_input_facet;
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::date& d) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), d);
else {
//instantiate a custom facet for dealing with dates since the user
//has not put one in the stream so far. This is for efficiency
//since we would always need to reconstruct for every date
//if the locale did not already exist. Of course this will be overridden
//if the user imbues at some later point. With the default settings
//for the facet the resulting format will be the same as the
//std::time_facet settings.
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), d);
}
return os;
}
//! input operator for date
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, date& d)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, d);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, d);
}
}
catch(...) {
// mask tells us what exceptions are turned on
std::ios_base::iostate exception_mask = is.exceptions();
// if the user wants exceptions on failbit, we'll rethrow our
// date_time exception & set the failbit
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {} // ignore this one
throw; // rethrow original exception
}
else {
// if the user want's to fail quietly, we simply set the failbit
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::date_duration& dd) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), dd);
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), dd);
}
return os;
}
//! input operator for date_duration
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, date_duration& dd)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, dd);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, dd);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::date_period& dp) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), dp);
else {
//instantiate a custom facet for dealing with date periods since the user
//has not put one in the stream so far. This is for efficiency
//since we would always need to reconstruct for every time period
//if the local did not already exist. Of course this will be overridden
//if the user imbues at some later point. With the default settings
//for the facet the resulting format will be the same as the
//std::time_facet settings.
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), dp);
}
return os;
}
//! input operator for date_period
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, date_period& dp)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, dp);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, dp);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
/********** small gregorian types **********/
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::greg_month& gm) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), gm);
else {
custom_date_facet* f = new custom_date_facet();//-> 10/1074199752/32 because year & day not initialized in put(...)
//custom_date_facet* f = new custom_date_facet("%B");
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), gm);
}
return os;
}
//! input operator for greg_month
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, greg_month& m)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, m);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, m);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::greg_weekday& gw) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), gw);
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), gw);
}
return os;
}
//! input operator for greg_weekday
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, greg_weekday& wd)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, wd);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, wd);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
//NOTE: output operator for greg_day was not necessary
//! input operator for greg_day
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, greg_day& gd)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, gd);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, gd);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
//NOTE: output operator for greg_year was not necessary
//! input operator for greg_year
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, greg_year& gy)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, gy);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, gy);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
/********** date generator types **********/
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::partial_date& pd) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), pd);
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), pd);
}
return os;
}
//! input operator for partial_date
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, partial_date& pd)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, pd);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, pd);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::nth_day_of_the_week_in_month& nkd) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), nkd);
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), nkd);
}
return os;
}
//! input operator for nth_day_of_the_week_in_month
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
nth_day_of_the_week_in_month& nday)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, nday);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, nday);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::first_day_of_the_week_in_month& fkd) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), fkd);
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), fkd);
}
return os;
}
//! input operator for first_day_of_the_week_in_month
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
first_day_of_the_week_in_month& fkd)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, fkd);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, fkd);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::last_day_of_the_week_in_month& lkd) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc()))
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), lkd);
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), lkd);
}
return os;
}
//! input operator for last_day_of_the_week_in_month
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
last_day_of_the_week_in_month& lkd)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, lkd);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, lkd);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::first_day_of_the_week_after& fda) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc())) {
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), fda);
}
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), fda);
}
return os;
}
//! input operator for first_day_of_the_week_after
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
first_day_of_the_week_after& fka)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, fka);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, fka);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os, const boost::gregorian::first_day_of_the_week_before& fdb) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::date_facet<date, CharT> custom_date_facet;
std::ostreambuf_iterator<CharT> output_itr(os);
if (std::has_facet<custom_date_facet>(os.getloc())) {
std::use_facet<custom_date_facet>(os.getloc()).put(output_itr, os, os.fill(), fdb);
}
else {
custom_date_facet* f = new custom_date_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(output_itr, os, os.fill(), fdb);
}
return os;
}
//! input operator for first_day_of_the_week_before
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
first_day_of_the_week_before& fkb)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::date_input_facet<date, CharT> date_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<date_input_facet>(is.getloc())) {
std::use_facet<date_input_facet>(is.getloc()).get(sit, str_end, is, fkb);
}
else {
date_input_facet* f = new date_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, fkb);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
} } // namespaces
#endif // DATE_TIME_GREGORIAN_IO_HPP__

View File

@ -0,0 +1,196 @@
#ifndef DATETIME_PERIOD_FORMATTER_HPP___
#define DATETIME_PERIOD_FORMATTER_HPP___
/* Copyright (c) 2002-2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
namespace boost { namespace date_time {
//! Not a facet, but a class used to specify and control period formats
/*! Provides settings for the following:
* - period_separator -- default '/'
* - period_open_start_delimeter -- default '['
* - period_open_range_end_delimeter -- default ')'
* - period_closed_range_end_delimeter -- default ']'
* - display_as_open_range, display_as_closed_range -- default closed_range
*
* Thus the default formatting for a period is as follows:
*@code
* [period.start()/period.last()]
*@endcode
* So for a typical date_period this would be
*@code
* [2004-Jan-04/2004-Feb-01]
*@endcode
* where the date formatting is controlled by the date facet
*/
template <class CharT, class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
class period_formatter {
public:
typedef std::basic_string<CharT> string_type;
typedef CharT char_type;
typedef typename std::basic_string<char_type>::const_iterator const_itr_type;
typedef std::vector<std::basic_string<CharT> > collection_type;
static const char_type default_period_separator[2];
static const char_type default_period_start_delimeter[2];
static const char_type default_period_open_range_end_delimeter[2];
static const char_type default_period_closed_range_end_delimeter[2];
enum range_display_options { AS_OPEN_RANGE, AS_CLOSED_RANGE };
//! Constructor that sets up period formatter options -- default should suffice most cases.
period_formatter(range_display_options range_option_in = AS_CLOSED_RANGE,
const char_type* const period_separator = default_period_separator,
const char_type* const period_start_delimeter = default_period_start_delimeter,
const char_type* const period_open_range_end_delimeter = default_period_open_range_end_delimeter,
const char_type* const period_closed_range_end_delimeter = default_period_closed_range_end_delimeter) :
m_range_option(range_option_in),
m_period_separator(period_separator),
m_period_start_delimeter(period_start_delimeter),
m_open_range_end_delimeter(period_open_range_end_delimeter),
m_closed_range_end_delimeter(period_closed_range_end_delimeter)
{}
//! Puts the characters between period elements into stream -- default is /
OutItrT put_period_separator(OutItrT& oitr) const
{
const_itr_type ci = m_period_separator.begin();
while (ci != m_period_separator.end()) {
*oitr = *ci;
ci++;
}
return oitr;
}
//! Puts the period start characters into stream -- default is [
OutItrT put_period_start_delimeter(OutItrT& oitr) const
{
const_itr_type ci = m_period_start_delimeter.begin();
while (ci != m_period_start_delimeter.end()) {
*oitr = *ci;
ci++;
}
return oitr;
}
//! Puts the period end characters into stream as controled by open/closed range setting.
OutItrT put_period_end_delimeter(OutItrT& oitr) const
{
const_itr_type ci, end;
if (m_range_option == AS_OPEN_RANGE) {
ci = m_open_range_end_delimeter.begin();
end = m_open_range_end_delimeter.end();
}
else {
ci = m_closed_range_end_delimeter.begin();
end = m_closed_range_end_delimeter.end();
}
while (ci != end) {
*oitr = *ci;
ci++;
}
return oitr;
}
range_display_options range_option() const
{
return m_range_option;
}
//! Reset the range_option control
void
range_option(range_display_options option) const
{
m_range_option = option;
}
void delimiter_strings(const string_type& ,
const string_type& ,
const string_type& ,
const string_type& )
{
m_period_separator;
m_period_start_delimeter;
m_open_range_end_delimeter;
m_closed_range_end_delimeter;
}
//! Generic code to output a period -- no matter the period type.
/*! This generic code will output any period using a facet to
* to output the 'elements'. For example, in the case of a date_period
* the elements will be instances of a date which will be formatted
* according the to setup in the passed facet parameter.
*
* The steps for formatting a period are always the same:
* - put the start delimiter
* - put start element
* - put the separator
* - put either last or end element depending on range settings
* - put end delimeter depending on range settings
*
* Thus for a typical date period the result might look like this:
*@code
*
* [March 01, 2004/June 07, 2004] <-- closed range
* [March 01, 2004/June 08, 2004) <-- open range
*
*@endcode
*/
template<class period_type, class facet_type>
OutItrT put_period(OutItrT next,
std::ios_base& a_ios,
char_type a_fill,
const period_type& p,
const facet_type& facet) const {
put_period_start_delimeter(next);
next = facet.put(next, a_ios, a_fill, p.begin());
put_period_separator(next);
if (m_range_option == AS_CLOSED_RANGE) {
facet.put(next, a_ios, a_fill, p.last());
}
else {
facet.put(next, a_ios, a_fill, p.end());
}
put_period_end_delimeter(next);
return next;
}
private:
range_display_options m_range_option;
string_type m_period_separator;
string_type m_period_start_delimeter;
string_type m_open_range_end_delimeter;
string_type m_closed_range_end_delimeter;
};
template <class CharT, class OutItrT>
const typename period_formatter<CharT, OutItrT>::char_type
period_formatter<CharT, OutItrT>::default_period_separator[2] = {'/'};
template <class CharT, class OutItrT>
const typename period_formatter<CharT, OutItrT>::char_type
period_formatter<CharT, OutItrT>::default_period_start_delimeter[2] = {'['};
template <class CharT, class OutItrT>
const typename period_formatter<CharT, OutItrT>::char_type
period_formatter<CharT, OutItrT>::default_period_open_range_end_delimeter[2] = {')'};
template <class CharT, class OutItrT>
const typename period_formatter<CharT, OutItrT>::char_type
period_formatter<CharT, OutItrT>::default_period_closed_range_end_delimeter[2] = {']'};
} } //namespace boost::date_time
#endif

View File

@ -0,0 +1,198 @@
#ifndef DATETIME_PERIOD_PARSER_HPP___
#define DATETIME_PERIOD_PARSER_HPP___
/* Copyright (c) 2002-2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <boost/throw_exception.hpp>
#include <boost/date_time/string_parse_tree.hpp>
#include <boost/date_time/string_convert.hpp>
namespace boost { namespace date_time {
//! Not a facet, but a class used to specify and control period parsing
/*! Provides settings for the following:
* - period_separator -- default '/'
* - period_open_start_delimeter -- default '['
* - period_open_range_end_delimeter -- default ')'
* - period_closed_range_end_delimeter -- default ']'
* - display_as_open_range, display_as_closed_range -- default closed_range
*
* For a typical date_period, the contents of the input stream would be
*@code
* [2004-Jan-04/2004-Feb-01]
*@endcode
* where the date format is controlled by the date facet
*/
template<class date_type, typename CharT>
class period_parser {
public:
typedef std::basic_string<CharT> string_type;
typedef CharT char_type;
//typedef typename std::basic_string<char_type>::const_iterator const_itr_type;
typedef std::istreambuf_iterator<CharT> stream_itr_type;
typedef string_parse_tree<CharT> parse_tree_type;
typedef typename parse_tree_type::parse_match_result_type match_results;
typedef std::vector<std::basic_string<CharT> > collection_type;
static const char_type default_period_separator[2];
static const char_type default_period_start_delimeter[2];
static const char_type default_period_open_range_end_delimeter[2];
static const char_type default_period_closed_range_end_delimeter[2];
enum period_range_option { AS_OPEN_RANGE, AS_CLOSED_RANGE };
//! Constructor that sets up period parser options
period_parser(period_range_option range_opt = AS_CLOSED_RANGE,
const char_type* const period_separator = default_period_separator,
const char_type* const period_start_delimeter = default_period_start_delimeter,
const char_type* const period_open_range_end_delimeter = default_period_open_range_end_delimeter,
const char_type* const period_closed_range_end_delimeter = default_period_closed_range_end_delimeter)
: m_range_option(range_opt)
{
delimiters.push_back(string_type(period_separator));
delimiters.push_back(string_type(period_start_delimeter));
delimiters.push_back(string_type(period_open_range_end_delimeter));
delimiters.push_back(string_type(period_closed_range_end_delimeter));
}
period_parser(const period_parser<date_type,CharT>& p_parser)
{
this->delimiters = p_parser.delimiters;
this->m_range_option = p_parser.m_range_option;
}
period_range_option range_option() const
{
return m_range_option;
}
void range_option(period_range_option option)
{
m_range_option = option;
}
collection_type delimiter_strings() const
{
return delimiters;
}
void delimiter_strings(const string_type& separator,
const string_type& start_delim,
const string_type& open_end_delim,
const string_type& closed_end_delim)
{
delimiters.clear();
delimiters.push_back(separator);
delimiters.push_back(start_delim);
delimiters.push_back(open_end_delim);
delimiters.push_back(closed_end_delim);
}
//! Generic code to parse a period -- no matter the period type.
/*! This generic code will parse any period using a facet to
* to get the 'elements'. For example, in the case of a date_period
* the elements will be instances of a date which will be parsed
* according the to setup in the passed facet parameter.
*
* The steps for parsing a period are always the same:
* - consume the start delimiter
* - get start element
* - consume the separator
* - get either last or end element depending on range settings
* - consume the end delimeter depending on range settings
*
* Thus for a typical date period the contents of the input stream
* might look like this:
*@code
*
* [March 01, 2004/June 07, 2004] <-- closed range
* [March 01, 2004/June 08, 2004) <-- open range
*
*@endcode
*/
template<class period_type, class duration_type, class facet_type>
period_type get_period(stream_itr_type& sitr,
stream_itr_type& stream_end,
std::ios_base& a_ios,
const period_type& /* p */,
const duration_type& dur_unit,
const facet_type& facet) const
{
// skip leading whitespace
while(std::isspace(*sitr) && sitr != stream_end) { ++sitr; }
typedef typename period_type::point_type point_type;
point_type p1(not_a_date_time), p2(not_a_date_time);
consume_delim(sitr, stream_end, delimiters[START]); // start delim
facet.get(sitr, stream_end, a_ios, p1); // first point
consume_delim(sitr, stream_end, delimiters[SEPARATOR]); // separator
facet.get(sitr, stream_end, a_ios, p2); // second point
// period construction parameters are always open range [begin, end)
if (m_range_option == AS_CLOSED_RANGE) {
consume_delim(sitr, stream_end, delimiters[CLOSED_END]);// end delim
// add 1 duration unit to p2 to make range open
p2 += dur_unit;
}
else {
consume_delim(sitr, stream_end, delimiters[OPEN_END]); // end delim
}
return period_type(p1, p2);
}
private:
collection_type delimiters;
period_range_option m_range_option;
enum delim_ids { SEPARATOR, START, OPEN_END, CLOSED_END };
//! throws ios_base::failure if delimiter and parsed data do not match
void consume_delim(stream_itr_type& sitr,
stream_itr_type& stream_end,
const string_type& delim) const
{
/* string_parse_tree will not parse a string of punctuation characters
* without knowing exactly how many characters to process
* Ex [2000. Will not parse out the '[' string without knowing
* to process only one character. By using length of the delimiter
* string we can safely iterate past it. */
string_type s;
for(unsigned int i = 0; i < delim.length() && sitr != stream_end; ++i) {
s += *sitr;
++sitr;
}
if(s != delim) {
boost::throw_exception(std::ios_base::failure("Parse failed. Expected '"
+ convert_string_type<char_type,char>(delim) + "' but found '" + convert_string_type<char_type,char>(s) + "'"));
}
}
};
template <class date_type, class char_type>
const typename period_parser<date_type, char_type>::char_type
period_parser<date_type, char_type>::default_period_separator[2] = {'/'};
template <class date_type, class char_type>
const typename period_parser<date_type, char_type>::char_type
period_parser<date_type, char_type>::default_period_start_delimeter[2] = {'['};
template <class date_type, class char_type>
const typename period_parser<date_type, char_type>::char_type
period_parser<date_type, char_type>::default_period_open_range_end_delimeter[2] = {')'};
template <class date_type, class char_type>
const typename period_parser<date_type, char_type>::char_type
period_parser<date_type, char_type>::default_period_closed_range_end_delimeter[2] = {']'};
} } //namespace boost::date_time
#endif // DATETIME_PERIOD_PARSER_HPP___

View File

@ -0,0 +1,39 @@
#ifndef POSIX_TIME_HPP___
#define POSIX_TIME_HPP___
/* Copyright (c) 2002-2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
/*!@file posix_time.hpp Global header file to get all of posix time types
*/
#include "boost/date_time/compiler_config.hpp"
#include "boost/date_time/posix_time/ptime.hpp"
#if defined(BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES)
#include "boost/date_time/posix_time/date_duration_operators.hpp"
#endif
// output functions
#if defined(BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS)
#include "boost/date_time/posix_time/time_formatters_limited.hpp"
#else
#include "boost/date_time/posix_time/time_formatters.hpp"
#endif // BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS
// streaming operators
#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
#include "boost/date_time/posix_time/posix_time_legacy_io.hpp"
#else
#include "boost/date_time/posix_time/posix_time_io.hpp"
#endif // USE_DATE_TIME_PRE_1_33_FACET_IO
#include "boost/date_time/posix_time/time_parsers.hpp"
#include "boost/date_time/posix_time/conversion.hpp"
#endif

View File

@ -0,0 +1,236 @@
#ifndef DATE_TIME_POSIX_TIME_IO_HPP__
#define DATE_TIME_POSIX_TIME_IO_HPP__
/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <locale>
#include <iostream>
#include <iterator> // i/ostreambuf_iterator
#include <boost/io/ios_state.hpp>
#include <boost/date_time/time_facet.hpp>
#include <boost/date_time/period_formatter.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <boost/date_time/posix_time/time_period.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <boost/date_time/posix_time/conversion.hpp> // to_tm will be needed in the facets
namespace boost {
namespace posix_time {
//! wptime_facet is depricated and will be phased out. use wtime_facet instead
//typedef boost::date_time::time_facet<ptime, wchar_t> wptime_facet;
//! ptime_facet is depricated and will be phased out. use time_facet instead
//typedef boost::date_time::time_facet<ptime, char> ptime_facet;
//! wptime_input_facet is depricated and will be phased out. use wtime_input_facet instead
//typedef boost::date_time::time_input_facet<ptime,wchar_t> wptime_input_facet;
//! ptime_input_facet is depricated and will be phased out. use time_input_facet instead
//typedef boost::date_time::time_input_facet<ptime,char> ptime_input_facet;
typedef boost::date_time::time_facet<ptime, wchar_t> wtime_facet;
typedef boost::date_time::time_facet<ptime, char> time_facet;
typedef boost::date_time::time_input_facet<ptime, wchar_t> wtime_input_facet;
typedef boost::date_time::time_input_facet<ptime, char> time_input_facet;
template <class CharT, class TraitsT>
inline
std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os,
const ptime& p) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::time_facet<ptime, CharT> custom_ptime_facet;
std::ostreambuf_iterator<CharT> oitr(os);
if (std::has_facet<custom_ptime_facet>(os.getloc()))
std::use_facet<custom_ptime_facet>(os.getloc()).put(oitr, os, os.fill(), p);
else {
//instantiate a custom facet for dealing with times since the user
//has not put one in the stream so far. This is for efficiency
//since we would always need to reconstruct for every time period
//if the locale did not already exist. Of course this will be overridden
//if the user imbues as some later point.
custom_ptime_facet* f = new custom_ptime_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(oitr, os, os.fill(), p);
}
return os;
}
//! input operator for ptime
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, ptime& pt)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::time_input_facet<ptime, CharT> time_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<time_input_facet>(is.getloc())) {
std::use_facet<time_input_facet>(is.getloc()).get(sit, str_end, is, pt);
}
else {
time_input_facet* f = new time_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, pt);
}
}
catch(...) {
// mask tells us what exceptions are turned on
std::ios_base::iostate exception_mask = is.exceptions();
// if the user wants exceptions on failbit, we'll rethrow our
// date_time exception & set the failbit
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {} // ignore this one
throw; // rethrow original exception
}
else {
// if the user want's to fail quietly, we simply set the failbit
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
template <class CharT, class TraitsT>
inline
std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& os,
const boost::posix_time::time_period& p) {
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::time_facet<ptime, CharT> custom_ptime_facet;
std::ostreambuf_iterator<CharT> oitr(os);
if (std::has_facet<custom_ptime_facet>(os.getloc())) {
std::use_facet<custom_ptime_facet>(os.getloc()).put(oitr, os, os.fill(), p);
}
else {
//instantiate a custom facet for dealing with periods since the user
//has not put one in the stream so far. This is for efficiency
//since we would always need to reconstruct for every time period
//if the local did not already exist. Of course this will be overridden
//if the user imbues as some later point.
custom_ptime_facet* f = new custom_ptime_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(oitr, os, os.fill(), p);
}
return os;
}
//! input operator for time_period
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, time_period& tp)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::time_input_facet<ptime, CharT> time_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<time_input_facet>(is.getloc())) {
std::use_facet<time_input_facet>(is.getloc()).get(sit, str_end, is, tp);
}
else {
time_input_facet* f = new time_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, tp);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
//! ostream operator for posix_time::time_duration
// todo fix to use facet -- place holder for now...
template <class CharT, class Traits>
inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const time_duration& td)
{
boost::io::ios_flags_saver iflags(os);
typedef boost::date_time::time_facet<ptime, CharT> custom_ptime_facet;
std::ostreambuf_iterator<CharT> oitr(os);
if (std::has_facet<custom_ptime_facet>(os.getloc()))
std::use_facet<custom_ptime_facet>(os.getloc()).put(oitr, os, os.fill(), td);
else {
//instantiate a custom facet for dealing with times since the user
//has not put one in the stream so far. This is for efficiency
//since we would always need to reconstruct for every time period
//if the locale did not already exist. Of course this will be overridden
//if the user imbues as some later point.
custom_ptime_facet* f = new custom_ptime_facet();
std::locale l = std::locale(os.getloc(), f);
os.imbue(l);
f->put(oitr, os, os.fill(), td);
}
return os;
}
//! input operator for time_duration
template <class CharT, class Traits>
inline
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, time_duration& td)
{
boost::io::ios_flags_saver iflags(is);
typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false);
if (strm_sentry) {
try {
typedef typename date_time::time_input_facet<ptime, CharT> time_input_facet;
std::istreambuf_iterator<CharT,Traits> sit(is), str_end;
if(std::has_facet<time_input_facet>(is.getloc())) {
std::use_facet<time_input_facet>(is.getloc()).get(sit, str_end, is, td);
}
else {
time_input_facet* f = new time_input_facet();
std::locale l = std::locale(is.getloc(), f);
is.imbue(l);
f->get(sit, str_end, is, td);
}
}
catch(...) {
std::ios_base::iostate exception_mask = is.exceptions();
if(std::ios_base::failbit & exception_mask) {
try { is.setstate(std::ios_base::failbit); }
catch(std::ios_base::failure&) {}
throw; // rethrow original exception
}
else {
is.setstate(std::ios_base::failbit);
}
}
}
return is;
}
} } // namespaces
#endif // DATE_TIME_POSIX_TIME_IO_HPP__

View File

@ -0,0 +1,153 @@
#ifndef POSIX_TIME_PRE133_OPERATORS_HPP___
#define POSIX_TIME_PRE133_OPERATORS_HPP___
/* Copyright (c) 2002-2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
/*! @file posix_time_pre133_operators.hpp
* These input and output operators are for use with the
* pre 1.33 version of the date_time libraries io facet code.
* The operators used in version 1.33 and later can be found
* in posix_time_io.hpp */
#include <iostream>
#include <string>
#include <sstream>
#include "boost/date_time/compiler_config.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/date_time/posix_time/posix_time_duration.hpp"
#include "boost/date_time/posix_time/ptime.hpp"
#include "boost/date_time/posix_time/time_period.hpp"
#include "boost/date_time/time_parsing.hpp"
namespace boost {
namespace posix_time {
//The following code is removed for configurations with poor std::locale support (eg: MSVC6, gcc 2.9x)
#ifndef BOOST_DATE_TIME_NO_LOCALE
#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
//! ostream operator for posix_time::time_duration
template <class charT, class traits>
inline
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const time_duration& td)
{
typedef boost::date_time::ostream_time_duration_formatter<time_duration, charT> duration_formatter;
duration_formatter::duration_put(td, os);
return os;
}
//! ostream operator for posix_time::ptime
template <class charT, class traits>
inline
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const ptime& t)
{
typedef boost::date_time::ostream_time_formatter<ptime, charT> time_formatter;
time_formatter::time_put(t, os);
return os;
}
//! ostream operator for posix_time::time_period
template <class charT, class traits>
inline
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const time_period& tp)
{
typedef boost::date_time::ostream_time_period_formatter<time_period, charT> period_formatter;
period_formatter::period_put(tp, os);
return os;
}
#endif // USE_DATE_TIME_PRE_1_33_FACET_IO
/******** input streaming ********/
template<class charT>
inline
std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is, time_duration& td)
{
// need to create a std::string and parse it
std::basic_string<charT> inp_s;
std::stringstream out_ss;
is >> inp_s;
typename std::basic_string<charT>::iterator b = inp_s.begin();
// need to use both iterators because there is no requirement
// for the data held by a std::basic_string<> be terminated with
// any marker (such as '\0').
typename std::basic_string<charT>::iterator e = inp_s.end();
while(b != e){
out_ss << is.narrow(*b, 0);
++b;
}
td = date_time::parse_delimited_time_duration<time_duration>(out_ss.str());
return is;
}
template<class charT>
inline
std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is, ptime& pt)
{
gregorian::date d(not_a_date_time);
time_duration td(0,0,0);
is >> d >> td;
pt = ptime(d, td);
return is;
}
/** operator>> for time_period. time_period must be in
* "[date time_duration/date time_duration]" format. */
template<class charT>
inline
std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is, time_period& tp)
{
gregorian::date d(not_a_date_time);
time_duration td(0,0,0);
ptime beg(d, td);
ptime end(beg);
std::basic_string<charT> s;
// get first date string and remove leading '['
is >> s;
{
std::basic_stringstream<charT> ss;
ss << s.substr(s.find('[')+1);
ss >> d;
}
// get first time_duration & second date string, remove the '/'
// and split into 2 strings
is >> s;
{
std::basic_stringstream<charT> ss;
ss << s.substr(0, s.find('/'));
ss >> td;
}
beg = ptime(d, td);
{
std::basic_stringstream<charT> ss;
ss << s.substr(s.find('/')+1);
ss >> d;
}
// get last time_duration and remove the trailing ']'
is >> s;
{
std::basic_stringstream<charT> ss;
ss << s.substr(0, s.find(']'));
ss >> td;
}
end = ptime(d, td);
tp = time_period(beg,end);
return is;
}
#endif //BOOST_DATE_TIME_NO_LOCALE
} } // namespaces
#endif // POSIX_TIME_PRE133_OPERATORS_HPP___

View File

@ -0,0 +1,289 @@
#ifndef POSIXTIME_FORMATTERS_HPP___
#define POSIXTIME_FORMATTERS_HPP___
/* Copyright (c) 2002-2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/compiler_config.hpp>
#include <boost/date_time/iso_format.hpp>
#include <boost/date_time/date_format_simple.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/time_formatting_streams.hpp>
#include <boost/date_time/time_resolution_traits.hpp> // absolute_value
#include <boost/date_time/time_parsing.hpp>
/* NOTE: The "to_*_string" code for older compilers, ones that define
* BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS, is located in
* formatters_limited.hpp
*/
namespace boost {
namespace posix_time {
// template function called by wrapper functions:
// to_*_string(time_duration) & to_*_wstring(time_duration)
template<class charT>
inline std::basic_string<charT> to_simple_string_type(time_duration td) {
std::basic_ostringstream<charT> ss;
if(td.is_special()) {
/* simply using 'ss << td.get_rep()' won't work on compilers
* that don't support locales. This way does. */
// switch copied from date_names_put.hpp
switch(td.get_rep().as_special())
{
case not_a_date_time:
//ss << "not-a-number";
ss << "not-a-date-time";
break;
case pos_infin:
ss << "+infinity";
break;
case neg_infin:
ss << "-infinity";
break;
default:
ss << "";
}
}
else {
charT fill_char = '0';
if(td.is_negative()) {
ss << '-';
}
ss << std::setw(2) << std::setfill(fill_char)
<< date_time::absolute_value(td.hours()) << ":";
ss << std::setw(2) << std::setfill(fill_char)
<< date_time::absolute_value(td.minutes()) << ":";
ss << std::setw(2) << std::setfill(fill_char)
<< date_time::absolute_value(td.seconds());
//TODO the following is totally non-generic, yelling FIXME
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
boost::int64_t frac_sec =
date_time::absolute_value(td.fractional_seconds());
// JDG [7/6/02 VC++ compatibility]
charT buff[32];
_i64toa(frac_sec, buff, 10);
#else
time_duration::fractional_seconds_type frac_sec =
date_time::absolute_value(td.fractional_seconds());
#endif
if (frac_sec != 0) {
ss << "." << std::setw(time_duration::num_fractional_digits())
<< std::setfill(fill_char)
// JDG [7/6/02 VC++ compatibility]
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
<< buff;
#else
<< frac_sec;
#endif
}
}// else
return ss.str();
}
//! Time duration to string -hh::mm::ss.fffffff. Example: 10:09:03.0123456
/*!\ingroup time_format
*/
inline std::string to_simple_string(time_duration td) {
return to_simple_string_type<char>(td);
}
// template function called by wrapper functions:
// to_*_string(time_duration) & to_*_wstring(time_duration)
template<class charT>
inline std::basic_string<charT> to_iso_string_type(time_duration td)
{
std::basic_ostringstream<charT> ss;
if(td.is_special()) {
/* simply using 'ss << td.get_rep()' won't work on compilers
* that don't support locales. This way does. */
// switch copied from date_names_put.hpp
switch(td.get_rep().as_special()) {
case not_a_date_time:
//ss << "not-a-number";
ss << "not-a-date-time";
break;
case pos_infin:
ss << "+infinity";
break;
case neg_infin:
ss << "-infinity";
break;
default:
ss << "";
}
}
else {
charT fill_char = '0';
if(td.is_negative()) {
ss << '-';
}
ss << std::setw(2) << std::setfill(fill_char)
<< date_time::absolute_value(td.hours());
ss << std::setw(2) << std::setfill(fill_char)
<< date_time::absolute_value(td.minutes());
ss << std::setw(2) << std::setfill(fill_char)
<< date_time::absolute_value(td.seconds());
//TODO the following is totally non-generic, yelling FIXME
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
boost::int64_t frac_sec =
date_time::absolute_value(td.fractional_seconds());
// JDG [7/6/02 VC++ compatibility]
charT buff[32];
_i64toa(frac_sec, buff, 10);
#else
time_duration::fractional_seconds_type frac_sec =
date_time::absolute_value(td.fractional_seconds());
#endif
if (frac_sec != 0) {
ss << "." << std::setw(time_duration::num_fractional_digits())
<< std::setfill(fill_char)
// JDG [7/6/02 VC++ compatibility]
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
<< buff;
#else
<< frac_sec;
#endif
}
}// else
return ss.str();
}
//! Time duration in iso format -hhmmss,fffffff Example: 10:09:03,0123456
/*!\ingroup time_format
*/
inline std::string to_iso_string(time_duration td){
return to_iso_string_type<char>(td);
}
//! Time to simple format CCYY-mmm-dd hh:mm:ss.fffffff
/*!\ingroup time_format
*/
template<class charT>
inline std::basic_string<charT> to_simple_string_type(ptime t)
{
// can't use this w/gcc295, no to_simple_string_type<>(td) available
std::basic_string<charT> ts = gregorian::to_simple_string_type<charT>(t.date());// + " ";
if(!t.time_of_day().is_special()) {
charT space = ' ';
return ts + space + to_simple_string_type<charT>(t.time_of_day());
}
else {
return ts;
}
}
inline std::string to_simple_string(ptime t){
return to_simple_string_type<char>(t);
}
// function called by wrapper functions to_*_string(time_period)
// & to_*_wstring(time_period)
template<class charT>
inline std::basic_string<charT> to_simple_string_type(time_period tp)
{
charT beg = '[', mid = '/', end = ']';
std::basic_string<charT> d1(to_simple_string_type<charT>(tp.begin()));
std::basic_string<charT> d2(to_simple_string_type<charT>(tp.last()));
return std::basic_string<charT>(beg + d1 + mid + d2 + end);
}
//! Convert to string of form [YYYY-mmm-DD HH:MM::SS.ffffff/YYYY-mmm-DD HH:MM::SS.fffffff]
/*!\ingroup time_format
*/
inline std::string to_simple_string(time_period tp){
return to_simple_string_type<char>(tp);
}
// function called by wrapper functions to_*_string(time_period)
// & to_*_wstring(time_period)
template<class charT>
inline std::basic_string<charT> to_iso_string_type(ptime t)
{
std::basic_string<charT> ts = gregorian::to_iso_string_type<charT>(t.date());// + "T";
if(!t.time_of_day().is_special()) {
charT sep = 'T';
return ts + sep + to_iso_string_type<charT>(t.time_of_day());
}
else {
return ts;
}
}
//! Convert iso short form YYYYMMDDTHHMMSS where T is the date-time separator
/*!\ingroup time_format
*/
inline std::string to_iso_string(ptime t){
return to_iso_string_type<char>(t);
}
// function called by wrapper functions to_*_string(time_period)
// & to_*_wstring(time_period)
template<class charT>
inline std::basic_string<charT> to_iso_extended_string_type(ptime t)
{
std::basic_string<charT> ts = gregorian::to_iso_extended_string_type<charT>(t.date());// + "T";
if(!t.time_of_day().is_special()) {
charT sep = 'T';
return ts + sep + to_simple_string_type<charT>(t.time_of_day());
}
else {
return ts;
}
}
//! Convert to form YYYY-MM-DDTHH:MM:SS where T is the date-time separator
/*!\ingroup time_format
*/
inline std::string to_iso_extended_string(ptime t){
return to_iso_extended_string_type<char>(t);
}
#if !defined(BOOST_NO_STD_WSTRING)
//! Time duration to wstring -hh::mm::ss.fffffff. Example: 10:09:03.0123456
/*!\ingroup time_format
*/
inline std::wstring to_simple_wstring(time_duration td) {
return to_simple_string_type<wchar_t>(td);
}
//! Time duration in iso format -hhmmss,fffffff Example: 10:09:03,0123456
/*!\ingroup time_format
*/
inline std::wstring to_iso_wstring(time_duration td){
return to_iso_string_type<wchar_t>(td);
}
inline std::wstring to_simple_wstring(ptime t){
return to_simple_string_type<wchar_t>(t);
}
//! Convert to wstring of form [YYYY-mmm-DD HH:MM::SS.ffffff/YYYY-mmm-DD HH:MM::SS.fffffff]
/*!\ingroup time_format
*/
inline std::wstring to_simple_wstring(time_period tp){
return to_simple_string_type<wchar_t>(tp);
}
//! Convert iso short form YYYYMMDDTHHMMSS where T is the date-time separator
/*!\ingroup time_format
*/
inline std::wstring to_iso_wstring(ptime t){
return to_iso_string_type<wchar_t>(t);
}
//! Convert to form YYYY-MM-DDTHH:MM:SS where T is the date-time separator
/*!\ingroup time_format
*/
inline std::wstring to_iso_extended_wstring(ptime t){
return to_iso_extended_string_type<wchar_t>(t);
}
#endif // BOOST_NO_STD_WSTRING
} } //namespace posix_time
#endif

View File

@ -0,0 +1,212 @@
#ifndef POSIXTIME_FORMATTERS_LIMITED_HPP___
#define POSIXTIME_FORMATTERS_LIMITED_HPP___
/* Copyright (c) 2002,2003 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/compiler_config.hpp>
#include <boost/date_time/iso_format.hpp>
#include <boost/date_time/date_format_simple.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/time_formatting_streams.hpp>
#include <boost/date_time/time_resolution_traits.hpp> // absolute_value
namespace boost {
namespace posix_time {
//! Time duration to string -hh::mm::ss.fffffff. Example: 10:09:03.0123456
/*!\ingroup time_format
*/
inline std::string to_simple_string(time_duration td) {
std::ostringstream ss;
if(td.is_special()) {
/* simply using 'ss << td.get_rep()' won't work on compilers
* that don't support locales. This way does. */
// switch copied from date_names_put.hpp
switch(td.get_rep().as_special())
{
case not_a_date_time:
//ss << "not-a-number";
ss << "not-a-date-time";
break;
case pos_infin:
ss << "+infinity";
break;
case neg_infin:
ss << "-infinity";
break;
default:
ss << "";
}
}
else {
if(td.is_negative()) {
ss << '-';
}
ss << std::setw(2) << std::setfill('0')
<< date_time::absolute_value(td.hours()) << ":";
ss << std::setw(2) << std::setfill('0')
<< date_time::absolute_value(td.minutes()) << ":";
ss << std::setw(2) << std::setfill('0')
<< date_time::absolute_value(td.seconds());
//TODO the following is totally non-generic, yelling FIXME
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
boost::int64_t frac_sec =
date_time::absolute_value(td.fractional_seconds());
// JDG [7/6/02 VC++ compatibility]
char buff[32];
_i64toa(frac_sec, buff, 10);
#else
time_duration::fractional_seconds_type frac_sec =
date_time::absolute_value(td.fractional_seconds());
#endif
if (frac_sec != 0) {
ss << "." << std::setw(time_duration::num_fractional_digits())
<< std::setfill('0')
// JDG [7/6/02 VC++ compatibility]
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
<< buff;
#else
<< frac_sec;
#endif
}
}// else
return ss.str();
}
//! Time duration in iso format -hhmmss,fffffff Example: 10:09:03,0123456
/*!\ingroup time_format
*/
inline
std::string
to_iso_string(time_duration td)
{
std::ostringstream ss;
if(td.is_special()) {
/* simply using 'ss << td.get_rep()' won't work on compilers
* that don't support locales. This way does. */
// switch copied from date_names_put.hpp
switch(td.get_rep().as_special()) {
case not_a_date_time:
//ss << "not-a-number";
ss << "not-a-date-time";
break;
case pos_infin:
ss << "+infinity";
break;
case neg_infin:
ss << "-infinity";
break;
default:
ss << "";
}
}
else {
if(td.is_negative()) {
ss << '-';
}
ss << std::setw(2) << std::setfill('0')
<< date_time::absolute_value(td.hours());
ss << std::setw(2) << std::setfill('0')
<< date_time::absolute_value(td.minutes());
ss << std::setw(2) << std::setfill('0')
<< date_time::absolute_value(td.seconds());
//TODO the following is totally non-generic, yelling FIXME
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
boost::int64_t frac_sec =
date_time::absolute_value(td.fractional_seconds());
// JDG [7/6/02 VC++ compatibility]
char buff[32];
_i64toa(frac_sec, buff, 10);
#else
time_duration::fractional_seconds_type frac_sec =
date_time::absolute_value(td.fractional_seconds());
#endif
if (frac_sec != 0) {
ss << "." << std::setw(time_duration::num_fractional_digits())
<< std::setfill('0')
// JDG [7/6/02 VC++ compatibility]
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
<< buff;
#else
<< frac_sec;
#endif
}
}// else
return ss.str();
}
//! Time to simple format CCYY-mmm-dd hh:mm:ss.fffffff
/*!\ingroup time_format
*/
inline
std::string
to_simple_string(ptime t)
{
std::string ts = gregorian::to_simple_string(t.date());// + " ";
if(!t.time_of_day().is_special()) {
return ts + " " + to_simple_string(t.time_of_day());
}
else {
return ts;
}
}
//! Convert to string of form [YYYY-mmm-DD HH:MM::SS.ffffff/YYYY-mmm-DD HH:MM::SS.fffffff]
/*!\ingroup time_format
*/
inline
std::string
to_simple_string(time_period tp)
{
std::string d1(to_simple_string(tp.begin()));
std::string d2(to_simple_string(tp.last()));
return std::string("[" + d1 + "/" + d2 +"]");
}
//! Convert iso short form YYYYMMDDTHHMMSS where T is the date-time separator
/*!\ingroup time_format
*/
inline
std::string to_iso_string(ptime t)
{
std::string ts = gregorian::to_iso_string(t.date());// + "T";
if(!t.time_of_day().is_special()) {
return ts + "T" + to_iso_string(t.time_of_day());
}
else {
return ts;
}
}
//! Convert to form YYYY-MM-DDTHH:MM:SS where T is the date-time separator
/*!\ingroup time_format
*/
inline
std::string
to_iso_extended_string(ptime t)
{
std::string ts = gregorian::to_iso_extended_string(t.date());// + "T";
if(!t.time_of_day().is_special()) {
return ts + "T" + to_simple_string(t.time_of_day());
}
else {
return ts;
}
}
} } //namespace posix_time
#endif

View File

@ -0,0 +1,48 @@
#ifndef POSIXTIME_PARSERS_HPP___
#define POSIXTIME_PARSERS_HPP___
/* Copyright (c) 2002,2003 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland
* $Date$
*/
#include "boost/date_time/gregorian/gregorian.hpp"
#include "boost/date_time/time_parsing.hpp"
#include "boost/date_time/posix_time/posix_time_types.hpp"
namespace boost {
namespace posix_time {
//! Creates a time_duration object from a delimited string
/*! Expected format for string is "[-]h[h][:mm][:ss][.fff]".
* A negative duration will be created if the first character in
* string is a '-', all other '-' will be treated as delimiters.
* Accepted delimiters are "-:,.". */
inline time_duration duration_from_string(const std::string& s) {
return date_time::parse_delimited_time_duration<time_duration>(s);
}
inline ptime time_from_string(const std::string& s) {
return date_time::parse_delimited_time<ptime>(s, ' ');
}
inline ptime from_iso_string(const std::string& s) {
return date_time::parse_iso_time<ptime>(s, 'T');
}
inline ptime from_iso_extended_string(const std::string& s) {
return date_time::parse_delimited_time<ptime>(s, 'T');
}
} } //namespace posix_time
#endif

View File

@ -0,0 +1,96 @@
#ifndef DATETIME_SPECIAL_VALUE_FORMATTER_HPP___
#define DATETIME_SPECIAL_VALUE_FORMATTER_HPP___
/* Copyright (c) 2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland
* $Date$
*/
#include <vector>
#include <string>
#include "boost/date_time/special_defs.hpp"
namespace boost { namespace date_time {
//! Class that provides generic formmatting ostream formatting for special values
/*! This class provides for the formmating of special values to an output stream.
* In particular, it produces strings for the values of negative and positive
* infinity as well as not_a_date_time.
*
* While not a facet, this class is used by the date and time facets for formatting
* special value types.
*
*/
template <class CharT, class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > >
class special_values_formatter
{
public:
typedef std::basic_string<CharT> string_type;
typedef CharT char_type;
typedef std::vector<string_type> collection_type;
static const char_type default_special_value_names[3][17];
//! Construct special values formatter using default strings.
/*! Default strings are not-a-date-time -infinity +infinity
*/
special_values_formatter()
{
std::copy(&default_special_value_names[0],
&default_special_value_names[3],
std::back_inserter(m_special_value_names));
}
//! Construct special values formatter from array of strings
/*! This constructor will take pair of iterators from an array of strings
* that represent the special values and copy them for use in formatting
* special values.
*@code
* const char* const special_value_names[]={"nadt","-inf","+inf" };
*
* special_value_formatter svf(&special_value_names[0], &special_value_names[3]);
*@endcode
*/
special_values_formatter(const char_type* const* begin, const char_type* const* end)
{
std::copy(begin, end, std::back_inserter(m_special_value_names));
}
special_values_formatter(typename collection_type::iterator beg, typename collection_type::iterator end)
{
std::copy(beg, end, std::back_inserter(m_special_value_names));
}
OutItrT put_special(OutItrT next,
const boost::date_time::special_values& value) const
{
unsigned int index = value;
if (index < m_special_value_names.size()) {
std::copy(m_special_value_names[index].begin(),
m_special_value_names[index].end(),
next);
}
return next;
}
protected:
collection_type m_special_value_names;
};
//! Storage for the strings used to indicate special values
/* using c_strings to initialize these worked fine in testing, however,
* a project that compiled its objects separately, then linked in a separate
* step wound up with redefinition errors for the values in this array.
* Initializing individual characters eliminated this problem */
template <class CharT, class OutItrT>
const typename special_values_formatter<CharT, OutItrT>::char_type special_values_formatter<CharT, OutItrT>::default_special_value_names[3][17] = {
{'n','o','t','-','a','-','d','a','t','e','-','t','i','m','e'},
{'-','i','n','f','i','n','i','t','y'},
{'+','i','n','f','i','n','i','t','y'} };
} } //namespace boost::date_time
#endif

View File

@ -0,0 +1,159 @@
#ifndef DATE_TIME_SPECIAL_VALUES_PARSER_HPP__
#define DATE_TIME_SPECIAL_VALUES_PARSER_HPP__
/* Copyright (c) 2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date:
*/
#include "boost/date_time/string_parse_tree.hpp"
#include "boost/date_time/special_defs.hpp"
#include <string>
#include <vector>
namespace boost { namespace date_time {
//! Class for special_value parsing
/*!
* TODO: add doc-comments for which elements can be changed
* Parses input stream for strings representing special_values.
* Special values parsed are:
* - not_a_date_time
* - neg_infin
* - pod_infin
* - min_date_time
* - max_date_time
*/
template<class date_type, typename charT>
class special_values_parser
{
public:
typedef std::basic_string<charT> string_type;
//typedef std::basic_stringstream<charT> stringstream_type;
typedef std::istreambuf_iterator<charT> stream_itr_type;
//typedef typename string_type::const_iterator const_itr;
//typedef typename date_type::year_type year_type;
//typedef typename date_type::month_type month_type;
typedef typename date_type::duration_type duration_type;
//typedef typename date_type::day_of_week_type day_of_week_type;
//typedef typename date_type::day_type day_type;
typedef string_parse_tree<charT> parse_tree_type;
typedef typename parse_tree_type::parse_match_result_type match_results;
typedef std::vector<std::basic_string<charT> > collection_type;
typedef charT char_type;
static const char_type nadt_string[16];
static const char_type neg_inf_string[10];
static const char_type pos_inf_string[10];
static const char_type min_date_time_string[18];
static const char_type max_date_time_string[18];
//! Creates a special_values_parser with the default set of "sv_strings"
special_values_parser()
{
sv_strings(string_type(nadt_string),
string_type(neg_inf_string),
string_type(pos_inf_string),
string_type(min_date_time_string),
string_type(max_date_time_string));
}
//! Creates a special_values_parser using a user defined set of element strings
special_values_parser(const string_type& nadt_str,
const string_type& neg_inf_str,
const string_type& pos_inf_str,
const string_type& min_dt_str,
const string_type& max_dt_str)
{
sv_strings(nadt_str, neg_inf_str, pos_inf_str, min_dt_str, max_dt_str);
}
special_values_parser(typename collection_type::iterator beg, typename collection_type::iterator end)
{
collection_type phrases;
std::copy(beg, end, std::back_inserter(phrases));
m_sv_strings = parse_tree_type(phrases, static_cast<int>(not_a_date_time));
}
special_values_parser(const special_values_parser<date_type,charT>& svp)
{
this->m_sv_strings = svp.m_sv_strings;
}
//! Replace special value strings
void sv_strings(const string_type& nadt_str,
const string_type& neg_inf_str,
const string_type& pos_inf_str,
const string_type& min_dt_str,
const string_type& max_dt_str)
{
collection_type phrases;
phrases.push_back(nadt_str);
phrases.push_back(neg_inf_str);
phrases.push_back(pos_inf_str);
phrases.push_back(min_dt_str);
phrases.push_back(max_dt_str);
m_sv_strings = parse_tree_type(phrases, static_cast<int>(not_a_date_time));
}
/* Does not return a special_value because if the parsing fails,
* the return value will always be not_a_date_time
* (mr.current_match retains its default value of -1 on a failed
* parse and that casts to not_a_date_time). */
//! Sets match_results.current_match to the corresponding special_value or -1
bool match(stream_itr_type& sitr,
stream_itr_type& str_end,
match_results& mr) const
{
unsigned int level = 0;
m_sv_strings.match(sitr, str_end, mr, level);
return (mr.current_match != match_results::PARSE_ERROR);
}
/*special_values match(stream_itr_type& sitr,
stream_itr_type& str_end,
match_results& mr) const
{
unsigned int level = 0;
m_sv_strings.match(sitr, str_end, mr, level);
if(mr.current_match == match_results::PARSE_ERROR) {
throw std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'");
}
return static_cast<special_values>(mr.current_match);
}*/
private:
parse_tree_type m_sv_strings;
};
template<class date_type, class CharT>
const typename special_values_parser<date_type, CharT>::char_type
special_values_parser<date_type, CharT>::nadt_string[16] =
{'n','o','t','-','a','-','d','a','t','e','-','t','i','m','e'};
template<class date_type, class CharT>
const typename special_values_parser<date_type, CharT>::char_type
special_values_parser<date_type, CharT>::neg_inf_string[10] =
{'-','i','n','f','i','n','i','t','y'};
template<class date_type, class CharT>
const typename special_values_parser<date_type, CharT>::char_type
special_values_parser<date_type, CharT>::pos_inf_string[10] =
{'+','i','n','f','i','n','i','t','y'};
template<class date_type, class CharT>
const typename special_values_parser<date_type, CharT>::char_type
special_values_parser<date_type, CharT>::min_date_time_string[18] =
{'m','i','n','i','m','u','m','-','d','a','t','e','-','t','i','m','e'};
template<class date_type, class CharT>
const typename special_values_parser<date_type, CharT>::char_type
special_values_parser<date_type, CharT>::max_date_time_string[18] =
{'m','a','x','i','m','u','m','-','d','a','t','e','-','t','i','m','e'};
} } //namespace
#endif // DATE_TIME_SPECIAL_VALUES_PARSER_HPP__

View File

@ -0,0 +1,32 @@
#ifndef _STRING_CONVERT_HPP___
#define _STRING_CONVERT_HPP___
/* Copyright (c) 2005 CrystalClear Software, Inc.
* Subject to the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include "boost/date_time/compiler_config.hpp"
#include <string>
namespace boost {
namespace date_time {
//! Converts a string from one value_type to another
/*! Converts a wstring to a string (or a string to wstring). If both template parameters
* are of same type, a copy of the input string is returned. */
template<class InputT, class OutputT>
inline
std::basic_string<OutputT> convert_string_type(const std::basic_string<InputT>& inp_str)
{
typedef std::basic_string<OutputT> output_type;
output_type result;
result.insert(result.begin(), inp_str.begin(), inp_str.end());
return result;
}
}} // namespace boost::date_time
#endif // _STRING_CONVERT_HPP___

View File

@ -0,0 +1,278 @@
#ifndef BOOST_DATE_TIME_STRING_PARSE_TREE___HPP__
#define BOOST_DATE_TIME_STRING_PARSE_TREE___HPP__
/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include "boost/lexical_cast.hpp" //error without?
#include "boost/algorithm/string/case_conv.hpp"
#include <map>
#include <string>
#include <vector>
#include <algorithm>
namespace boost { namespace date_time {
template<typename charT>
struct parse_match_result
{
parse_match_result() :
match_depth(0),
current_match(-1)// -1 is match_not-found value
{}
typedef std::basic_string<charT> string_type;
string_type remaining() const
{
if (match_depth == cache.size()) {
return string_type();
}
if (current_match == -1) {
return cache;
}
//some of the cache was used return the rest
return string_type(cache, match_depth);
}
charT last_char() const
{
return cache[cache.size()-1];
}
//! Returns true if more characters were parsed than was necessary
/*! Should be used in conjunction with last_char()
* to get the remaining character.
*/
bool has_remaining() const
{
return (cache.size() > match_depth);
}
// cache will hold characters that have been read from the stream
string_type cache;
unsigned short match_depth;
short current_match;
enum PARSE_STATE { PARSE_ERROR= -1 };
};
//for debug -- really only char streams...
template<typename charT>
std::basic_ostream<charT>&
operator<<(std::basic_ostream<charT>& os, parse_match_result<charT>& mr)
{
os << "cm: " << mr.current_match
<< " C: '" << mr.cache
<< "' md: " << mr.match_depth
<< " R: " << mr.remaining();
return os;
}
//! Recursive data structure to allow efficient parsing of various strings
/*! This class provides a quick lookup by building what amounts to a
* tree data structure. It also features a match function which can
* can handle nasty input interators by caching values as it recurses
* the tree so that it can backtrack as needed.
*/
template<typename charT>
struct string_parse_tree
{
#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x581) )
typedef std::multimap<charT, string_parse_tree< charT> > ptree_coll;
#else
typedef std::multimap<charT, string_parse_tree > ptree_coll;
#endif
typedef typename ptree_coll::value_type value_type;
typedef typename ptree_coll::iterator iterator;
typedef typename ptree_coll::const_iterator const_iterator;
typedef std::basic_string<charT> string_type;
typedef std::vector<std::basic_string<charT> > collection_type;
typedef parse_match_result<charT> parse_match_result_type;
/*! Parameter "starting_point" designates where the numbering begins.
* A starting_point of zero will start the numbering at zero
* (Sun=0, Mon=1, ...) were a starting_point of one starts the
* numbering at one (Jan=1, Feb=2, ...). The default is zero,
* negative vaules are not allowed */
string_parse_tree(collection_type names, unsigned int starting_point=0)
{
// iterate thru all the elements and build the tree
unsigned short index = 0;
while (index != names.size() ) {
string_type s = boost::algorithm::to_lower_copy(names[index]);
insert(s, static_cast<unsigned short>(index + starting_point));
index++;
}
//set the last tree node = index+1 indicating a value
index++;
}
string_parse_tree(short value = -1) :
m_value(value)
{}
ptree_coll m_next_chars;
short m_value;
void insert(const string_type& s, unsigned short value)
{
unsigned int i = 0;
iterator ti;
while(i < s.size()) {
if (i==0) {
if (i == (s.size()-1)) {
ti = m_next_chars.insert(value_type(s[i],
string_parse_tree<charT>(value)));
}
else {
ti = m_next_chars.insert(value_type(s[i],
string_parse_tree<charT>()));
}
}
else {
if (i == (s.size()-1)) {
ti = ti->second.m_next_chars.insert(value_type(s[i],
string_parse_tree<charT>(value)));
}
else {
ti = ti->second.m_next_chars.insert(value_type(s[i],
string_parse_tree<charT>()));
}
}
i++;
}
}
//! Recursive function that finds a matching string in the tree.
/*! Must check match_results::has_remaining() after match() is
* called. This is required so the user can determine if
* stream iterator is already pointing to the expected
* character or not (match() might advance sitr to next char in stream).
*
* A parse_match_result that has been returned from a failed match
* attempt can be sent in to the match function of a different
* string_parse_tree to attempt a match there. Use the iterators
* for the partially consumed stream, the parse_match_result object,
* and '0' for the level parameter. */
short
match(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end,
parse_match_result_type& result,
unsigned int& level) const
{
level++;
charT c;
// if we conditionally advance sitr, we won't have
// to consume the next character past the input
bool adv_itr = true;
if (level > result.cache.size()) {
if (sitr == stream_end) return 0; //bail - input exhausted
c = static_cast<charT>(std::tolower(*sitr));
//result.cache += c;
//sitr++;
}
else {
// if we're looking for characters from the cache,
// we don't want to increment sitr
adv_itr = false;
c = static_cast<charT>(std::tolower(result.cache[level-1]));
}
const_iterator litr = m_next_chars.lower_bound(c);
const_iterator uitr = m_next_chars.upper_bound(c);
while (litr != uitr) { // equal if not found
if(adv_itr) {
sitr++;
result.cache += c;
}
if (litr->second.m_value != -1) { // -1 is default value
if (result.match_depth < level) {
result.current_match = litr->second.m_value;
result.match_depth = static_cast<unsigned short>(level);
}
litr->second.match(sitr, stream_end,
result, level);
level--;
}
else {
litr->second.match(sitr, stream_end,
result, level);
level--;
}
if(level <= result.cache.size()) {
adv_itr = false;
}
litr++;
}
return result.current_match;
}
/*! Must check match_results::has_remaining() after match() is
* called. This is required so the user can determine if
* stream iterator is already pointing to the expected
* character or not (match() might advance sitr to next char in stream).
*/
parse_match_result_type
match(std::istreambuf_iterator<charT>& sitr,
std::istreambuf_iterator<charT>& stream_end) const
{
// lookup to_lower of char in tree.
unsigned int level = 0;
// string_type cache;
parse_match_result_type result;
match(sitr, stream_end, result, level);
return result;
}
void printme(std::ostream& os, int& level)
{
level++;
iterator itr = m_next_chars.begin();
iterator end = m_next_chars.end();
// os << "starting level: " << level << std::endl;
while (itr != end) {
os << "level: " << level
<< " node: " << itr->first
<< " value: " << itr->second.m_value
<< std::endl;
itr->second.printme(os, level);
itr++;
}
level--;
}
void print(std::ostream& os)
{
int level = 0;
printme(os, level);
}
void printmatch(std::ostream& os, charT c)
{
iterator litr = m_next_chars.lower_bound(c);
iterator uitr = m_next_chars.upper_bound(c);
os << "matches for: " << c << std::endl;
while (litr != uitr) {
os << " node: " << litr->first
<< " value: " << litr->second.m_value
<< std::endl;
litr++;
}
}
};
} } //namespace
#endif

View File

@ -0,0 +1,125 @@
#ifndef DATE_TIME_STRINGS_FROM_FACET__HPP___
#define DATE_TIME_STRINGS_FROM_FACET__HPP___
/* Copyright (c) 2004 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland
* $Date$
*/
#include <sstream>
#include <string>
#include <vector>
#include <locale>
namespace boost { namespace date_time {
//! This function gathers up all the month strings from a std::locale
/*! Using the time_put facet, this function creates a collection of
* all the month strings from a locale. This is handy when building
* custom date parsers or formatters that need to be localized.
*
*@param charT The type of char to use when gathering typically char
* or wchar_t.
*@param locale The locale to use when gathering the strings
*@param short_strings True(default) to gather short strings,
* false for long strings.
*@return A vector of strings containing the strings in order. eg:
* Jan, Feb, Mar, etc.
*/
template<typename charT>
std::vector<std::basic_string<charT> >
gather_month_strings(const std::locale& locale, bool short_strings=true)
{
typedef std::basic_string<charT> string_type;
typedef std::vector<string_type> collection_type;
typedef std::ostreambuf_iterator<charT> ostream_iter_type;
typedef std::basic_ostringstream<charT> stringstream_type;
typedef std::time_put<charT> time_put_facet_type;
charT short_fmt[3] = { '%', 'b' };
charT long_fmt[3] = { '%', 'B' };
collection_type months;
string_type outfmt(short_fmt);
if (!short_strings) {
outfmt = long_fmt;
}
{
//grab the needed strings by using the locale to
//output each month
const charT* p_outfmt = outfmt.c_str(), *p_outfmt_end = p_outfmt + outfmt.size();
tm tm_value;
memset(&tm_value, 0, sizeof(tm_value));
for (int m=0; m < 12; m++) {
tm_value.tm_mon = m;
stringstream_type ss;
ostream_iter_type oitr(ss);
std::use_facet<time_put_facet_type>(locale).put(oitr, ss, ss.fill(),
&tm_value,
p_outfmt,
p_outfmt_end);
months.push_back(ss.str());
}
}
return months;
}
//! This function gathers up all the weekday strings from a std::locale
/*! Using the time_put facet, this function creates a collection of
* all the weekday strings from a locale starting with the string for
* 'Sunday'. This is handy when building custom date parsers or
* formatters that need to be localized.
*
*@param charT The type of char to use when gathering typically char
* or wchar_t.
*@param locale The locale to use when gathering the strings
*@param short_strings True(default) to gather short strings,
* false for long strings.
*@return A vector of strings containing the weekdays in order. eg:
* Sun, Mon, Tue, Wed, Thu, Fri, Sat
*/
template<typename charT>
std::vector<std::basic_string<charT> >
gather_weekday_strings(const std::locale& locale, bool short_strings=true)
{
typedef std::basic_string<charT> string_type;
typedef std::vector<string_type> collection_type;
typedef std::ostreambuf_iterator<charT> ostream_iter_type;
typedef std::basic_ostringstream<charT> stringstream_type;
typedef std::time_put<charT> time_put_facet_type;
charT short_fmt[3] = { '%', 'a' };
charT long_fmt[3] = { '%', 'A' };
collection_type weekdays;
string_type outfmt(short_fmt);
if (!short_strings) {
outfmt = long_fmt;
}
{
//grab the needed strings by using the locale to
//output each month / weekday
const charT* p_outfmt = outfmt.c_str(), *p_outfmt_end = p_outfmt + outfmt.size();
tm tm_value;
memset(&tm_value, 0, sizeof(tm_value));
for (int i=0; i < 7; i++) {
tm_value.tm_wday = i;
stringstream_type ss;
ostream_iter_type oitr(ss);
std::use_facet<time_put_facet_type>(locale).put(oitr, ss, ss.fill(),
&tm_value,
p_outfmt,
p_outfmt_end);
weekdays.push_back(ss.str());
}
}
return weekdays;
}
} } //namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
#ifndef DATE_TIME_TIME_FORMATTING_STREAMS_HPP___
#define DATE_TIME_TIME_FORMATTING_STREAMS_HPP___
/* Copyright (c) 2002,2003 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include <boost/date_time/compiler_config.hpp>
#ifndef BOOST_DATE_TIME_NO_LOCALE
#include <locale>
#include <iomanip>
#include <iostream>
#include <boost/date_time/date_formatting_locales.hpp>
#include <boost/date_time/time_resolution_traits.hpp>
namespace boost {
namespace date_time {
//! Put a time type into a stream using appropriate facets
template<class time_duration_type,
class charT = char>
class ostream_time_duration_formatter
{
public:
typedef std::basic_ostream<charT> ostream_type;
typedef typename time_duration_type::fractional_seconds_type fractional_seconds_type;
//! Put time into an ostream
static void duration_put(const time_duration_type& td,
ostream_type& os)
{
if(td.is_special()) {
os << td.get_rep();
}
else {
charT fill_char = '0';
if(td.is_negative()) {
os << '-';
}
os << std::setw(2) << std::setfill(fill_char)
<< absolute_value(td.hours()) << ":";
os << std::setw(2) << std::setfill(fill_char)
<< absolute_value(td.minutes()) << ":";
os << std::setw(2) << std::setfill(fill_char)
<< absolute_value(td.seconds());
fractional_seconds_type frac_sec =
absolute_value(td.fractional_seconds());
if (frac_sec != 0) {
os << "."
<< std::setw(time_duration_type::num_fractional_digits())
<< std::setfill(fill_char)
<< frac_sec;
}
} // else
} // duration_put
}; //class ostream_time_duration_formatter
//! Put a time type into a stream using appropriate facets
template<class time_type,
class charT = char>
class ostream_time_formatter
{
public:
typedef std::basic_ostream<charT> ostream_type;
typedef typename time_type::date_type date_type;
typedef typename time_type::time_duration_type time_duration_type;
typedef ostream_time_duration_formatter<time_duration_type, charT> duration_formatter;
//! Put time into an ostream
static void time_put(const time_type& t,
ostream_type& os)
{
date_type d = t.date();
os << d;
if(!d.is_infinity() && !d.is_not_a_date())
{
os << " "; //TODO: fix the separator here.
duration_formatter::duration_put(t.time_of_day(), os);
}
} // time_to_ostream
}; //class ostream_time_formatter
//! Put a time period into a stream using appropriate facets
template<class time_period_type,
class charT = char>
class ostream_time_period_formatter
{
public:
typedef std::basic_ostream<charT> ostream_type;
typedef typename time_period_type::point_type time_type;
typedef ostream_time_formatter<time_type, charT> time_formatter;
//! Put time into an ostream
static void period_put(const time_period_type& tp,
ostream_type& os)
{
os << '['; //TODO: facet or manipulator for periods?
time_formatter::time_put(tp.begin(), os);
os << '/'; //TODO: facet or manipulator for periods?
time_formatter::time_put(tp.last(), os);
os << ']';
} // period_put
}; //class ostream_time_period_formatter
} } //namespace date_time
#endif //BOOST_DATE_TIME_NO_LOCALE
#endif

View File

@ -0,0 +1,324 @@
#ifndef _DATE_TIME_TIME_PARSING_HPP___
#define _DATE_TIME_TIME_PARSING_HPP___
/* Copyright (c) 2002,2003,2005 CrystalClear Software, Inc.
* Use, modification and distribution is subject to the
* Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
* Author: Jeff Garland, Bart Garst
* $Date$
*/
#include "boost/tokenizer.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/date_time/date_parsing.hpp"
#include "boost/cstdint.hpp"
#include <iostream>
namespace boost {
namespace date_time {
//! computes exponential math like 2^8 => 256, only works with positive integers
//Not general purpose, but needed b/c std::pow is not available
//everywehere. Hasn't been tested with negatives and zeros
template<class int_type>
inline
int_type power(int_type base, int_type exponent)
{
int_type result = 1;
for(int i = 0; i < exponent; ++i){
result *= base;
}
return result;
}
//! Creates a time_duration object from a delimited string
/*! Expected format for string is "[-]h[h][:mm][:ss][.fff]".
* If the number of fractional digits provided is greater than the
* precision of the time duration type then the extra digits are
* truncated.
*
* A negative duration will be created if the first character in
* string is a '-', all other '-' will be treated as delimiters.
* Accepted delimiters are "-:,.".
*/
template<class time_duration, class char_type>
inline
time_duration
str_from_delimited_time_duration(const std::basic_string<char_type>& s)
{
unsigned short min=0, sec =0;
int hour =0;
bool is_neg = (s.at(0) == '-');
boost::int64_t fs=0;
int pos = 0;
typedef typename std::basic_string<char_type>::traits_type traits_type;
typedef boost::char_separator<char_type, traits_type> char_separator_type;
typedef boost::tokenizer<char_separator_type,
typename std::basic_string<char_type>::const_iterator,
std::basic_string<char_type> > tokenizer;
typedef typename boost::tokenizer<char_separator_type,
typename std::basic_string<char_type>::const_iterator,
typename std::basic_string<char_type> >::iterator tokenizer_iterator;
char_type sep_chars[5] = {'-',':',',','.'};
char_separator_type sep(sep_chars);
tokenizer tok(s,sep);
for(tokenizer_iterator beg=tok.begin(); beg!=tok.end();++beg){
switch(pos) {
case 0: {
hour = boost::lexical_cast<int>(*beg);
break;
}
case 1: {
min = boost::lexical_cast<unsigned short>(*beg);
break;
}
case 2: {
sec = boost::lexical_cast<unsigned short>(*beg);
break;
};
case 3: {
int digits = static_cast<int>(beg->length());
//Works around a bug in MSVC 6 library that does not support
//operator>> thus meaning lexical_cast will fail to compile.
#if (defined(BOOST_MSVC) && (_MSC_VER < 1300))
// msvc wouldn't compile 'time_duration::num_fractional_digits()'
// (required template argument list) as a workaround a temp
// time_duration object was used
time_duration td(hour,min,sec,fs);
int precision = td.num_fractional_digits();
// _atoi64 is an MS specific function
if(digits >= precision) {
// drop excess digits
fs = _atoi64(beg->substr(0, precision).c_str());
}
else {
fs = _atoi64(beg->c_str());
}
#else
int precision = time_duration::num_fractional_digits();
if(digits >= precision) {
// drop excess digits
fs = boost::lexical_cast<boost::int64_t>(beg->substr(0, precision));
}
else {
fs = boost::lexical_cast<boost::int64_t>(*beg);
}
#endif
if(digits < precision){
// trailing zeros get dropped from the string,
// "1:01:01.1" would yield .000001 instead of .100000
// the power() compensates for the missing decimal places
fs *= power(10, precision - digits);
}
break;
}
default: break;
}//switch
pos++;
}
if(is_neg) {
return -time_duration(hour, min, sec, fs);
}
else {
return time_duration(hour, min, sec, fs);
}
}
//! Creates a time_duration object from a delimited string
/*! Expected format for string is "[-]h[h][:mm][:ss][.fff]".
* If the number of fractional digits provided is greater than the
* precision of the time duration type then the extra digits are
* truncated.
*
* A negative duration will be created if the first character in
* string is a '-', all other '-' will be treated as delimiters.
* Accepted delimiters are "-:,.".
*/
template<class time_duration>
inline
time_duration
parse_delimited_time_duration(const std::string& s)
{
return str_from_delimited_time_duration<time_duration,char>(s);
}
//! Utility function to split appart string
inline
bool
split(const std::string& s,
char sep,
std::string& first,
std::string& second)
{
std::string::size_type sep_pos = s.find(sep);
first = s.substr(0,sep_pos);
if (sep_pos!=std::string::npos)
second = s.substr(sep_pos+1);
return true;
}
template<class time_type>
inline
time_type
parse_delimited_time(const std::string& s, char sep)
{
typedef typename time_type::time_duration_type time_duration;
typedef typename time_type::date_type date_type;
//split date/time on a unique delimiter char such as ' ' or 'T'
std::string date_string, tod_string;
split(s, sep, date_string, tod_string);
//call parse_date with first string
date_type d = parse_date<date_type>(date_string);
//call parse_time_duration with remaining string
time_duration td = parse_delimited_time_duration<time_duration>(tod_string);
//construct a time
return time_type(d, td);
}
//! Parse time duration part of an iso time of form: [-]hhmmss[.fff...] (eg: 120259.123 is 12 hours, 2 min, 59 seconds, 123000 microseconds)
template<class time_duration>
inline
time_duration
parse_undelimited_time_duration(const std::string& s)
{
int precision = 0;
{
// msvc wouldn't compile 'time_duration::num_fractional_digits()'
// (required template argument list) as a workaround, a temp
// time_duration object was used
time_duration tmp(0,0,0,1);
precision = tmp.num_fractional_digits();
}
// 'precision+1' is so we grab all digits, plus the decimal
int offsets[] = {2,2,2, precision+1};
int pos = 0, sign = 0;
int hours = 0;
short min=0, sec=0;
boost::int64_t fs=0;
// increment one position if the string was "signed"
if(s.at(sign) == '-')
{
++sign;
}
// stlport choked when passing s.substr() to tokenizer
// using a new string fixed the error
std::string remain = s.substr(sign);
/* We do not want the offset_separator to wrap the offsets, we
* will never want to process more than:
* 2 char, 2 char, 2 char, frac_sec length.
* We *do* want the offset_separator to give us a partial for the
* last characters if there were not enough provided in the input string. */
bool wrap_off = false;
bool ret_part = true;
boost::offset_separator osf(offsets, offsets+4, wrap_off, ret_part);
typedef boost::tokenizer<boost::offset_separator,
std::basic_string<char>::const_iterator,
std::basic_string<char> > tokenizer;
typedef boost::tokenizer<boost::offset_separator,
std::basic_string<char>::const_iterator,
std::basic_string<char> >::iterator tokenizer_iterator;
tokenizer tok(remain, osf);
for(tokenizer_iterator ti=tok.begin(); ti!=tok.end();++ti){
switch(pos) {
case 0:
{
hours = boost::lexical_cast<int>(*ti);
break;
}
case 1:
{
min = boost::lexical_cast<short>(*ti);
break;
}
case 2:
{
sec = boost::lexical_cast<short>(*ti);
break;
}
case 3:
{
std::string char_digits(ti->substr(1)); // digits w/no decimal
int digits = static_cast<int>(char_digits.length());
//Works around a bug in MSVC 6 library that does not support
//operator>> thus meaning lexical_cast will fail to compile.
#if (defined(BOOST_MSVC) && (_MSC_VER <= 1200)) // 1200 == VC++ 6.0
// _atoi64 is an MS specific function
if(digits >= precision) {
// drop excess digits
fs = _atoi64(char_digits.substr(0, precision).c_str());
}
else if(digits == 0) {
fs = 0; // just in case _atoi64 doesn't like an empty string
}
else {
fs = _atoi64(char_digits.c_str());
}
#else
if(digits >= precision) {
// drop excess digits
fs = boost::lexical_cast<boost::int64_t>(char_digits.substr(0, precision));
}
else if(digits == 0) {
fs = 0; // lexical_cast doesn't like empty strings
}
else {
fs = boost::lexical_cast<boost::int64_t>(char_digits);
}
#endif
if(digits < precision){
// trailing zeros get dropped from the string,
// "1:01:01.1" would yield .000001 instead of .100000
// the power() compensates for the missing decimal places
fs *= power(10, precision - digits);
}
break;
}
default: break;
};
pos++;
}
if(sign) {
return -time_duration(hours, min, sec, fs);
}
else {
return time_duration(hours, min, sec, fs);
}
}
//! Parse time string of form YYYYMMDDThhmmss where T is delimeter between date and time
template<class time_type>
inline
time_type
parse_iso_time(const std::string& s, char sep)
{
typedef typename time_type::time_duration_type time_duration;
typedef typename time_type::date_type date_type;
//split date/time on a unique delimiter char such as ' ' or 'T'
std::string date_string, tod_string;
split(s, sep, date_string, tod_string);
//call parse_date with first string
date_type d = parse_undelimited_date<date_type>(date_string);
//call parse_time_duration with remaining string
time_duration td = parse_undelimited_time_duration<time_duration>(tod_string);
//construct a time
return time_type(d, td);
}
} }//namespace date_time
#endif

View File

@ -0,0 +1,307 @@
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ALLOCATOR_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/containers/version_type.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/assert.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/container/detail/placement_new.hpp>
#include <cstddef>
#include <stdexcept>
//!\file
//!Describes an allocator that allocates portions of fixed size
//!memory buffer (shared memory, mapped file...)
namespace boost {
namespace interprocess {
//!An STL compatible allocator that uses a segment manager as
//!memory source. The internal pointer type will of the same type (raw, smart) as
//!"typename SegmentManager::void_pointer" type. This allows
//!placing the allocator in shared memory, memory mapped-files, etc...
template<class T, class SegmentManager>
class allocator
{
public:
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
//Self type
typedef allocator<T, SegmentManager> self_t;
//Pointer to void
typedef typename segment_manager::void_pointer aux_pointer_t;
//Typedef to const void pointer
typedef typename boost::intrusive::
pointer_traits<aux_pointer_t>::template
rebind_pointer<const void>::type cvoid_ptr;
//Pointer to the allocator
typedef typename boost::intrusive::
pointer_traits<cvoid_ptr>::template
rebind_pointer<segment_manager>::type alloc_ptr_t;
//Not assignable from related allocator
template<class T2, class SegmentManager2>
allocator& operator=(const allocator<T2, SegmentManager2>&);
//Not assignable from other allocator
allocator& operator=(const allocator&);
//Pointer to the allocator
alloc_ptr_t mp_mngr;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef T value_type;
typedef typename boost::intrusive::
pointer_traits<cvoid_ptr>::template
rebind_pointer<T>::type pointer;
typedef typename boost::intrusive::
pointer_traits<pointer>::template
rebind_pointer<const T>::type const_pointer;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef boost::interprocess::version_type<allocator, 2> version;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Experimental. Don't use.
typedef boost::container::container_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Obtains an allocator that allocates
//!objects of type T2
template<class T2>
struct rebind
{
typedef allocator<T2, SegmentManager> other;
};
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return ipcdetail::to_raw_pointer(mp_mngr); }
//!Constructor from the segment manager.
//!Never throws
allocator(segment_manager *segment_mngr)
: mp_mngr(segment_mngr) { }
//!Constructor from other allocator.
//!Never throws
allocator(const allocator &other)
: mp_mngr(other.get_segment_manager()){ }
//!Constructor from related allocator.
//!Never throws
template<class T2>
allocator(const allocator<T2, SegmentManager> &other)
: mp_mngr(other.get_segment_manager()){}
//!Allocates memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_ptr hint = 0)
{
(void)hint;
if(size_overflows<sizeof(T)>(count)){
throw bad_alloc();
}
return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
}
//!Deallocates memory previously allocated.
//!Never throws
void deallocate(const pointer &ptr, size_type)
{ mp_mngr->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); }
//!Returns the number of elements that could be allocated.
//!Never throws
size_type max_size() const
{ return mp_mngr->get_size()/sizeof(T); }
//!Swap segment manager. Does not throw. If each allocator is placed in
//!different memory segments, the result is undefined.
friend void swap(self_t &alloc1, self_t &alloc2)
{ boost::adl_move_swap(alloc1.mp_mngr, alloc2.mp_mngr); }
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)mp_mngr->size(ipcdetail::to_raw_pointer(p))/sizeof(T);
}
pointer allocation_command(boost::interprocess::allocation_type command,
size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
{
value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse);
pointer const p = mp_mngr->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse_raw);
reuse = reuse_raw;
return p;
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
{
if(size_overflows<sizeof(T)>(elem_size)){
throw bad_alloc();
}
mp_mngr->allocate_many(elem_size*sizeof(T), num_elements, chain);
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
{
mp_mngr->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain &chain)
{ mp_mngr->deallocate_many(chain); }
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{ return this->allocate(1); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
{ this->allocate_many(1, num_elements, chain); }
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{ return this->deallocate(p, 1); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain &chain)
{ this->deallocate_many(chain); }
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
//!Constructs an object
//!Throws if T's constructor throws
//!For backwards compatibility with libraries using C++03 allocators
template<class P>
void construct(const pointer &ptr, BOOST_FWD_REF(P) p)
{ ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward<P>(p)); }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
//!Equality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator==(const allocator<T , SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() == alloc2.get_segment_manager(); }
//!Inequality test for same type
//!of allocator
template<class T, class SegmentManager> inline
bool operator!=(const allocator<T, SegmentManager> &alloc1,
const allocator<T, SegmentManager> &alloc2)
{ return alloc1.get_segment_manager() != alloc2.get_segment_manager(); }
} //namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
template<class T>
struct has_trivial_destructor;
template<class T, class SegmentManager>
struct has_trivial_destructor
<boost::interprocess::allocator <T, SegmentManager> >
{
static const bool value = true;
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_ALLOCATOR_HPP

View File

@ -0,0 +1,858 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP
#define BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp> //to_raw_pointer
#include <boost/utility/addressof.hpp> //boost::addressof
#include <boost/assert.hpp> //BOOST_ASSERT
#include <boost/interprocess/exceptions.hpp> //bad_alloc
#include <boost/interprocess/sync/scoped_lock.hpp> //scoped_lock
#include <boost/interprocess/containers/allocation_type.hpp> //boost::interprocess::allocation_type
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/interprocess/mem_algo/detail/mem_algo_common.hpp>
#include <boost/interprocess/detail/segment_manager_helper.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/container/detail/placement_new.hpp>
#include <boost/move/adl_move_swap.hpp>
namespace boost {
namespace interprocess {
template <class T>
struct sizeof_value
{
static const std::size_t value = sizeof(T);
};
template <>
struct sizeof_value<void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<const void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<volatile void>
{
static const std::size_t value = sizeof(void*);
};
template <>
struct sizeof_value<const volatile void>
{
static const std::size_t value = sizeof(void*);
};
namespace ipcdetail {
//!Object function that creates the node allocator if it is not created and
//!increments reference count if it is already created
template<class NodePool>
struct get_or_create_node_pool_func
{
//!This connects or constructs the unique instance of node_pool_t
//!Can throw boost::interprocess::bad_alloc
void operator()()
{
//Find or create the node_pool_t
mp_node_pool = mp_segment_manager->template find_or_construct
<NodePool>(boost::interprocess::unique_instance)(mp_segment_manager);
//If valid, increment link count
if(mp_node_pool != 0)
mp_node_pool->inc_ref_count();
}
//!Constructor. Initializes function
//!object parameters
get_or_create_node_pool_func(typename NodePool::segment_manager *mngr)
: mp_segment_manager(mngr){}
NodePool *mp_node_pool;
typename NodePool::segment_manager *mp_segment_manager;
};
template<class NodePool>
inline NodePool *get_or_create_node_pool(typename NodePool::segment_manager *mgnr)
{
ipcdetail::get_or_create_node_pool_func<NodePool> func(mgnr);
mgnr->atomic_func(func);
return func.mp_node_pool;
}
//!Object function that decrements the reference count. If the count
//!reaches to zero destroys the node allocator from memory.
//!Never throws
template<class NodePool>
struct destroy_if_last_link_func
{
//!Decrements reference count and destroys the object if there is no
//!more attached allocators. Never throws
void operator()()
{
//If not the last link return
if(mp_node_pool->dec_ref_count() != 0) return;
//Last link, let's destroy the segment_manager
mp_node_pool->get_segment_manager()->template destroy<NodePool>(boost::interprocess::unique_instance);
}
//!Constructor. Initializes function
//!object parameters
destroy_if_last_link_func(NodePool *pool)
: mp_node_pool(pool)
{}
NodePool *mp_node_pool;
};
//!Destruction function, initializes and executes destruction function
//!object. Never throws
template<class NodePool>
inline void destroy_node_pool_if_last_link(NodePool *pool)
{
//Get segment manager
typename NodePool::segment_manager *mngr = pool->get_segment_manager();
//Execute destruction functor atomically
destroy_if_last_link_func<NodePool>func(pool);
mngr->atomic_func(func);
}
template<class NodePool>
class cache_impl
{
typedef typename NodePool::segment_manager::
void_pointer void_pointer;
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<NodePool>::type node_pool_ptr;
typedef typename NodePool::multiallocation_chain multiallocation_chain;
typedef typename NodePool::segment_manager::size_type size_type;
node_pool_ptr mp_node_pool;
multiallocation_chain m_cached_nodes;
size_type m_max_cached_nodes;
public:
typedef typename NodePool::segment_manager segment_manager;
cache_impl(segment_manager *segment_mngr, size_type max_cached_nodes)
: mp_node_pool(get_or_create_node_pool<NodePool>(segment_mngr))
, m_max_cached_nodes(max_cached_nodes)
{}
cache_impl(const cache_impl &other)
: mp_node_pool(other.get_node_pool())
, m_max_cached_nodes(other.get_max_cached_nodes())
{
mp_node_pool->inc_ref_count();
}
~cache_impl()
{
this->deallocate_all_cached_nodes();
ipcdetail::destroy_node_pool_if_last_link(ipcdetail::to_raw_pointer(mp_node_pool));
}
NodePool *get_node_pool() const
{ return ipcdetail::to_raw_pointer(mp_node_pool); }
segment_manager *get_segment_manager() const
{ return mp_node_pool->get_segment_manager(); }
size_type get_max_cached_nodes() const
{ return m_max_cached_nodes; }
void *cached_allocation()
{
//If don't have any cached node, we have to get a new list of free nodes from the pool
if(m_cached_nodes.empty()){
mp_node_pool->allocate_nodes(m_max_cached_nodes/2, m_cached_nodes);
}
void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front());
return ret;
}
void cached_allocation(size_type n, multiallocation_chain &chain)
{
size_type count = n, allocated(0);
BOOST_TRY{
//If don't have any cached node, we have to get a new list of free nodes from the pool
while(!m_cached_nodes.empty() && count--){
void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front());
chain.push_back(ret);
++allocated;
}
if(allocated != n){
mp_node_pool->allocate_nodes(n - allocated, chain);
}
}
BOOST_CATCH(...){
this->cached_deallocation(chain);
BOOST_RETHROW
}
BOOST_CATCH_END
}
void cached_deallocation(void *ptr)
{
//Check if cache is full
if(m_cached_nodes.size() >= m_max_cached_nodes){
//This only occurs if this allocator deallocate memory allocated
//with other equal allocator. Since the cache is full, and more
//deallocations are probably coming, we'll make some room in cache
//in a single, efficient multi node deallocation.
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2);
}
m_cached_nodes.push_front(ptr);
}
void cached_deallocation(multiallocation_chain &chain)
{
m_cached_nodes.splice_after(m_cached_nodes.before_begin(), chain);
//Check if cache is full
if(m_cached_nodes.size() >= m_max_cached_nodes){
//This only occurs if this allocator deallocate memory allocated
//with other equal allocator. Since the cache is full, and more
//deallocations are probably coming, we'll make some room in cache
//in a single, efficient multi node deallocation.
this->priv_deallocate_n_nodes(m_cached_nodes.size() - m_max_cached_nodes/2);
}
}
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(size_type newmax)
{
m_max_cached_nodes = newmax;
this->priv_deallocate_remaining_nodes();
}
//!Frees all cached nodes.
//!Never throws
void deallocate_all_cached_nodes()
{
if(m_cached_nodes.empty()) return;
mp_node_pool->deallocate_nodes(m_cached_nodes);
}
private:
//!Frees all cached nodes at once.
//!Never throws
void priv_deallocate_remaining_nodes()
{
if(m_cached_nodes.size() > m_max_cached_nodes){
priv_deallocate_n_nodes(m_cached_nodes.size()-m_max_cached_nodes);
}
}
//!Frees n cached nodes at once. Never throws
void priv_deallocate_n_nodes(size_type n)
{
//This only occurs if this allocator deallocate memory allocated
//with other equal allocator. Since the cache is full, and more
//deallocations are probably coming, we'll make some room in cache
//in a single, efficient multi node deallocation.
size_type count(n);
typename multiallocation_chain::iterator it(m_cached_nodes.before_begin());
while(count--){
++it;
}
multiallocation_chain chain;
chain.splice_after(chain.before_begin(), m_cached_nodes, m_cached_nodes.before_begin(), it, n);
//Deallocate all new linked list at once
mp_node_pool->deallocate_nodes(chain);
}
public:
void swap(cache_impl &other)
{
::boost::adl_move_swap(mp_node_pool, other.mp_node_pool);
::boost::adl_move_swap(m_cached_nodes, other.m_cached_nodes);
::boost::adl_move_swap(m_max_cached_nodes, other.m_max_cached_nodes);
}
};
template<class Derived, class T, class SegmentManager>
class array_allocation_impl
{
const Derived *derived() const
{ return static_cast<const Derived*>(this); }
Derived *derived()
{ return static_cast<Derived*>(this); }
typedef typename SegmentManager::void_pointer void_pointer;
public:
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<T>::type pointer;
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<const T>::type const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename SegmentManager::size_type size_type;
typedef typename SegmentManager::difference_type difference_type;
typedef boost::container::container_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
public:
//!Returns maximum the number of objects the previously allocated memory
//!pointed by p can hold. This size only works for memory allocated with
//!allocate, allocation_command and allocate_many.
size_type size(const pointer &p) const
{
return (size_type)this->derived()->get_segment_manager()->size(ipcdetail::to_raw_pointer(p))/sizeof(T);
}
pointer allocation_command(boost::interprocess::allocation_type command,
size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
{
value_type *reuse_raw = ipcdetail::to_raw_pointer(reuse);
pointer const p = this->derived()->get_segment_manager()->allocation_command
(command, limit_size, prefer_in_recvd_out_size, reuse_raw);
reuse = reuse_raw;
return p;
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void allocate_many(size_type elem_size, size_type num_elements, multiallocation_chain &chain)
{
if(size_overflows<sizeof(T)>(elem_size)){
throw bad_alloc();
}
this->derived()->get_segment_manager()->allocate_many(elem_size*sizeof(T), num_elements, chain);
}
//!Allocates n_elements elements, each one of size elem_sizes[i]in a
//!contiguous block
//!of memory. The elements must be deallocated
void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain)
{
this->derived()->get_segment_manager()->allocate_many(elem_sizes, n_elements, sizeof(T), chain);
}
//!Allocates many elements of size elem_size in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. The elements must be deallocated
//!with deallocate(...)
void deallocate_many(multiallocation_chain &chain)
{ this->derived()->get_segment_manager()->deallocate_many(chain); }
//!Returns the number of elements that could be
//!allocated. Never throws
size_type max_size() const
{ return this->derived()->get_segment_manager()->get_size()/sizeof(T); }
//!Returns address of mutable object.
//!Never throws
pointer address(reference value) const
{ return pointer(boost::addressof(value)); }
//!Returns address of non mutable object.
//!Never throws
const_pointer address(const_reference value) const
{ return const_pointer(boost::addressof(value)); }
//!Constructs an object
//!Throws if T's constructor throws
//!For backwards compatibility with libraries using C++03 allocators
template<class P>
void construct(const pointer &ptr, BOOST_FWD_REF(P) p)
{ ::new((void*)ipcdetail::to_raw_pointer(ptr), boost_container_new_t()) value_type(::boost::forward<P>(p)); }
//!Destroys object. Throws if object's
//!destructor throws
void destroy(const pointer &ptr)
{ BOOST_ASSERT(ptr != 0); (*ptr).~value_type(); }
};
template<class Derived, unsigned int Version, class T, class SegmentManager>
class node_pool_allocation_impl
: public array_allocation_impl
< Derived
, T
, SegmentManager>
{
const Derived *derived() const
{ return static_cast<const Derived*>(this); }
Derived *derived()
{ return static_cast<Derived*>(this); }
typedef typename SegmentManager::void_pointer void_pointer;
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<const void>::type cvoid_pointer;
public:
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<T>::type pointer;
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<const T>::type const_pointer;
typedef T value_type;
typedef typename ipcdetail::add_reference
<value_type>::type reference;
typedef typename ipcdetail::add_reference
<const value_type>::type const_reference;
typedef typename SegmentManager::size_type size_type;
typedef typename SegmentManager::difference_type difference_type;
typedef boost::container::container_detail::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
template <int Dummy>
struct node_pool
{
typedef typename Derived::template node_pool<0>::type type;
static type *get(void *p)
{ return static_cast<type*>(p); }
};
public:
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0)
{
(void)hint;
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
if(size_overflows<sizeof(T)>(count)){
throw bad_alloc();
}
else if(Version == 1 && count == 1){
return pointer(static_cast<value_type*>
(pool->allocate_node()));
}
else{
return pointer(static_cast<value_type*>
(pool->get_segment_manager()->allocate(count*sizeof(T))));
}
}
//!Deallocate allocated memory. Never throws
void deallocate(const pointer &ptr, size_type count)
{
(void)count;
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
if(Version == 1 && count == 1)
pool->deallocate_node(ipcdetail::to_raw_pointer(ptr));
else
pool->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_pointer(ptr));
}
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
return pointer(static_cast<value_type*>(pool->allocate_node()));
}
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
pool->allocate_nodes(num_elements, chain);
}
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{
typedef typename node_pool<0>::type node_pool_t;
node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
pool->deallocate_node(ipcdetail::to_raw_pointer(p));
}
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain &chain)
{
node_pool<0>::get(this->derived()->get_node_pool())->deallocate_nodes
(chain);
}
//!Deallocates all free blocks of the pool
void deallocate_free_blocks()
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); }
//!Deprecated, use deallocate_free_blocks.
//!Deallocates all free chunks of the pool.
void deallocate_free_chunks()
{ node_pool<0>::get(this->derived()->get_node_pool())->deallocate_free_blocks(); }
};
template<class T, class NodePool, unsigned int Version>
class cached_allocator_impl
: public array_allocation_impl
<cached_allocator_impl<T, NodePool, Version>, T, typename NodePool::segment_manager>
{
cached_allocator_impl & operator=(const cached_allocator_impl& other);
typedef array_allocation_impl
< cached_allocator_impl
<T, NodePool, Version>
, T
, typename NodePool::segment_manager> base_t;
public:
typedef NodePool node_pool_t;
typedef typename NodePool::segment_manager segment_manager;
typedef typename segment_manager::void_pointer void_pointer;
typedef typename boost::intrusive::
pointer_traits<void_pointer>::template
rebind_pointer<const void>::type cvoid_pointer;
typedef typename base_t::pointer pointer;
typedef typename base_t::size_type size_type;
typedef typename base_t::multiallocation_chain multiallocation_chain;
typedef typename base_t::value_type value_type;
public:
static const std::size_t DEFAULT_MAX_CACHED_NODES = 64;
cached_allocator_impl(segment_manager *segment_mngr, size_type max_cached_nodes)
: m_cache(segment_mngr, max_cached_nodes)
{}
cached_allocator_impl(const cached_allocator_impl &other)
: m_cache(other.m_cache)
{}
//!Copy constructor from related cached_adaptive_pool_base. If not present, constructs
//!a node pool. Increments the reference count of the associated node pool.
//!Can throw boost::interprocess::bad_alloc
template<class T2, class NodePool2>
cached_allocator_impl
(const cached_allocator_impl
<T2, NodePool2, Version> &other)
: m_cache(other.get_segment_manager(), other.get_max_cached_nodes())
{}
//!Returns a pointer to the node pool.
//!Never throws
node_pool_t* get_node_pool() const
{ return m_cache.get_node_pool(); }
//!Returns the segment manager.
//!Never throws
segment_manager* get_segment_manager()const
{ return m_cache.get_segment_manager(); }
//!Sets the new max cached nodes value. This can provoke deallocations
//!if "newmax" is less than current cached nodes. Never throws
void set_max_cached_nodes(size_type newmax)
{ m_cache.set_max_cached_nodes(newmax); }
//!Returns the max cached nodes parameter.
//!Never throws
size_type get_max_cached_nodes() const
{ return m_cache.get_max_cached_nodes(); }
//!Allocate memory for an array of count elements.
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate(size_type count, cvoid_pointer hint = 0)
{
(void)hint;
void * ret;
if(size_overflows<sizeof(T)>(count)){
throw bad_alloc();
}
else if(Version == 1 && count == 1){
ret = m_cache.cached_allocation();
}
else{
ret = this->get_segment_manager()->allocate(count*sizeof(T));
}
return pointer(static_cast<T*>(ret));
}
//!Deallocate allocated memory. Never throws
void deallocate(const pointer &ptr, size_type count)
{
(void)count;
if(Version == 1 && count == 1){
m_cache.cached_deallocation(ipcdetail::to_raw_pointer(ptr));
}
else{
this->get_segment_manager()->deallocate((void*)ipcdetail::to_raw_pointer(ptr));
}
}
//!Allocates just one object. Memory allocated with this function
//!must be deallocated only with deallocate_one().
//!Throws boost::interprocess::bad_alloc if there is no enough memory
pointer allocate_one()
{ return pointer(static_cast<value_type*>(this->m_cache.cached_allocation())); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void allocate_individual(size_type num_elements, multiallocation_chain &chain)
{ this->m_cache.cached_allocation(num_elements, chain); }
//!Deallocates memory previously allocated with allocate_one().
//!You should never use deallocate_one to deallocate memory allocated
//!with other functions different from allocate_one(). Never throws
void deallocate_one(const pointer &p)
{ this->m_cache.cached_deallocation(ipcdetail::to_raw_pointer(p)); }
//!Allocates many elements of size == 1 in a contiguous block
//!of memory. The minimum number to be allocated is min_elements,
//!the preferred and maximum number is
//!preferred_elements. The number of actually allocated elements is
//!will be assigned to received_size. Memory allocated with this function
//!must be deallocated only with deallocate_one().
void deallocate_individual(multiallocation_chain &chain)
{ m_cache.cached_deallocation(chain); }
//!Deallocates all free blocks of the pool
void deallocate_free_blocks()
{ m_cache.get_node_pool()->deallocate_free_blocks(); }
//!Swaps allocators. Does not throw. If each allocator is placed in a
//!different shared memory segments, the result is undefined.
friend void swap(cached_allocator_impl &alloc1, cached_allocator_impl &alloc2)
{ ::boost::adl_move_swap(alloc1.m_cache, alloc2.m_cache); }
void deallocate_cache()
{ m_cache.deallocate_all_cached_nodes(); }
//!Deprecated use deallocate_free_blocks.
void deallocate_free_chunks()
{ m_cache.get_node_pool()->deallocate_free_blocks(); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
cache_impl<node_pool_t> m_cache;
#endif //!defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
};
//!Equality test for same type of
//!cached_allocator_impl
template<class T, class N, unsigned int V> inline
bool operator==(const cached_allocator_impl<T, N, V> &alloc1,
const cached_allocator_impl<T, N, V> &alloc2)
{ return alloc1.get_node_pool() == alloc2.get_node_pool(); }
//!Inequality test for same type of
//!cached_allocator_impl
template<class T, class N, unsigned int V> inline
bool operator!=(const cached_allocator_impl<T, N, V> &alloc1,
const cached_allocator_impl<T, N, V> &alloc2)
{ return alloc1.get_node_pool() != alloc2.get_node_pool(); }
//!Pooled shared memory allocator using adaptive pool. Includes
//!a reference count but the class does not delete itself, this is
//!responsibility of user classes. Node size (NodeSize) and the number of
//!nodes allocated per block (NodesPerBlock) are known at compile time
template<class private_node_allocator_t>
class shared_pool_impl
: public private_node_allocator_t
{
public:
//!Segment manager typedef
typedef typename private_node_allocator_t::
segment_manager segment_manager;
typedef typename private_node_allocator_t::
multiallocation_chain multiallocation_chain;
typedef typename private_node_allocator_t::
size_type size_type;
private:
typedef typename segment_manager::mutex_family::mutex_type mutex_type;
public:
//!Constructor from a segment manager. Never throws
shared_pool_impl(segment_manager *segment_mngr)
: private_node_allocator_t(segment_mngr)
{}
//!Destructor. Deallocates all allocated blocks. Never throws
~shared_pool_impl()
{}
//!Allocates array of count elements. Can throw boost::interprocess::bad_alloc
void *allocate_node()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return private_node_allocator_t::allocate_node();
}
//!Deallocates an array pointed by ptr. Never throws
void deallocate_node(void *ptr)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_node(ptr);
}
//!Allocates n nodes.
//!Can throw boost::interprocess::bad_alloc
void allocate_nodes(const size_type n, multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::allocate_nodes(n, chain);
}
//!Deallocates a linked list of nodes ending in null pointer. Never throws
void deallocate_nodes(multiallocation_chain &nodes, size_type num)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(nodes, num);
}
//!Deallocates the nodes pointed by the multiallocation iterator. Never throws
void deallocate_nodes(multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_nodes(chain);
}
//!Deallocates all the free blocks of memory. Never throws
void deallocate_free_blocks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_free_blocks();
}
//!Deallocates all used memory from the common pool.
//!Precondition: all nodes allocated from this pool should
//!already be deallocated. Otherwise, undefined behavior. Never throws
void purge_blocks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::purge_blocks();
}
//!Increments internal reference count and returns new count. Never throws
size_type inc_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
return ++m_header.m_usecount;
}
//!Decrements internal reference count and returns new count. Never throws
size_type dec_ref_count()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
BOOST_ASSERT(m_header.m_usecount > 0);
return --m_header.m_usecount;
}
//!Deprecated, use deallocate_free_blocks.
void deallocate_free_chunks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::deallocate_free_blocks();
}
//!Deprecated, use purge_blocks.
void purge_chunks()
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
private_node_allocator_t::purge_blocks();
}
private:
//!This struct includes needed data and derives from
//!the mutex type to allow EBO when using null_mutex
struct header_t : mutex_type
{
size_type m_usecount; //Number of attached allocators
header_t()
: m_usecount(0) {}
} m_header;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ALLOCATOR_DETAIL_ALLOCATOR_COMMON_HPP

View File

@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/detail/allocation_type.hpp>
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef int allocation_type;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
static const allocation_type allocate_new = boost::container::allocate_new;
static const allocation_type expand_fwd = boost::container::expand_fwd;
static const allocation_type expand_bwd = boost::container::expand_bwd;
static const allocation_type shrink_in_place = boost::container::shrink_in_place;
static const allocation_type try_shrink_in_place= boost::container::try_shrink_in_place;
static const allocation_type nothrow_allocation = boost::container::nothrow_allocation;
static const allocation_type zero_memory = boost::container::zero_memory;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_ALLOCATION_TYPE_HPP

View File

@ -0,0 +1,44 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2009-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP
#define BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
//////////////////////////////////////////////////////////////////////////////
// Standard predeclarations
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/container_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::ordered_range;
using boost::container::ordered_unique_range;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_CONTAINERS_FWD_HPP

View File

@ -0,0 +1,37 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
#define BOOST_INTERPROCESS_CONTAINERS_STRING_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/string.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::basic_string;
using boost::container::string;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_STRING_HPP

View File

@ -0,0 +1,37 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
#define BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/vector.hpp>
#include <boost/interprocess/containers/containers_fwd.hpp>
namespace boost {
namespace interprocess {
using boost::container::vector;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VECTOR_HPP

View File

@ -0,0 +1,37 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
#define BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/container/detail/version_type.hpp>
namespace boost {
namespace interprocess {
using boost::container::container_detail::version_type;
using boost::container::container_detail::version;
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif // #ifndef BOOST_INTERPROCESS_CONTAINERS_VERSION_TYPE_HPP

View File

@ -0,0 +1,31 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
#define BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost { namespace interprocess { namespace ipcdetail {
struct static_cast_tag {};
struct const_cast_tag {};
struct dynamic_cast_tag {};
struct reinterpret_cast_tag {};
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_CAST_TAGS_HPP

View File

@ -0,0 +1,212 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#define BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail{
class file_wrapper
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_wrapper)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Default constructor.
//!Represents an empty file_wrapper.
file_wrapper();
//!Creates a file object with name "name" and mode "mode", with the access mode "mode"
//!If the file previously exists, throws an error.
file_wrapper(create_only_t, const char *name, mode_t mode, const permissions &perm = permissions())
{ this->priv_open_or_create(ipcdetail::DoCreate, name, mode, perm); }
//!Tries to create a file with name "name" and mode "mode", with the
//!access mode "mode". If the file previously exists, it tries to open it with mode "mode".
//!Otherwise throws an error.
file_wrapper(open_or_create_t, const char *name, mode_t mode, const permissions &perm = permissions())
{ this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode, perm); }
//!Tries to open a file with name "name", with the access mode "mode".
//!If the file does not previously exist, it throws an error.
file_wrapper(open_only_t, const char *name, mode_t mode)
{ this->priv_open_or_create(ipcdetail::DoOpen, name, mode, permissions()); }
//!Moves the ownership of "moved"'s file to *this.
//!After the call, "moved" does not represent any file.
//!Does not throw
file_wrapper(BOOST_RV_REF(file_wrapper) moved)
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file to *this.
//!After the call, "moved" does not represent any file.
//!Does not throw
file_wrapper &operator=(BOOST_RV_REF(file_wrapper) moved)
{
file_wrapper tmp(boost::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps to file_wrappers.
//!Does not throw
void swap(file_wrapper &other);
//!Erases a file from the system.
//!Returns false on error. Never throws
static bool remove(const char *name);
//!Sets the size of the file
void truncate(offset_t length);
//!Closes the
//!file
~file_wrapper();
//!Returns the name of the file
//!used in the constructor
const char *get_name() const;
//!Returns the name of the file
//!used in the constructor
bool get_size(offset_t &size) const;
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Get mapping handle
//!to use with mapped_region
mapping_handle_t get_mapping_handle() const;
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
//!Closes a previously opened file mapping. Never throws.
bool priv_open_or_create(ipcdetail::create_enum_t type, const char *filename, mode_t mode, const permissions &perm);
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
};
inline file_wrapper::file_wrapper()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
{}
inline file_wrapper::~file_wrapper()
{ this->priv_close(); }
inline const char *file_wrapper::get_name() const
{ return m_filename.c_str(); }
inline bool file_wrapper::get_size(offset_t &size) const
{ return get_file_size((file_handle_t)m_handle, size); }
inline void file_wrapper::swap(file_wrapper &other)
{
(simple_swap)(m_handle, other.m_handle);
(simple_swap)(m_mode, other.m_mode);
m_filename.swap(other.m_filename);
}
inline mapping_handle_t file_wrapper::get_mapping_handle() const
{ return mapping_handle_from_file_handle(m_handle); }
inline mode_t file_wrapper::get_mode() const
{ return m_mode; }
inline bool file_wrapper::priv_open_or_create
(ipcdetail::create_enum_t type,
const char *filename,
mode_t mode,
const permissions &perm = permissions())
{
m_filename = filename;
if(mode != read_only && mode != read_write){
error_info err(mode_error);
throw interprocess_exception(err);
}
//Open file existing native API to obtain the handle
switch(type){
case ipcdetail::DoOpen:
m_handle = open_existing_file(filename, mode);
break;
case ipcdetail::DoCreate:
m_handle = create_new_file(filename, mode, perm);
break;
case ipcdetail::DoOpenOrCreate:
m_handle = create_or_open_file(filename, mode, perm);
break;
default:
{
error_info err = other_error;
throw interprocess_exception(err);
}
}
//Check for error
if(m_handle == invalid_file()){
error_info err = system_error_code();
throw interprocess_exception(err);
}
m_mode = mode;
return true;
}
inline bool file_wrapper::remove(const char *filename)
{ return delete_file(filename); }
inline void file_wrapper::truncate(offset_t length)
{
if(!truncate_file(m_handle, length)){
error_info err(system_error_code());
throw interprocess_exception(err);
}
}
inline void file_wrapper::priv_close()
{
if(m_handle != invalid_file()){
close_file(m_handle);
m_handle = invalid_file();
}
}
} //namespace ipcdetail{
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_FILE_WRAPPER_HPP

View File

@ -0,0 +1,77 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP
#define BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
#include <typeinfo> //typeid
//!\file
//!Describes an abstract interface for placement construction and destruction.
namespace boost {
namespace interprocess {
namespace ipcdetail {
struct in_place_interface
{
in_place_interface(std::size_t alignm, std::size_t sz, const char *tname)
: alignment(alignm), size(sz), type_name(tname)
{}
std::size_t alignment;
std::size_t size;
const char *type_name;
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed) = 0;
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed) = 0;
virtual ~in_place_interface(){}
};
template<class T>
struct placement_destroy : public in_place_interface
{
placement_destroy()
: in_place_interface(::boost::container::container_detail::alignment_of<T>::value, sizeof(T), typeid(T).name())
{}
virtual void destroy_n(void *mem, std::size_t num, std::size_t &destroyed)
{
T* memory = static_cast<T*>(mem);
for(destroyed = 0; destroyed < num; ++destroyed)
(memory++)->~T();
}
virtual void construct_n(void *, std::size_t, std::size_t &) {}
private:
void destroy(void *mem)
{ static_cast<T*>(mem)->~T(); }
};
}
}
} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_IN_PLACE_INTERFACE_HPP

View File

@ -0,0 +1,775 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#define BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/segment_manager.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/detail/nothrow.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
//
#include <boost/core/no_exceptions_support.hpp>
//
#include <boost/intrusive/detail/minimal_pair_header.hpp>
#include <boost/assert.hpp>
//!\file
//!Describes a named shared memory allocation user class.
//!
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class BasicManagedMemoryImpl>
class create_open_func;
template<
class CharType,
class MemoryAlgorithm,
template<class IndexConfig> class IndexType
>
struct segment_manager_type
{
typedef segment_manager<CharType, MemoryAlgorithm, IndexType> type;
};
//!This class is designed to be a base class to classes that manage
//!creation of objects in a fixed size memory buffer. Apart
//!from allocating raw memory, the user can construct named objects. To
//!achieve this, this class uses the reserved space provided by the allocation
//!algorithm to place a named_allocator_algo, who takes care of name mappings.
//!The class can be customized with the char type used for object names
//!and the memory allocation algorithm to be used.*/
template < class CharType
, class MemoryAlgorithm
, template<class IndexConfig> class IndexType
, std::size_t Offset = 0
>
class basic_managed_memory_impl
{
//Non-copyable
basic_managed_memory_impl(const basic_managed_memory_impl &);
basic_managed_memory_impl &operator=(const basic_managed_memory_impl &);
template<class BasicManagedMemoryImpl>
friend class create_open_func;
public:
typedef typename segment_manager_type
<CharType, MemoryAlgorithm, IndexType>::type segment_manager;
typedef CharType char_type;
typedef MemoryAlgorithm memory_algorithm;
typedef typename MemoryAlgorithm::mutex_family mutex_family;
typedef CharType char_t;
typedef typename MemoryAlgorithm::size_type size_type;
typedef typename MemoryAlgorithm::difference_type difference_type;
typedef difference_type handle_t;
typedef typename segment_manager::
const_named_iterator const_named_iterator;
typedef typename segment_manager::
const_unique_iterator const_unique_iterator;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef typename
segment_manager::char_ptr_holder_t char_ptr_holder_t;
//Experimental. Don't use.
typedef typename segment_manager::multiallocation_chain multiallocation_chain;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
static const size_type PayloadPerAllocation = segment_manager::PayloadPerAllocation;
private:
typedef basic_managed_memory_impl
<CharType, MemoryAlgorithm, IndexType, Offset> self_t;
protected:
template<class ManagedMemory>
static bool grow(const char *filename, size_type extra_bytes)
{
typedef typename ManagedMemory::device_type device_type;
//Increase file size
try{
offset_t old_size;
{
device_type f(open_or_create, filename, read_write);
if(!f.get_size(old_size))
return false;
f.truncate(old_size + extra_bytes);
}
ManagedMemory managed_memory(open_only, filename);
//Grow always works
managed_memory.self_t::grow(extra_bytes);
}
catch(...){
return false;
}
return true;
}
template<class ManagedMemory>
static bool shrink_to_fit(const char *filename)
{
typedef typename ManagedMemory::device_type device_type;
size_type new_size;
try{
ManagedMemory managed_memory(open_only, filename);
managed_memory.get_size();
managed_memory.self_t::shrink_to_fit();
new_size = managed_memory.get_size();
}
catch(...){
return false;
}
//Decrease file size
{
device_type f(open_or_create, filename, read_write);
f.truncate(new_size);
}
return true;
}
//!Constructor. Allocates basic resources. Never throws.
basic_managed_memory_impl()
: mp_header(0){}
//!Destructor. Calls close. Never throws.
~basic_managed_memory_impl()
{ this->close_impl(); }
//!Places segment manager in the reserved space. This can throw.
bool create_impl (void *addr, size_type size)
{
if(mp_header) return false;
//Check if there is enough space
if(size < segment_manager::get_min_size())
return false;
//This function should not throw. The index construction can
//throw if constructor allocates memory. So we must catch it.
BOOST_TRY{
//Let's construct the allocator in memory
mp_header = ::new(addr, boost_container_new_t()) segment_manager(size);
}
BOOST_CATCH(...){
return false;
}
BOOST_CATCH_END
return true;
}
//!Connects to a segment manager in the reserved buffer. Never throws.
bool open_impl (void *addr, size_type)
{
if(mp_header) return false;
mp_header = static_cast<segment_manager*>(addr);
return true;
}
//!Frees resources. Never throws.
bool close_impl()
{
bool ret = mp_header != 0;
mp_header = 0;
return ret;
}
//!Frees resources and destroys common resources. Never throws.
bool destroy_impl()
{
if(mp_header == 0)
return false;
mp_header->~segment_manager();
this->close_impl();
return true;
}
//!
void grow(size_type extra_bytes)
{ mp_header->grow(extra_bytes); }
void shrink_to_fit()
{ mp_header->shrink_to_fit(); }
public:
//!Returns segment manager. Never throws.
segment_manager *get_segment_manager() const
{ return mp_header; }
//!Returns the base address of the memory in this process. Never throws.
void * get_address () const
{ return reinterpret_cast<char*>(mp_header) - Offset; }
//!Returns the size of memory segment. Never throws.
size_type get_size () const
{ return mp_header->get_size() + Offset; }
//!Returns the number of free bytes of the memory
//!segment
size_type get_free_memory() const
{ return mp_header->get_free_memory(); }
//!Returns the result of "all_memory_deallocated()" function
//!of the used memory algorithm
bool all_memory_deallocated()
{ return mp_header->all_memory_deallocated(); }
//!Returns the result of "check_sanity()" function
//!of the used memory algorithm
bool check_sanity()
{ return mp_header->check_sanity(); }
//!Writes to zero free memory (memory not yet allocated) of
//!the memory algorithm
void zero_free_memory()
{ mp_header->zero_free_memory(); }
//!Transforms an absolute address into an offset from base address.
//!The address must belong to the memory segment. Never throws.
handle_t get_handle_from_address (const void *ptr) const
{
return (handle_t)(reinterpret_cast<const char*>(ptr) -
reinterpret_cast<const char*>(this->get_address()));
}
//!Returns true if the address belongs to the managed memory segment
bool belongs_to_segment (const void *ptr) const
{
return ptr >= this->get_address() &&
ptr < (reinterpret_cast<const char*>(this->get_address()) + this->get_size());
}
//!Transforms previously obtained offset into an absolute address in the
//!process space of the current process. Never throws.*/
void * get_address_from_handle (handle_t offset) const
{ return reinterpret_cast<char*>(this->get_address()) + offset; }
//!Searches for nbytes of free memory in the segment, marks the
//!memory as used and return the pointer to the memory. If no
//!memory is available throws a boost::interprocess::bad_alloc exception
void* allocate (size_type nbytes)
{ return mp_header->allocate(nbytes); }
//!Searches for nbytes of free memory in the segment, marks the
//!memory as used and return the pointer to the memory. If no memory
//!is available returns 0. Never throws.
void* allocate (size_type nbytes, const std::nothrow_t &tag)
{ return mp_header->allocate(nbytes, tag); }
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
//!must be power of two. If no memory
//!is available returns 0. Never throws.
void * allocate_aligned (size_type nbytes, size_type alignment, const std::nothrow_t &tag)
{ return mp_header->allocate_aligned(nbytes, alignment, tag); }
template<class T>
T * allocation_command (boost::interprocess::allocation_type command, size_type limit_size,
size_type &prefer_in_recvd_out_size, T *&reuse)
{ return mp_header->allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); }
//!Allocates nbytes bytes aligned to "alignment" bytes. "alignment"
//!must be power of two. If no
//!memory is available throws a boost::interprocess::bad_alloc exception
void * allocate_aligned(size_type nbytes, size_type alignment)
{ return mp_header->allocate_aligned(nbytes, alignment); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Experimental. Don't use.
//!Allocates n_elements of elem_bytes bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ mp_header->allocate_many(elem_bytes, n_elements, chain); }
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); }
//!Allocates n_elements of elem_bytes bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_bytes, n_elements, chain); }
//!Allocates n_elements, each one of
//!element_lengths[i]*sizeof_element bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); }
//!Deallocates all elements contained in chain.
//!Never throws.
void deallocate_many(multiallocation_chain &chain)
{ mp_header->deallocate_many(chain); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Marks previously allocated memory as free. Never throws.
void deallocate (void *addr)
{ if (mp_header) mp_header->deallocate(addr); }
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{ return mp_header->template find<T>(name); }
//!Creates a named object or array in memory
//!
//!Allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name)
{ return mp_header->template construct<T>(name); }
//!Finds or creates a named object or array in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name)
{ return mp_header->template find_or_construct<T>(name); }
//!Creates a named object or array in memory
//!
//!Allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Returns 0 if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
construct(char_ptr_holder_t name, const std::nothrow_t &tag)
{ return mp_header->template construct<T>(name, tag); }
//!Finds or creates a named object or array in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs a T object or an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. If an array is being constructed all objects are
//!created using the same parameters given to this function.
//!
//!-> Returns 0 if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and if an
//!array was being constructed, destructors of created objects are called
//!before freeing the memory.
template <class T>
typename segment_manager::template construct_proxy<T>::type
find_or_construct(char_ptr_holder_t name, const std::nothrow_t &tag)
{ return mp_header->template find_or_construct<T>(name, tag); }
//!Creates a named array from iterators in memory
//!
//!Allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
construct_it(char_ptr_holder_t name)
{ return mp_header->template construct_it<T>(name); }
//!Finds or creates a named array from iterators in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> Throws boost::interprocess::bad_alloc if there is no available memory
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
find_or_construct_it(char_ptr_holder_t name)
{ return mp_header->template find_or_construct_it<T>(name); }
//!Creates a named array from iterators in memory
//!
//!Allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
construct_it(char_ptr_holder_t name, const std::nothrow_t &tag)
{ return mp_header->template construct_it<T>(name, tag); }
//!Finds or creates a named array from iterators in memory
//!
//!Tries to find an object with the given name in memory. If
//!found, returns the pointer to this pointer. If the object is not found,
//!allocates and constructs an array of T in memory,
//!associates this with the given name and returns a pointer to the
//!created object. Each element in the array is created using the
//!objects returned when dereferencing iterators as parameters
//!and incrementing all iterators for each element.
//!
//!-> If the name was previously used, returns 0.
//!
//!-> If there is no available memory, returns 0.
//!
//!-> If T's constructor throws, the function throws that exception.
//!
//!Memory is freed automatically if T's constructor throws and
//!destructors of created objects are called before freeing the memory.*/
template <class T>
typename segment_manager::template construct_iter_proxy<T>::type
find_or_construct_it(char_ptr_holder_t name, const std::nothrow_t &tag)
{ return mp_header->template find_or_construct_it<T>(name, tag); }
//!Calls a functor and guarantees that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the functor throws, this function throws.
template <class Func>
void atomic_func(Func &f)
{ mp_header->atomic_func(f); }
//!Tries to call a functor guaranteeing that no new construction, search or
//!destruction will be executed by any process while executing the object
//!function call. If the atomic function can't be immediatelly executed
//!because the internal mutex is already locked, returns false.
//!If the functor throws, this function throws.
template <class Func>
bool try_atomic_func(Func &f)
{ return mp_header->try_atomic_func(f); }
//!Destroys a named memory object or array.
//!
//!Finds the object with the given name, calls its destructors,
//!frees used memory and returns true.
//!
//!-> If the object is not found, it returns false.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object or array, the Standard
//!does not guarantee that dynamically allocated memory, will be released.
//!Also, when deleting arrays, the Standard doesn't require calling
//!destructors for the rest of the objects if for one of them the destructor
//!terminated with an exception.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!Destroying an array:
//!
//!When destroying an array, if a destructor throws, the rest of
//!destructors are called. If any of these throws, the exceptions are
//!ignored. The name association will be erased, memory will be freed and
//!the first exception will be thrown. This guarantees the unlocking of
//!mutexes and other resources.
//!
//!For all theses reasons, classes with throwing destructors are not
//!recommended.
template <class T>
bool destroy(const CharType *name)
{ return mp_header->template destroy<T>(name); }
//!Destroys the unique instance of type T
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!For all theses reasons, classes with throwing destructors are not
//!recommended for memory.
template <class T>
bool destroy(const unique_instance_t *const )
{ return mp_header->template destroy<T>(unique_instance); }
//!Destroys the object (named, unique, or anonymous)
//!
//!Calls the destructor, frees used memory and returns true.
//!
//!Exception Handling:
//!
//!When deleting a dynamically object, the Standard does not
//!guarantee that dynamically allocated memory will be released.
//!
//!Destroying an object:
//!
//!If the destructor throws, the memory will be freed and that exception
//!will be thrown.
//!
//!For all theses reasons, classes with throwing destructors are not
//!recommended for memory.
template <class T>
void destroy_ptr(const T *ptr)
{ mp_header->template destroy_ptr<T>(ptr); }
//!Returns the name of an object created with construct/find_or_construct
//!functions. If ptr points to an unique instance typeid(T).name() is returned.
template<class T>
static const char_type *get_instance_name(const T *ptr)
{ return segment_manager::get_instance_name(ptr); }
//!Returns is the type an object created with construct/find_or_construct
//!functions. Does not throw.
template<class T>
static instance_type get_instance_type(const T *ptr)
{ return segment_manager::get_instance_type(ptr); }
//!Returns the length of an object created with construct/find_or_construct
//!functions (1 if is a single element, >=1 if it's an array). Does not throw.
template<class T>
static size_type get_instance_length(const T *ptr)
{ return segment_manager::get_instance_length(ptr); }
//!Preallocates needed index resources to optimize the
//!creation of "num" named objects in the memory segment.
//!Can throw boost::interprocess::bad_alloc if there is no enough memory.
void reserve_named_objects(size_type num)
{ mp_header->reserve_named_objects(num); }
//!Preallocates needed index resources to optimize the
//!creation of "num" unique objects in the memory segment.
//!Can throw boost::interprocess::bad_alloc if there is no enough memory.
void reserve_unique_objects(size_type num)
{ mp_header->reserve_unique_objects(num); }
//!Calls shrink_to_fit in both named and unique object indexes
//to try to free unused memory from those indexes.
void shrink_to_fit_indexes()
{ mp_header->shrink_to_fit_indexes(); }
//!Returns the number of named objects stored
//!in the managed segment.
size_type get_num_named_objects()
{ return mp_header->get_num_named_objects(); }
//!Returns the number of unique objects stored
//!in the managed segment.
size_type get_num_unique_objects()
{ return mp_header->get_num_unique_objects(); }
//!Returns a constant iterator to the index storing the
//!named allocations. NOT thread-safe. Never throws.
const_named_iterator named_begin() const
{ return mp_header->named_begin(); }
//!Returns a constant iterator to the end of the index
//!storing the named allocations. NOT thread-safe. Never throws.
const_named_iterator named_end() const
{ return mp_header->named_end(); }
//!Returns a constant iterator to the index storing the
//!unique allocations. NOT thread-safe. Never throws.
const_unique_iterator unique_begin() const
{ return mp_header->unique_begin(); }
//!Returns a constant iterator to the end of the index
//!storing the unique allocations. NOT thread-safe. Never throws.
const_unique_iterator unique_end() const
{ return mp_header->unique_end(); }
//!This is the default allocator to allocate types T
//!from this managed segment
template<class T>
struct allocator
{
typedef typename segment_manager::template allocator<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename allocator<T>::type
get_allocator()
{ return mp_header->template get_allocator<T>(); }
//!This is the default deleter to delete types T
//!from this managed segment.
template<class T>
struct deleter
{
typedef typename segment_manager::template deleter<T>::type type;
};
//!Returns an instance of the default allocator for type T
//!initialized that allocates memory from this segment manager.
template<class T>
typename deleter<T>::type
get_deleter()
{ return mp_header->template get_deleter<T>(); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find_no_lock (char_ptr_holder_t name)
{ return mp_header->template find_no_lock<T>(name); }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
protected:
//!Swaps the segment manager's managed by this managed memory segment.
//!NOT thread-safe. Never throws.
void swap(basic_managed_memory_impl &other)
{ (simple_swap)(mp_header, other.mp_header); }
private:
segment_manager *mp_header;
};
template<class BasicManagedMemoryImpl>
class create_open_func
{
typedef typename BasicManagedMemoryImpl::size_type size_type;
public:
create_open_func(BasicManagedMemoryImpl * const frontend, create_enum_t type)
: m_frontend(frontend), m_type(type){}
bool operator()(void *addr, std::size_t size, bool created) const
{
if( ((m_type == DoOpen) && created) ||
((m_type == DoCreate) && !created) ||
//Check for overflow
size_type(-1) < size ){
return false;
}
else if(created){
return m_frontend->create_impl(addr, static_cast<size_type>(size));
}
else{
return m_frontend->open_impl (addr, static_cast<size_type>(size));
}
}
static std::size_t get_min_size()
{
const size_type sz = BasicManagedMemoryImpl::segment_manager::get_min_size();
if(sz > std::size_t(-1)){
//The minimum size is not representable by std::size_t
BOOST_ASSERT(false);
return std::size_t(-1);
}
else{
return static_cast<std::size_t>(sz);
}
}
private:
BasicManagedMemoryImpl *m_frontend;
create_enum_t m_type;
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_MANAGED_MEMORY_IMPL_HPP

View File

@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Stephen Cleary 2000.
// (C) Copyright Ion Gaztanaga 2007-2012.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
// This file is a slightly modified file from Boost.Pool
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
#define BOOST_INTERPROCESS_DETAIL_MATH_FUNCTIONS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <climits>
#include <boost/static_assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
// Greatest common divisor and least common multiple
//
// gcd is an algorithm that calculates the greatest common divisor of two
// integers, using Euclid's algorithm.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
inline Integer gcd(Integer A, Integer B)
{
do
{
const Integer tmp(B);
B = A % B;
A = tmp;
} while (B != 0);
return A;
}
//
// lcm is an algorithm that calculates the least common multiple of two
// integers.
//
// Pre: A > 0 && B > 0
// Recommended: A > B
template <typename Integer>
inline Integer lcm(const Integer & A, const Integer & B)
{
Integer ret = A;
ret /= gcd(A, B);
ret *= B;
return ret;
}
template <typename Integer>
inline Integer log2_ceil(const Integer & A)
{
Integer i = 0;
Integer power_of_2 = 1;
while(power_of_2 < A){
power_of_2 <<= 1;
++i;
}
return i;
}
template <typename Integer>
inline Integer upper_power_of_2(const Integer & A)
{
Integer power_of_2 = 1;
while(power_of_2 < A){
power_of_2 <<= 1;
}
return power_of_2;
}
//This function uses binary search to discover the
//highest set bit of the integer
inline std::size_t floor_log2 (std::size_t x)
{
const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT;
const bool Size_t_Bits_Power_2= !(Bits & (Bits-1));
BOOST_STATIC_ASSERT(((Size_t_Bits_Power_2)== true));
std::size_t n = x;
std::size_t log2 = 0;
for(std::size_t shift = Bits >> 1; shift; shift >>= 1){
std::size_t tmp = n >> shift;
if (tmp)
log2 += shift, n = tmp;
}
return log2;
}
} // namespace ipcdetail
} // namespace interprocess
} // namespace boost
#endif

View File

@ -0,0 +1,316 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP
#define BOOST_INTERPROCESS_NAMED_PROXY_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess/detail
#include <boost/interprocess/detail/in_place_interface.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/move/utility_core.hpp>
#ifndef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/move/detail/fwd_macros.hpp>
#else
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/container/detail/placement_new.hpp>
#include <cstddef>
//!\file
//!Describes a proxy class that implements named allocation syntax.
namespace boost {
namespace interprocess {
namespace ipcdetail {
#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
template<class T, bool is_iterator, class ...Args>
struct CtorArgN : public placement_destroy<T>
{
typedef bool_<is_iterator> IsIterator;
typedef CtorArgN<T, is_iterator, Args...> self_t;
typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t;
self_t& operator++()
{
this->do_increment(IsIterator(), index_tuple_t());
return *this;
}
self_t operator++(int) { return ++*this; *this; }
CtorArgN(Args && ...args)
: args_(args...)
{}
virtual void construct_n(void *mem
, std::size_t num
, std::size_t &constructed)
{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed){
this->construct(memory++, IsIterator(), index_tuple_t());
this->do_increment(IsIterator(), index_tuple_t());
}
}
private:
template<std::size_t ...IdxPack>
void construct(void *mem, true_, const index_tuple<IdxPack...>&)
{ ::new((void*)mem, boost_container_new_t())T(*boost::forward<Args>(get<IdxPack>(args_))...); }
template<std::size_t ...IdxPack>
void construct(void *mem, false_, const index_tuple<IdxPack...>&)
{ ::new((void*)mem, boost_container_new_t())T(boost::forward<Args>(get<IdxPack>(args_))...); }
template<std::size_t ...IdxPack>
void do_increment(true_, const index_tuple<IdxPack...>&)
{
this->expansion_helper(++get<IdxPack>(args_)...);
}
template<class ...ExpansionArgs>
void expansion_helper(ExpansionArgs &&...)
{}
template<std::size_t ...IdxPack>
void do_increment(false_, const index_tuple<IdxPack...>&)
{}
tuple<Args&...> args_;
};
//!Describes a proxy class that implements named
//!allocation syntax.
template
< class SegmentManager //segment manager to construct the object
, class T //type of object to build
, bool is_iterator //passing parameters are normal object or iterators?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
template<class ...Args>
T *operator()(Args &&...args) const
{
CtorArgN<T, is_iterator, Args...> &&ctor_obj = CtorArgN<T, is_iterator, Args...>
(boost::forward<Args>(args)...);
return mp_mngr->template
generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);
}
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
#else //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2):
//
// template<class T, bool is_iterator, class P1, class P2>
// struct Ctor2Arg
// : public placement_destroy<T>
// {
// typedef bool_<is_iterator> IsIterator;
// typedef Ctor2Arg self_t;
//
// void do_increment(false_)
// { ++m_p1; ++m_p2; }
//
// void do_increment(true_){}
//
// self_t& operator++()
// {
// this->do_increment(IsIterator());
// return *this;
// }
//
// self_t operator++(int) { return ++*this; *this; }
//
// Ctor2Arg(const P1 &p1, const P2 &p2)
// : p1((P1 &)p_1), p2((P2 &)p_2) {}
//
// void construct(void *mem)
// { new((void*)object)T(m_p1, m_p2); }
//
// virtual void construct_n(void *mem
// , std::size_t num
// , std::size_t &constructed)
// {
// T* memory = static_cast<T*>(mem);
// for(constructed = 0; constructed < num; ++constructed){
// this->construct(memory++, IsIterator());
// this->do_increment(IsIterator());
// }
// }
//
// private:
// void construct(void *mem, true_)
// { new((void*)mem)T(*m_p1, *m_p2); }
//
// void construct(void *mem, false_)
// { new((void*)mem)T(m_p1, m_p2); }
//
// P1 &m_p1; P2 &m_p2;
// };
////////////////////////////////////////////////////////////////
#define BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN(N)\
\
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
struct CtorArg##N : placement_destroy<T>\
{\
typedef CtorArg##N self_t;\
\
CtorArg##N ( BOOST_MOVE_UREF##N )\
BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N{}\
\
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)\
{\
T* memory = static_cast<T*>(mem);\
for(constructed = 0; constructed < num; ++constructed){\
::new((void*)memory++) T ( BOOST_MOVE_MFWD##N );\
}\
}\
\
private:\
BOOST_MOVE_MREF##N\
};\
//!
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN)
#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORARGN
#define BOOST_INTERPROCESS_NAMED_PROXY_CTORITN(N)\
\
template<class T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \
struct CtorIt##N : public placement_destroy<T>\
{\
typedef CtorIt##N self_t;\
\
self_t& operator++()\
{ BOOST_MOVE_MINC##N; return *this; }\
\
self_t operator++(int) { return ++*this; *this; }\
\
CtorIt##N ( BOOST_MOVE_VAL##N )\
BOOST_MOVE_COLON##N BOOST_MOVE_VAL_INIT##N{}\
\
virtual void construct_n(void *mem, std::size_t num, std::size_t &constructed)\
{\
T* memory = static_cast<T*>(mem);\
for(constructed = 0; constructed < num; ++constructed){\
::new((void*)memory++) T( BOOST_MOVE_MITFWD##N );\
++(*this);\
}\
}\
\
private:\
BOOST_MOVE_MEMB##N\
};\
//!
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CTORITN)
#undef BOOST_INTERPROCESS_NAMED_PROXY_CTORITN
//!Describes a proxy class that implements named
//!allocation syntax.
template
< class SegmentManager //segment manager to construct the object
, class T //type of object to build
, bool is_iterator //passing parameters are normal object or iterators?
>
class named_proxy
{
typedef typename SegmentManager::char_type char_type;
const char_type * mp_name;
SegmentManager * mp_mngr;
mutable std::size_t m_num;
const bool m_find;
const bool m_dothrow;
public:
named_proxy(SegmentManager *mngr, const char_type *name, bool find, bool dothrow)
: mp_name(name), mp_mngr(mngr), m_num(1)
, m_find(find), m_dothrow(dothrow)
{}
#define BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR(N)\
\
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
T *operator()( BOOST_MOVE_UREF##N ) const\
{\
typedef typename if_c<is_iterator \
, CtorIt##N<T BOOST_MOVE_I##N BOOST_MOVE_TARG##N> \
, CtorArg##N<T BOOST_MOVE_I##N BOOST_MOVE_TARG##N> \
>::type ctor_obj_t;\
ctor_obj_t ctor_obj = ctor_obj_t( BOOST_MOVE_FWD##N );\
return mp_mngr->template generic_construct<T>(mp_name, m_num, m_find, m_dothrow, ctor_obj);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR)
#undef BOOST_INTERPROCESS_NAMED_PROXY_CALL_OPERATOR
////////////////////////////////////////////////////////////////////////
// What the macro should generate (n == 2)
////////////////////////////////////////////////////////////////////////
//
// template <class P1, class P2>
// T *operator()(P1 &p1, P2 &p2) const
// {
// typedef CtorArg2
// <T, is_iterator, P1, P2>
// ctor_obj_t;
// ctor_obj_t ctor_obj(p1, p2);
//
// return mp_mngr->template generic_construct<T>
// (mp_name, m_num, m_find, m_dothrow, ctor_obj);
// }
//
//////////////////////////////////////////////////////////////////////////
//This operator allows --> named_new("Name")[3]; <-- syntax
const named_proxy &operator[](std::size_t num) const
{ m_num *= num; return *this; }
};
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_NAMED_PROXY_HPP

View File

@ -0,0 +1,42 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP
#define BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace std { //no namespace versioning in clang+libc++
struct nothrow_t;
} //namespace std {
namespace boost{ namespace interprocess {
template <int Dummy = 0>
struct nothrow
{
static const std::nothrow_t &get() { return *pnothrow; }
static std::nothrow_t *pnothrow;
};
template <int Dummy>
std::nothrow_t *nothrow<Dummy>::pnothrow =
reinterpret_cast<std::nothrow_t *>(0x1234); //Avoid sanitizer warnings on references to null
}} //namespace boost{ namespace interprocess {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_NOTHROW_HPP

View File

@ -0,0 +1,518 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
#define BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess
#include <boost/interprocess/exceptions.hpp>
// interprocess/detail
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/in_place_interface.hpp>
// container/detail
#include <boost/container/detail/type_traits.hpp> //alignment_of
#include <boost/container/detail/minimal_char_traits_header.hpp>
// intrusive
#include <boost/intrusive/pointer_traits.hpp>
// move/detail
#include <boost/move/detail/type_traits.hpp> //make_unsigned
// other boost
#include <boost/assert.hpp> //BOOST_ASSERT
#include <boost/core/no_exceptions_support.hpp>
// std
#include <cstddef> //std::size_t
//!\file
//!Describes the object placed in a memory segment that provides
//!named object allocation capabilities.
namespace boost{
namespace interprocess{
template<class MemoryManager>
class segment_manager_base;
//!An integer that describes the type of the
//!instance constructed in memory
enum instance_type { anonymous_type, named_type, unique_type, max_allocation_type };
namespace ipcdetail{
template<class MemoryAlgorithm>
class mem_algo_deallocator
{
void * m_ptr;
MemoryAlgorithm & m_algo;
public:
mem_algo_deallocator(void *ptr, MemoryAlgorithm &algo)
: m_ptr(ptr), m_algo(algo)
{}
void release()
{ m_ptr = 0; }
~mem_algo_deallocator()
{ if(m_ptr) m_algo.deallocate(m_ptr); }
};
template<class size_type>
struct block_header
{
size_type m_value_bytes;
unsigned short m_num_char;
unsigned char m_value_alignment;
unsigned char m_alloc_type_sizeof_char;
block_header(size_type val_bytes
,size_type val_alignment
,unsigned char al_type
,std::size_t szof_char
,std::size_t num_char
)
: m_value_bytes(val_bytes)
, m_num_char((unsigned short)num_char)
, m_value_alignment((unsigned char)val_alignment)
, m_alloc_type_sizeof_char( (al_type << 5u) | ((unsigned char)szof_char & 0x1F) )
{};
template<class T>
block_header &operator= (const T& )
{ return *this; }
size_type total_size() const
{
if(alloc_type() != anonymous_type){
return name_offset() + (m_num_char+1)*sizeof_char();
}
else{
return this->value_offset() + m_value_bytes;
}
}
size_type value_bytes() const
{ return m_value_bytes; }
template<class Header>
size_type total_size_with_header() const
{
return get_rounded_size
( size_type(sizeof(Header))
, size_type(::boost::container::container_detail::alignment_of<block_header<size_type> >::value))
+ total_size();
}
unsigned char alloc_type() const
{ return (m_alloc_type_sizeof_char >> 5u)&(unsigned char)0x7; }
unsigned char sizeof_char() const
{ return m_alloc_type_sizeof_char & (unsigned char)0x1F; }
template<class CharType>
CharType *name() const
{
return const_cast<CharType*>(reinterpret_cast<const CharType*>
(reinterpret_cast<const char*>(this) + name_offset()));
}
unsigned short name_length() const
{ return m_num_char; }
size_type name_offset() const
{
return this->value_offset() + get_rounded_size(size_type(m_value_bytes), size_type(sizeof_char()));
}
void *value() const
{
return const_cast<char*>((reinterpret_cast<const char*>(this) + this->value_offset()));
}
size_type value_offset() const
{
return get_rounded_size(size_type(sizeof(block_header<size_type>)), size_type(m_value_alignment));
}
template<class CharType>
bool less_comp(const block_header<size_type> &b) const
{
return m_num_char < b.m_num_char ||
(m_num_char < b.m_num_char &&
std::char_traits<CharType>::compare(name<CharType>(), b.name<CharType>(), m_num_char) < 0);
}
template<class CharType>
bool equal_comp(const block_header<size_type> &b) const
{
return m_num_char == b.m_num_char &&
std::char_traits<CharType>::compare(name<CharType>(), b.name<CharType>(), m_num_char) == 0;
}
template<class T>
static block_header<size_type> *block_header_from_value(T *value)
{ return block_header_from_value(value, sizeof(T), ::boost::container::container_detail::alignment_of<T>::value); }
static block_header<size_type> *block_header_from_value(const void *value, std::size_t sz, std::size_t algn)
{
block_header * hdr =
const_cast<block_header*>
(reinterpret_cast<const block_header*>(reinterpret_cast<const char*>(value) -
get_rounded_size(sizeof(block_header), algn)));
(void)sz;
//Some sanity checks
BOOST_ASSERT(hdr->m_value_alignment == algn);
BOOST_ASSERT(hdr->m_value_bytes % sz == 0);
return hdr;
}
template<class Header>
static block_header<size_type> *from_first_header(Header *header)
{
block_header<size_type> * hdr =
reinterpret_cast<block_header<size_type>*>(reinterpret_cast<char*>(header) +
get_rounded_size( size_type(sizeof(Header))
, size_type(::boost::container::container_detail::alignment_of<block_header<size_type> >::value)));
//Some sanity checks
return hdr;
}
template<class Header>
static Header *to_first_header(block_header<size_type> *bheader)
{
Header * hdr =
reinterpret_cast<Header*>(reinterpret_cast<char*>(bheader) -
get_rounded_size( size_type(sizeof(Header))
, size_type(::boost::container::container_detail::alignment_of<block_header<size_type> >::value)));
//Some sanity checks
return hdr;
}
};
inline void array_construct(void *mem, std::size_t num, in_place_interface &table)
{
//Try constructors
std::size_t constructed = 0;
BOOST_TRY{
table.construct_n(mem, num, constructed);
}
//If there is an exception call destructors and erase index node
BOOST_CATCH(...){
std::size_t destroyed = 0;
table.destroy_n(mem, constructed, destroyed);
BOOST_RETHROW
}
BOOST_CATCH_END
}
template<class CharT>
struct intrusive_compare_key
{
typedef CharT char_type;
intrusive_compare_key(const CharT *str, std::size_t len)
: mp_str(str), m_len(len)
{}
const CharT * mp_str;
std::size_t m_len;
};
//!This struct indicates an anonymous object creation
//!allocation
template<instance_type type>
class instance_t
{
instance_t(){}
};
template<class T>
struct char_if_void
{
typedef T type;
};
template<>
struct char_if_void<void>
{
typedef char type;
};
typedef instance_t<anonymous_type> anonymous_instance_t;
typedef instance_t<unique_type> unique_instance_t;
template<class Hook, class CharType, class SizeType>
struct intrusive_value_type_impl
: public Hook
{
private:
//Non-copyable
intrusive_value_type_impl(const intrusive_value_type_impl &);
intrusive_value_type_impl& operator=(const intrusive_value_type_impl &);
public:
typedef CharType char_type;
typedef SizeType size_type;
intrusive_value_type_impl(){}
enum { BlockHdrAlignment = ::boost::container::container_detail::alignment_of<block_header<size_type> >::value };
block_header<size_type> *get_block_header() const
{
return const_cast<block_header<size_type>*>
(reinterpret_cast<const block_header<size_type> *>(reinterpret_cast<const char*>(this) +
get_rounded_size(size_type(sizeof(*this)), size_type(BlockHdrAlignment))));
}
bool operator <(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
{ return (this->get_block_header())->template less_comp<CharType>(*other.get_block_header()); }
bool operator ==(const intrusive_value_type_impl<Hook, CharType, SizeType> & other) const
{ return (this->get_block_header())->template equal_comp<CharType>(*other.get_block_header()); }
static intrusive_value_type_impl *get_intrusive_value_type(block_header<size_type> *hdr)
{
return reinterpret_cast<intrusive_value_type_impl *>(reinterpret_cast<char*>(hdr) -
get_rounded_size(size_type(sizeof(intrusive_value_type_impl)), size_type(BlockHdrAlignment)));
}
CharType *name() const
{ return get_block_header()->template name<CharType>(); }
unsigned short name_length() const
{ return get_block_header()->name_length(); }
void *value() const
{ return get_block_header()->value(); }
};
template<class CharType>
class char_ptr_holder
{
public:
char_ptr_holder(const CharType *name)
: m_name(name)
{}
char_ptr_holder(const anonymous_instance_t *)
: m_name(static_cast<CharType*>(0))
{}
char_ptr_holder(const unique_instance_t *)
: m_name(reinterpret_cast<CharType*>(-1))
{}
operator const CharType *()
{ return m_name; }
const CharType *get() const
{ return m_name; }
bool is_unique() const
{ return m_name == reinterpret_cast<CharType*>(-1); }
bool is_anonymous() const
{ return m_name == static_cast<CharType*>(0); }
private:
const CharType *m_name;
};
//!The key of the the named allocation information index. Stores an offset pointer
//!to a null terminated string and the length of the string to speed up sorting
template<class CharT, class VoidPointer>
struct index_key
{
typedef typename boost::intrusive::
pointer_traits<VoidPointer>::template
rebind_pointer<const CharT>::type const_char_ptr_t;
typedef CharT char_type;
typedef typename boost::intrusive::pointer_traits<const_char_ptr_t>::difference_type difference_type;
typedef typename boost::move_detail::make_unsigned<difference_type>::type size_type;
private:
//Offset pointer to the object's name
const_char_ptr_t mp_str;
//Length of the name buffer (null NOT included)
size_type m_len;
public:
//!Constructor of the key
index_key (const char_type *nm, size_type length)
: mp_str(nm), m_len(length)
{}
//!Less than function for index ordering
bool operator < (const index_key & right) const
{
return (m_len < right.m_len) ||
(m_len == right.m_len &&
std::char_traits<char_type>::compare
(to_raw_pointer(mp_str),to_raw_pointer(right.mp_str), m_len) < 0);
}
//!Equal to function for index ordering
bool operator == (const index_key & right) const
{
return m_len == right.m_len &&
std::char_traits<char_type>::compare
(to_raw_pointer(mp_str), to_raw_pointer(right.mp_str), m_len) == 0;
}
void name(const CharT *nm)
{ mp_str = nm; }
void name_length(size_type len)
{ m_len = len; }
const CharT *name() const
{ return to_raw_pointer(mp_str); }
size_type name_length() const
{ return m_len; }
};
//!The index_data stores a pointer to a buffer and the element count needed
//!to know how many destructors must be called when calling destroy
template<class VoidPointer>
struct index_data
{
typedef VoidPointer void_pointer;
void_pointer m_ptr;
explicit index_data(void *ptr) : m_ptr(ptr){}
void *value() const
{ return static_cast<void*>(to_raw_pointer(m_ptr)); }
};
template<class MemoryAlgorithm>
struct segment_manager_base_type
{ typedef segment_manager_base<MemoryAlgorithm> type; };
template<class CharT, class MemoryAlgorithm>
struct index_config
{
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef CharT char_type;
typedef index_key<CharT, void_pointer> key_type;
typedef index_data<void_pointer> mapped_type;
typedef typename segment_manager_base_type
<MemoryAlgorithm>::type segment_manager_base;
template<class HeaderBase>
struct intrusive_value_type
{ typedef intrusive_value_type_impl<HeaderBase, CharT, typename segment_manager_base::size_type> type; };
typedef intrusive_compare_key<CharT> intrusive_compare_key_type;
};
template<class Iterator, bool intrusive>
class segment_manager_iterator_value_adaptor
{
typedef typename Iterator::value_type iterator_val_t;
typedef typename iterator_val_t::char_type char_type;
public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
: m_val(&val)
{}
const char_type *name() const
{ return m_val->name(); }
unsigned short name_length() const
{ return m_val->name_length(); }
const void *value() const
{ return m_val->value(); }
const typename Iterator::value_type *m_val;
};
template<class Iterator>
class segment_manager_iterator_value_adaptor<Iterator, false>
{
typedef typename Iterator::value_type iterator_val_t;
typedef typename iterator_val_t::first_type first_type;
typedef typename iterator_val_t::second_type second_type;
typedef typename first_type::char_type char_type;
typedef typename first_type::size_type size_type;
public:
segment_manager_iterator_value_adaptor(const typename Iterator::value_type &val)
: m_val(&val)
{}
const char_type *name() const
{ return m_val->first.name(); }
size_type name_length() const
{ return m_val->first.name_length(); }
const void *value() const
{
return reinterpret_cast<block_header<size_type>*>
(to_raw_pointer(m_val->second.m_ptr))->value();
}
const typename Iterator::value_type *m_val;
};
template<class Iterator, bool intrusive>
struct segment_manager_iterator_transform
{
typedef segment_manager_iterator_value_adaptor<Iterator, intrusive> result_type;
template <class T> result_type operator()(const T &arg) const
{ return result_type(arg); }
};
} //namespace ipcdetail {
//These pointers are the ones the user will use to
//indicate previous allocation types
static const ipcdetail::anonymous_instance_t * anonymous_instance = 0;
static const ipcdetail::unique_instance_t * unique_instance = 0;
namespace ipcdetail_really_deep_namespace {
//Otherwise, gcc issues a warning of previously defined
//anonymous_instance and unique_instance
struct dummy
{
dummy()
{
(void)anonymous_instance;
(void)unique_instance;
}
};
} //detail_really_deep_namespace
}} //namespace boost { namespace interprocess
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_SEGMENT_MANAGER_BASE_HPP

View File

@ -0,0 +1,200 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2015.
// (C) Copyright Gennaro Prota 2003 - 2004.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP
#define BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess
#include <boost/interprocess/interprocess_fwd.hpp>
// interprocess/detail
#include <boost/interprocess/detail/type_traits.hpp>
// move/detail
#include <boost/container/detail/iterator.hpp>
namespace boost {
namespace interprocess {
template <class PseudoReference>
struct operator_arrow_proxy
{
operator_arrow_proxy(const PseudoReference &px)
: m_value(px)
{}
PseudoReference* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable PseudoReference m_value;
};
template <class T>
struct operator_arrow_proxy<T&>
{
operator_arrow_proxy(T &px)
: m_value(px)
{}
T* operator->() const { return const_cast<T*>(&m_value); }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
T &m_value;
};
template <class Iterator, class UnaryFunction>
class transform_iterator
: public UnaryFunction
{
public:
typedef typename ::boost::container::iterator_traits<Iterator>::iterator_category iterator_category;
typedef typename ipcdetail::remove_reference<typename UnaryFunction::result_type>::type value_type;
typedef typename ::boost::container::iterator_traits<Iterator>::difference_type difference_type;
typedef operator_arrow_proxy<typename UnaryFunction::result_type> pointer;
typedef typename UnaryFunction::result_type reference;
explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
: UnaryFunction(f), m_it(it)
{}
explicit transform_iterator()
: UnaryFunction(), m_it()
{}
//Constructors
transform_iterator& operator++()
{ increment(); return *this; }
transform_iterator operator++(int)
{
transform_iterator result (*this);
increment();
return result;
}
transform_iterator& operator--()
{ decrement(); return *this; }
transform_iterator operator--(int)
{
transform_iterator result (*this);
decrement();
return result;
}
friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
{ return i.equal(i2); }
friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i == i2); }
friend bool operator< (const transform_iterator& i, const transform_iterator& i2)
{ return i < i2; }
friend bool operator> (const transform_iterator& i, const transform_iterator& i2)
{ return i2 < i; }
friend bool operator<= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i > i2); }
friend bool operator>= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i < i2); }
friend difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(difference_type off)
{ this->advance(off); return *this; }
transform_iterator operator+(difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
friend transform_iterator operator+(difference_type off, const transform_iterator& right)
{ return right + off; }
transform_iterator& operator-=(difference_type off)
{ this->advance(-off); return *this; }
transform_iterator operator-(difference_type off) const
{ return *this + (-off); }
typename UnaryFunction::result_type operator*() const
{ return dereference(); }
typename UnaryFunction::result_type operator[](difference_type off) const
{ return UnaryFunction::operator()(m_it[off]); }
operator_arrow_proxy<typename UnaryFunction::result_type>
operator->() const
{ return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
Iterator & base()
{ return m_it; }
const Iterator & base() const
{ return m_it; }
private:
Iterator m_it;
void increment()
{ ++m_it; }
void decrement()
{ --m_it; }
bool equal(const transform_iterator &other) const
{ return m_it == other.m_it; }
bool less(const transform_iterator &other) const
{ return other.m_it < m_it; }
typename UnaryFunction::result_type dereference() const
{ return UnaryFunction::operator()(*m_it); }
void advance(difference_type n)
{ ::boost::container::iterator_advance(m_it, n); }
difference_type distance_to(const transform_iterator &other)const
{ return ::boost::container::iterator_distance(other.m_it, m_it); }
};
template <class Iterator, class UnaryFunc>
transform_iterator<Iterator, UnaryFunc>
make_transform_iterator(Iterator it, UnaryFunc fun)
{
return transform_iterator<Iterator, UnaryFunc>(it, fun);
}
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_TRANSFORM_ITERATORS_HPP

View File

@ -0,0 +1,35 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#define BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/container/detail/variadic_templates_tools.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
using boost::container::container_detail::tuple;
using boost::container::container_detail::build_number_seq;
using boost::container::container_detail::index_tuple;
using boost::container::container_detail::get;
}}} //namespace boost { namespace interprocess { namespace ipcdetail {
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_VARIADIC_TEMPLATES_TOOLS_HPP

View File

@ -0,0 +1,199 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_FILE_MAPPING_HPP
#define BOOST_INTERPROCESS_FILE_MAPPING_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#if !defined(BOOST_INTERPROCESS_MAPPED_FILES)
#error "Boost.Interprocess: This platform does not support memory mapped files!"
#endif
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/detail/simple_swap.hpp>
#include <boost/move/utility_core.hpp>
#include <string> //std::string
//!\file
//!Describes file_mapping and mapped region classes
namespace boost {
namespace interprocess {
//!A class that wraps a file-mapping that can be used to
//!create mapped regions from the mapped files
class file_mapping
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
BOOST_MOVABLE_BUT_NOT_COPYABLE(file_mapping)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructs an empty file mapping.
//!Does not throw
file_mapping();
//!Opens a file mapping of file "filename", starting in offset
//!"file_offset", and the mapping's size will be "size". The mapping
//!can be opened for read-only "read_only" or read-write "read_write"
//!modes. Throws interprocess_exception on error.
file_mapping(const char *filename, mode_t mode);
//!Moves the ownership of "moved"'s file mapping object to *this.
//!After the call, "moved" does not represent any file mapping object.
//!Does not throw
file_mapping(BOOST_RV_REF(file_mapping) moved)
: m_handle(file_handle_t(ipcdetail::invalid_file()))
, m_mode(read_only)
{ this->swap(moved); }
//!Moves the ownership of "moved"'s file mapping to *this.
//!After the call, "moved" does not represent any file mapping.
//!Does not throw
file_mapping &operator=(BOOST_RV_REF(file_mapping) moved)
{
file_mapping tmp(boost::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps to file_mappings.
//!Does not throw.
void swap(file_mapping &other);
//!Returns access mode
//!used in the constructor
mode_t get_mode() const;
//!Obtains the mapping handle
//!to be used with mapped_region
mapping_handle_t get_mapping_handle() const;
//!Destroys the file mapping. All mapped regions created from this are still
//!valid. Does not throw
~file_mapping();
//!Returns the name of the file
//!used in the constructor.
const char *get_name() const;
//!Removes the file named "filename" even if it's been memory mapped.
//!Returns true on success.
//!The function might fail in some operating systems if the file is
//!being used other processes and no deletion permission was shared.
static bool remove(const char *filename);
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
//!Closes a previously opened file mapping. Never throws.
void priv_close();
file_handle_t m_handle;
mode_t m_mode;
std::string m_filename;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
inline file_mapping::file_mapping()
: m_handle(file_handle_t(ipcdetail::invalid_file()))
, m_mode(read_only)
{}
inline file_mapping::~file_mapping()
{ this->priv_close(); }
inline const char *file_mapping::get_name() const
{ return m_filename.c_str(); }
inline void file_mapping::swap(file_mapping &other)
{
(simple_swap)(m_handle, other.m_handle);
(simple_swap)(m_mode, other.m_mode);
m_filename.swap(other.m_filename);
}
inline mapping_handle_t file_mapping::get_mapping_handle() const
{ return ipcdetail::mapping_handle_from_file_handle(m_handle); }
inline mode_t file_mapping::get_mode() const
{ return m_mode; }
inline file_mapping::file_mapping
(const char *filename, mode_t mode)
: m_filename(filename)
{
//Check accesses
if (mode != read_write && mode != read_only){
error_info err = other_error;
throw interprocess_exception(err);
}
//Open file
m_handle = ipcdetail::open_existing_file(filename, mode);
//Check for error
if(m_handle == ipcdetail::invalid_file()){
error_info err = system_error_code();
this->priv_close();
throw interprocess_exception(err);
}
m_mode = mode;
}
inline bool file_mapping::remove(const char *filename)
{ return ipcdetail::delete_file(filename); }
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
inline void file_mapping::priv_close()
{
if(m_handle != ipcdetail::invalid_file()){
ipcdetail::close_file(m_handle);
m_handle = ipcdetail::invalid_file();
}
}
//!A class that stores the name of a file
//!and tries to remove it in its destructor
//!Useful to remove temporary files in the presence
//!of exceptions
class remove_file_on_destroy
{
const char * m_name;
public:
remove_file_on_destroy(const char *name)
: m_name(name)
{}
~remove_file_on_destroy()
{ ipcdetail::delete_file(m_name); }
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_FILE_MAPPING_HPP

View File

@ -0,0 +1,158 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP
#define BOOST_INTERPROCESS_ISET_INDEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/intrusive/detail/minimal_pair_header.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/intrusive/detail/minimal_pair_header.hpp> //std::pair
#include <boost/intrusive/detail/minimal_less_equal_header.hpp> //std::less
#include <boost/container/detail/minimal_char_traits_header.hpp> //std::char_traits
#include <boost/intrusive/set.hpp>
//!\file
//!Describes index adaptor of boost::intrusive::set container, to use it
//!as name/shared memory index
namespace boost {
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct iset_index_aux
{
typedef typename
MapConfig::segment_manager_base segment_manager_base;
typedef typename
segment_manager_base::void_pointer void_pointer;
typedef typename bi::make_set_base_hook
< bi::void_pointer<void_pointer>
, bi::optimize_size<true>
>::type derivation_hook;
typedef typename MapConfig::template
intrusive_value_type<derivation_hook>::type value_type;
typedef std::less<value_type> value_compare;
typedef typename bi::make_set
< value_type
, bi::base_hook<derivation_hook>
>::type index_t;
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Index type based in boost::intrusive::set.
//!Just derives from boost::intrusive::set
//!and defines the interface needed by managed memory segments*/
template <class MapConfig>
class iset_index
//Derive class from map specialization
: public iset_index_aux<MapConfig>::index_t
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef iset_index_aux<MapConfig> index_aux;
typedef typename index_aux::index_t index_type;
typedef typename MapConfig::
intrusive_compare_key_type intrusive_compare_key_type;
typedef typename MapConfig::char_type char_type;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef typename index_type::iterator iterator;
typedef typename index_type::const_iterator const_iterator;
typedef typename index_type::insert_commit_data insert_commit_data;
typedef typename index_type::value_type value_type;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
struct intrusive_key_value_less
{
bool operator()(const intrusive_compare_key_type &i, const value_type &b) const
{
std::size_t blen = b.name_length();
return (i.m_len < blen) ||
(i.m_len == blen &&
std::char_traits<char_type>::compare
(i.mp_str, b.name(), i.m_len) < 0);
}
bool operator()(const value_type &b, const intrusive_compare_key_type &i) const
{
std::size_t blen = b.name_length();
return (blen < i.m_len) ||
(blen == i.m_len &&
std::char_traits<char_type>::compare
(b.name(), i.mp_str, i.m_len) < 0);
}
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor. Takes a pointer to the
//!segment manager. Can throw
iset_index(typename MapConfig::segment_manager_base *)
: index_type(/*typename index_aux::value_compare()*/)
{}
//!This reserves memory to optimize the insertion of n
//!elements in the index
void reserve(typename MapConfig::segment_manager_base::size_type)
{ /*Does nothing, map has not reserve or rehash*/ }
//!This frees all unnecessary memory
void shrink_to_fit()
{ /*Does nothing, this intrusive index does not allocate memory;*/ }
iterator find(const intrusive_compare_key_type &key)
{ return index_type::find(key, intrusive_key_value_less()); }
const_iterator find(const intrusive_compare_key_type &key) const
{ return index_type::find(key, intrusive_key_value_less()); }
std::pair<iterator, bool>insert_check
(const intrusive_compare_key_type &key, insert_commit_data &commit_data)
{ return index_type::insert_check(key, intrusive_key_value_less(), commit_data); }
};
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//!Trait class to detect if an index is an intrusive
//!index.
template<class MapConfig>
struct is_intrusive_index
<boost::interprocess::iset_index<MapConfig> >
{
static const bool value = true;
};
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_ISET_INDEX_HPP

View File

@ -0,0 +1,250 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
#define BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/file_wrapper.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/permissions.hpp>
//These includes needed to fulfill default template parameters of
//predeclarations in interprocess_fwd.hpp
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
#include <boost/interprocess/sync/mutex_family.hpp>
#include <boost/interprocess/indexes/iset_index.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class AllocationAlgorithm>
struct mfile_open_or_create
{
typedef ipcdetail::managed_open_or_create_impl
< file_wrapper, AllocationAlgorithm::Alignment, true, false> type;
};
} //namespace ipcdetail {
//!A basic mapped file named object creation class. Initializes the
//!mapped file. Inherits all basic functionality from
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_mapped_file
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
: public ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType
,ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
public:
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType,
ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
typedef ipcdetail::file_wrapper device_type;
private:
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
basic_managed_mapped_file *get_this_pointer()
{ return this; }
private:
typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_mapped_file)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public: //functions
//!Unsigned integral type enough to represent
//!the size of a basic_managed_mapped_file.
typedef typename BOOST_INTERPROCESS_IMPDEF(base_t::size_type) size_type;
//!Creates mapped file and creates and places the segment manager.
//!This can throw.
basic_managed_mapped_file()
{}
//!Creates mapped file and creates and places the segment manager.
//!This can throw.
basic_managed_mapped_file(create_only_t, const char *name,
size_type size, const void *addr = 0, const permissions &perm = permissions())
: m_mfile(create_only, name, size, read_write, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
{}
//!Creates mapped file and creates and places the segment manager if
//!segment was not created. If segment was created it connects to the
//!segment.
//!This can throw.
basic_managed_mapped_file (open_or_create_t,
const char *name, size_type size,
const void *addr = 0, const permissions &perm = permissions())
: m_mfile(open_or_create, name, size, read_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpenOrCreate), perm)
{}
//!Connects to a created mapped file and its segment manager.
//!This can throw.
basic_managed_mapped_file (open_only_t, const char* name,
const void *addr = 0)
: m_mfile(open_only, name, read_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Connects to a created mapped file and its segment manager
//!in copy_on_write mode.
//!This can throw.
basic_managed_mapped_file (open_copy_on_write_t, const char* name,
const void *addr = 0)
: m_mfile(open_only, name, copy_on_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Connects to a created mapped file and its segment manager
//!in read-only mode.
//!This can throw.
basic_managed_mapped_file (open_read_only_t, const char* name,
const void *addr = 0)
: m_mfile(open_only, name, read_only, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_mapped_file(BOOST_RV_REF(basic_managed_mapped_file) moved)
{
this->swap(moved);
}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_mapped_file &operator=(BOOST_RV_REF(basic_managed_mapped_file) moved)
{
basic_managed_mapped_file tmp(boost::move(moved));
this->swap(tmp);
return *this;
}
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~basic_managed_mapped_file()
{}
//!Swaps the ownership of the managed mapped memories managed by *this and other.
//!Never throws.
void swap(basic_managed_mapped_file &other)
{
base_t::swap(other);
m_mfile.swap(other.m_mfile);
}
//!Flushes cached data to file.
//!Never throws
bool flush()
{ return m_mfile.flush(); }
//!Tries to resize mapped file so that we have room for
//!more objects.
//!
//!This function is not synchronized so no other thread or process should
//!be reading or writing the file
static bool grow(const char *filename, size_type extra_bytes)
{
return base_t::template grow
<basic_managed_mapped_file>(filename, extra_bytes);
}
//!Tries to resize mapped file to minimized the size of the file.
//!
//!This function is not synchronized so no other thread or process should
//!be reading or writing the file
static bool shrink_to_fit(const char *filename)
{
return base_t::template shrink_to_fit
<basic_managed_mapped_file>(filename);
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{
if(m_mfile.get_mapped_region().get_mode() == read_only){
return base_t::template find_no_lock<T>(name);
}
else{
return base_t::template find<T>(name);
}
}
private:
typename ipcdetail::mfile_open_or_create<AllocationAlgorithm>::type m_mfile;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Typedef for a default basic_managed_mapped_file
//!of narrow characters
typedef basic_managed_mapped_file
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_mapped_file;
//!Typedef for a default basic_managed_mapped_file
//!of wide characters
typedef basic_managed_mapped_file
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_mapped_file;
#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_MAPPED_FILE_HPP

View File

@ -0,0 +1,262 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
#define BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/managed_memory_impl.hpp>
#include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/permissions.hpp>
//These includes needed to fulfill default template parameters of
//predeclarations in interprocess_fwd.hpp
#include <boost/interprocess/mem_algo/rbtree_best_fit.hpp>
#include <boost/interprocess/sync/mutex_family.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class AllocationAlgorithm>
struct shmem_open_or_create
{
typedef ipcdetail::managed_open_or_create_impl
< shared_memory_object, AllocationAlgorithm::Alignment, true, false> type;
};
} //namespace ipcdetail {
//!A basic shared memory named object creation class. Initializes the
//!shared memory segment. Inherits all basic functionality from
//!basic_managed_memory_impl<CharType, AllocationAlgorithm, IndexType>*/
template
<
class CharType,
class AllocationAlgorithm,
template<class IndexConfig> class IndexType
>
class basic_managed_shared_memory
: public ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType
,ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>
, private ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef ipcdetail::basic_managed_memory_impl
<CharType, AllocationAlgorithm, IndexType,
ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> base_t;
typedef typename ipcdetail::shmem_open_or_create<AllocationAlgorithm>::type base2_t;
typedef ipcdetail::create_open_func<base_t> create_open_func_t;
basic_managed_shared_memory *get_this_pointer()
{ return this; }
public:
typedef shared_memory_object device_type;
typedef typename base_t::size_type size_type;
private:
typedef typename base_t::char_ptr_holder_t char_ptr_holder_t;
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_managed_shared_memory)
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public: //functions
//!Destroys *this and indicates that the calling process is finished using
//!the resource. The destructor function will deallocate
//!any system resources allocated by the system for use by this process for
//!this resource. The resource can still be opened again calling
//!the open constructor overload. To erase the resource from the system
//!use remove().
~basic_managed_shared_memory()
{}
//!Default constructor. Does nothing.
//!Useful in combination with move semantics
basic_managed_shared_memory()
{}
//!Creates shared memory and creates and places the segment manager.
//!This can throw.
basic_managed_shared_memory(create_only_t, const char *name,
size_type size, const void *addr = 0, const permissions& perm = permissions())
: base_t()
, base2_t(create_only, name, size, read_write, addr,
create_open_func_t(get_this_pointer(), ipcdetail::DoCreate), perm)
{}
//!Creates shared memory and creates and places the segment manager if
//!segment was not created. If segment was created it connects to the
//!segment.
//!This can throw.
basic_managed_shared_memory (open_or_create_t,
const char *name, size_type size,
const void *addr = 0, const permissions& perm = permissions())
: base_t()
, base2_t(open_or_create, name, size, read_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpenOrCreate), perm)
{}
//!Connects to a created shared memory and its segment manager.
//!in copy_on_write mode.
//!This can throw.
basic_managed_shared_memory (open_copy_on_write_t, const char* name,
const void *addr = 0)
: base_t()
, base2_t(open_only, name, copy_on_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Connects to a created shared memory and its segment manager.
//!in read-only mode.
//!This can throw.
basic_managed_shared_memory (open_read_only_t, const char* name,
const void *addr = 0)
: base_t()
, base2_t(open_only, name, read_only, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Connects to a created shared memory and its segment manager.
//!This can throw.
basic_managed_shared_memory (open_only_t, const char* name,
const void *addr = 0)
: base_t()
, base2_t(open_only, name, read_write, addr,
create_open_func_t(get_this_pointer(),
ipcdetail::DoOpen))
{}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_shared_memory(BOOST_RV_REF(basic_managed_shared_memory) moved)
{
basic_managed_shared_memory tmp;
this->swap(moved);
tmp.swap(moved);
}
//!Moves the ownership of "moved"'s managed memory to *this.
//!Does not throw
basic_managed_shared_memory &operator=(BOOST_RV_REF(basic_managed_shared_memory) moved)
{
basic_managed_shared_memory tmp(boost::move(moved));
this->swap(tmp);
return *this;
}
//!Swaps the ownership of the managed shared memories managed by *this and other.
//!Never throws.
void swap(basic_managed_shared_memory &other)
{
base_t::swap(other);
base2_t::swap(other);
}
//!Tries to resize the managed shared memory object so that we have
//!room for more objects.
//!
//!This function is not synchronized so no other thread or process should
//!be reading or writing the file
static bool grow(const char *shmname, size_type extra_bytes)
{
return base_t::template grow
<basic_managed_shared_memory>(shmname, extra_bytes);
}
//!Tries to resize the managed shared memory to minimized the size of the file.
//!
//!This function is not synchronized so no other thread or process should
//!be reading or writing the file
static bool shrink_to_fit(const char *shmname)
{
return base_t::template shrink_to_fit
<basic_managed_shared_memory>(shmname);
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//!Tries to find a previous named allocation address. Returns a memory
//!buffer and the object count. If not found returned pointer is 0.
//!Never throws.
template <class T>
std::pair<T*, size_type> find (char_ptr_holder_t name)
{
if(base2_t::get_mapped_region().get_mode() == read_only){
return base_t::template find_no_lock<T>(name);
}
else{
return base_t::template find<T>(name);
}
}
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Typedef for a default basic_managed_shared_memory
//!of narrow characters
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family>
,iset_index>
managed_shared_memory;
//!Typedef for a default basic_managed_shared_memory
//!of wide characters
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family>
,iset_index>
wmanaged_shared_memory;
//!Typedef for a default basic_managed_shared_memory
//!of narrow characters to be placed in a fixed address
typedef basic_managed_shared_memory
<char
,rbtree_best_fit<mutex_family, void*>
,iset_index>
fixed_managed_shared_memory;
//!Typedef for a default basic_managed_shared_memory
//!of narrow characters to be placed in a fixed address
typedef basic_managed_shared_memory
<wchar_t
,rbtree_best_fit<mutex_family, void*>
,iset_index>
wfixed_managed_shared_memory;
#endif //#ifdef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_MANAGED_SHARED_MEMORY_HPP

View File

@ -0,0 +1,596 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
#define BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
// interprocess
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/containers/allocation_type.hpp>
// interprocess/detail
#include <boost/interprocess/detail/math_functions.hpp>
#include <boost/interprocess/detail/min_max.hpp>
#include <boost/interprocess/detail/type_traits.hpp>
#include <boost/interprocess/detail/utilities.hpp>
// container/detail
#include <boost/container/detail/multiallocation_chain.hpp>
#include <boost/container/detail/placement_new.hpp>
// move
#include <boost/move/utility_core.hpp>
// other boost
#include <boost/static_assert.hpp>
#include <boost/assert.hpp>
//!\file
//!Implements common operations for memory algorithms.
namespace boost {
namespace interprocess {
namespace ipcdetail {
template<class VoidPointer>
class basic_multiallocation_chain
: public boost::container::container_detail::
basic_multiallocation_chain<VoidPointer>
{
BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_multiallocation_chain)
typedef boost::container::container_detail::
basic_multiallocation_chain<VoidPointer> base_t;
public:
basic_multiallocation_chain()
: base_t()
{}
basic_multiallocation_chain(BOOST_RV_REF(basic_multiallocation_chain) other)
: base_t(::boost::move(static_cast<base_t&>(other)))
{}
basic_multiallocation_chain& operator=(BOOST_RV_REF(basic_multiallocation_chain) other)
{
this->base_t::operator=(::boost::move(static_cast<base_t&>(other)));
return *this;
}
void *pop_front()
{
return boost::interprocess::ipcdetail::to_raw_pointer(this->base_t::pop_front());
}
};
//!This class implements several allocation functions shared by different algorithms
//!(aligned allocation, multiple allocation...).
template<class MemoryAlgorithm>
class memory_algorithm_common
{
public:
typedef typename MemoryAlgorithm::void_pointer void_pointer;
typedef typename MemoryAlgorithm::block_ctrl block_ctrl;
typedef typename MemoryAlgorithm::multiallocation_chain multiallocation_chain;
typedef memory_algorithm_common<MemoryAlgorithm> this_type;
typedef typename MemoryAlgorithm::size_type size_type;
static const size_type Alignment = MemoryAlgorithm::Alignment;
static const size_type MinBlockUnits = MemoryAlgorithm::MinBlockUnits;
static const size_type AllocatedCtrlBytes = MemoryAlgorithm::AllocatedCtrlBytes;
static const size_type AllocatedCtrlUnits = MemoryAlgorithm::AllocatedCtrlUnits;
static const size_type BlockCtrlBytes = MemoryAlgorithm::BlockCtrlBytes;
static const size_type BlockCtrlUnits = MemoryAlgorithm::BlockCtrlUnits;
static const size_type UsableByPreviousChunk = MemoryAlgorithm::UsableByPreviousChunk;
static void assert_alignment(const void *ptr)
{ assert_alignment((std::size_t)ptr); }
static void assert_alignment(size_type uint_ptr)
{
(void)uint_ptr;
BOOST_ASSERT(uint_ptr % Alignment == 0);
}
static bool check_alignment(const void *ptr)
{ return (((std::size_t)ptr) % Alignment == 0); }
static size_type ceil_units(size_type size)
{ return get_rounded_size(size, Alignment)/Alignment; }
static size_type floor_units(size_type size)
{ return size/Alignment; }
static size_type multiple_of_units(size_type size)
{ return get_rounded_size(size, Alignment); }
static void allocate_many
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain);
}
static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
{
return this_type::priv_deallocate_many(memory_algo, chain);
}
static bool calculate_lcm_and_needs_backwards_lcmed
(size_type backwards_multiple, size_type received_size, size_type size_to_achieve,
size_type &lcm_out, size_type &needs_backwards_lcmed_out)
{
// Now calculate lcm_val
size_type max = backwards_multiple;
size_type min = Alignment;
size_type needs_backwards;
size_type needs_backwards_lcmed;
size_type lcm_val;
size_type current_forward;
//Swap if necessary
if(max < min){
size_type tmp = min;
min = max;
max = tmp;
}
//Check if it's power of two
if((backwards_multiple & (backwards_multiple-1)) == 0){
if(0 != (size_to_achieve & ((backwards_multiple-1)))){
return false;
}
lcm_val = max;
//If we want to use minbytes data to get a buffer between maxbytes
//and minbytes if maxbytes can't be achieved, calculate the
//biggest of all possibilities
current_forward = get_truncated_size_po2(received_size, backwards_multiple);
needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
needs_backwards_lcmed = get_rounded_size_po2(needs_backwards, lcm_val);
lcm_out = lcm_val;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
//Check if it's multiple of alignment
else if((backwards_multiple & (Alignment - 1u)) == 0){
lcm_val = backwards_multiple;
current_forward = get_truncated_size(received_size, backwards_multiple);
//No need to round needs_backwards because backwards_multiple == lcm_val
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards_lcmed & (Alignment - 1u)) == 0);
lcm_out = lcm_val;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
//Check if it's multiple of the half of the alignmment
else if((backwards_multiple & ((Alignment/2u) - 1u)) == 0){
lcm_val = backwards_multiple*2u;
current_forward = get_truncated_size(received_size, backwards_multiple);
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
if(0 != (needs_backwards_lcmed & (Alignment-1)))
//while(0 != (needs_backwards_lcmed & (Alignment-1)))
needs_backwards_lcmed += backwards_multiple;
BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0);
lcm_out = lcm_val;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
//Check if it's multiple of the quarter of the alignmment
else if((backwards_multiple & ((Alignment/4u) - 1u)) == 0){
size_type remainder;
lcm_val = backwards_multiple*4u;
current_forward = get_truncated_size(received_size, backwards_multiple);
needs_backwards_lcmed = needs_backwards = size_to_achieve - current_forward;
//while(0 != (needs_backwards_lcmed & (Alignment-1)))
//needs_backwards_lcmed += backwards_multiple;
if(0 != (remainder = ((needs_backwards_lcmed & (Alignment-1))>>(Alignment/8u)))){
if(backwards_multiple & Alignment/2u){
needs_backwards_lcmed += (remainder)*backwards_multiple;
}
else{
needs_backwards_lcmed += (4-remainder)*backwards_multiple;
}
}
BOOST_ASSERT((needs_backwards_lcmed % lcm_val) == 0);
lcm_out = lcm_val;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
else{
lcm_val = lcm(max, min);
}
//If we want to use minbytes data to get a buffer between maxbytes
//and minbytes if maxbytes can't be achieved, calculate the
//biggest of all possibilities
current_forward = get_truncated_size(received_size, backwards_multiple);
needs_backwards = size_to_achieve - current_forward;
BOOST_ASSERT((needs_backwards % backwards_multiple) == 0);
needs_backwards_lcmed = get_rounded_size(needs_backwards, lcm_val);
lcm_out = lcm_val;
needs_backwards_lcmed_out = needs_backwards_lcmed;
return true;
}
static void allocate_many
( MemoryAlgorithm *memory_algo
, const size_type *elem_sizes
, size_type n_elements
, size_type sizeof_element
, multiallocation_chain &chain)
{
this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain);
}
static void* allocate_aligned
(MemoryAlgorithm *memory_algo, size_type nbytes, size_type alignment)
{
//Ensure power of 2
if ((alignment & (alignment - size_type(1u))) != 0){
//Alignment is not power of two
BOOST_ASSERT((alignment & (alignment - size_type(1u))) == 0);
return 0;
}
size_type real_size = nbytes;
if(alignment <= Alignment){
void *ignore_reuse = 0;
return memory_algo->priv_allocate
(boost::interprocess::allocate_new, nbytes, real_size, ignore_reuse);
}
if(nbytes > UsableByPreviousChunk)
nbytes -= UsableByPreviousChunk;
//We can find a aligned portion if we allocate a block that has alignment
//nbytes + alignment bytes or more.
size_type minimum_allocation = max_value
(nbytes + alignment, size_type(MinBlockUnits*Alignment));
//Since we will split that block, we must request a bit more memory
//if the alignment is near the beginning of the buffer, because otherwise,
//there is no space for a new block before the alignment.
//
// ____ Aligned here
// |
// -----------------------------------------------------
// | MBU |
// -----------------------------------------------------
size_type request =
minimum_allocation + (2*MinBlockUnits*Alignment - AllocatedCtrlBytes
//prevsize - UsableByPreviousChunk
);
//Now allocate the buffer
real_size = request;
void *ignore_reuse = 0;
void *buffer = memory_algo->priv_allocate(boost::interprocess::allocate_new, request, real_size, ignore_reuse);
if(!buffer){
return 0;
}
else if ((((std::size_t)(buffer)) % alignment) == 0){
//If we are lucky and the buffer is aligned, just split it and
//return the high part
block_ctrl *first = memory_algo->priv_get_block(buffer);
size_type old_size = first->m_size;
const size_type first_min_units =
max_value(ceil_units(nbytes) + AllocatedCtrlUnits, size_type(MinBlockUnits));
//We can create a new block in the end of the segment
if(old_size >= (first_min_units + MinBlockUnits)){
block_ctrl *second = reinterpret_cast<block_ctrl *>
(reinterpret_cast<char*>(first) + Alignment*first_min_units);
first->m_size = first_min_units;
second->m_size = old_size - first->m_size;
BOOST_ASSERT(second->m_size >= MinBlockUnits);
memory_algo->priv_mark_new_allocated_block(first);
memory_algo->priv_mark_new_allocated_block(second);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(second));
}
return buffer;
}
//Buffer not aligned, find the aligned part.
//
// ____ Aligned here
// |
// -----------------------------------------------------
// | MBU +more | ACB |
// -----------------------------------------------------
char *pos = reinterpret_cast<char*>
(reinterpret_cast<std::size_t>(static_cast<char*>(buffer) +
//This is the minimum size of (2)
(MinBlockUnits*Alignment - AllocatedCtrlBytes) +
//This is the next MBU for the aligned memory
AllocatedCtrlBytes +
//This is the alignment trick
alignment - 1) & -alignment);
//Now obtain the address of the blocks
block_ctrl *first = memory_algo->priv_get_block(buffer);
block_ctrl *second = memory_algo->priv_get_block(pos);
BOOST_ASSERT(pos <= (reinterpret_cast<char*>(first) + first->m_size*Alignment));
BOOST_ASSERT(first->m_size >= 2*MinBlockUnits);
BOOST_ASSERT((pos + MinBlockUnits*Alignment - AllocatedCtrlBytes + nbytes*Alignment/Alignment) <=
(reinterpret_cast<char*>(first) + first->m_size*Alignment));
//Set the new size of the first block
size_type old_size = first->m_size;
first->m_size = (size_type)(reinterpret_cast<char*>(second) - reinterpret_cast<char*>(first))/Alignment;
memory_algo->priv_mark_new_allocated_block(first);
//Now check if we can create a new buffer in the end
//
// __"second" block
// | __Aligned here
// | | __"third" block
// -----------|-----|-----|------------------------------
// | MBU +more | ACB | (3) | BCU |
// -----------------------------------------------------
//This size will be the minimum size to be able to create a
//new block in the end.
const size_type second_min_units = max_value(size_type(MinBlockUnits),
ceil_units(nbytes) + AllocatedCtrlUnits );
//Check if we can create a new block (of size MinBlockUnits) in the end of the segment
if((old_size - first->m_size) >= (second_min_units + MinBlockUnits)){
//Now obtain the address of the end block
block_ctrl *third = new (reinterpret_cast<char*>(second) + Alignment*second_min_units)block_ctrl;
second->m_size = second_min_units;
third->m_size = old_size - first->m_size - second->m_size;
BOOST_ASSERT(third->m_size >= MinBlockUnits);
memory_algo->priv_mark_new_allocated_block(second);
memory_algo->priv_mark_new_allocated_block(third);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(third));
}
else{
second->m_size = old_size - first->m_size;
BOOST_ASSERT(second->m_size >= MinBlockUnits);
memory_algo->priv_mark_new_allocated_block(second);
}
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(first));
return memory_algo->priv_get_user_buffer(second);
}
static bool try_shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, size_type &received_size)
{
size_type const preferred_size = received_size;
(void)memory_algo;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
//The block must be marked as allocated
BOOST_ASSERT(memory_algo->priv_is_allocated_block(block));
//Check if alignment and block size are right
assert_alignment(ptr);
//Put this to a safe value
received_size = (old_block_units - AllocatedCtrlUnits)*Alignment + UsableByPreviousChunk;
//Now translate it to Alignment units
const size_type max_user_units = floor_units(max_size - UsableByPreviousChunk);
const size_type preferred_user_units = ceil_units(preferred_size - UsableByPreviousChunk);
//Check if rounded max and preferred are possible correct
if(max_user_units < preferred_user_units)
return false;
//Check if the block is smaller than the requested minimum
size_type old_user_units = old_block_units - AllocatedCtrlUnits;
if(old_user_units < preferred_user_units)
return false;
//If the block is smaller than the requested minimum
if(old_user_units == preferred_user_units)
return true;
size_type shrunk_user_units =
((BlockCtrlUnits - AllocatedCtrlUnits) >= preferred_user_units)
? (BlockCtrlUnits - AllocatedCtrlUnits)
: preferred_user_units;
//Some parameter checks
if(max_user_units < shrunk_user_units)
return false;
//We must be able to create at least a new empty block
if((old_user_units - shrunk_user_units) < BlockCtrlUnits ){
return false;
}
//Update new size
received_size = shrunk_user_units*Alignment + UsableByPreviousChunk;
return true;
}
static bool shrink
(MemoryAlgorithm *memory_algo, void *ptr
,const size_type max_size, size_type &received_size)
{
size_type const preferred_size = received_size;
//Obtain the real block
block_ctrl *block = memory_algo->priv_get_block(ptr);
size_type old_block_units = (size_type)block->m_size;
if(!try_shrink(memory_algo, ptr, max_size, received_size)){
return false;
}
//Check if the old size was just the shrunk size (no splitting)
if((old_block_units - AllocatedCtrlUnits) == ceil_units(preferred_size - UsableByPreviousChunk))
return true;
//Now we can just rewrite the size of the old buffer
block->m_size = (received_size-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits;
BOOST_ASSERT(block->m_size >= BlockCtrlUnits);
//We create the new block
block_ctrl *new_block = reinterpret_cast<block_ctrl*>
(reinterpret_cast<char*>(block) + block->m_size*Alignment);
//Write control data to simulate this new block was previously allocated
//and deallocate it
new_block->m_size = old_block_units - block->m_size;
BOOST_ASSERT(new_block->m_size >= BlockCtrlUnits);
memory_algo->priv_mark_new_allocated_block(block);
memory_algo->priv_mark_new_allocated_block(new_block);
memory_algo->priv_deallocate(memory_algo->priv_get_user_buffer(new_block));
return true;
}
private:
static void priv_allocate_many
( MemoryAlgorithm *memory_algo
, const size_type *elem_sizes
, size_type n_elements
, size_type sizeof_element
, multiallocation_chain &chain)
{
//Note: sizeof_element == 0 indicates that we want to
//allocate n_elements of the same size "*elem_sizes"
//Calculate the total size of all requests
size_type total_request_units = 0;
size_type elem_units = 0;
const size_type ptr_size_units = memory_algo->priv_get_total_units(sizeof(void_pointer));
if(!sizeof_element){
elem_units = memory_algo->priv_get_total_units(*elem_sizes);
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
total_request_units = n_elements*elem_units;
}
else{
for(size_type i = 0; i < n_elements; ++i){
if(multiplication_overflows(elem_sizes[i], sizeof_element)){
total_request_units = 0;
break;
}
elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element);
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
if(sum_overflows(total_request_units, elem_units)){
total_request_units = 0;
break;
}
total_request_units += elem_units;
}
}
if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){
size_type low_idx = 0;
while(low_idx < n_elements){
size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
size_type min_allocation = (!sizeof_element)
? elem_units
: memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
size_type received_size = total_bytes;
void *ignore_reuse = 0;
void *ret = memory_algo->priv_allocate
(boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse);
if(!ret){
break;
}
block_ctrl *block = memory_algo->priv_get_block(ret);
size_type received_units = (size_type)block->m_size;
char *block_address = reinterpret_cast<char*>(block);
size_type total_used_units = 0;
while(total_used_units < received_units){
if(sizeof_element){
elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
}
if(total_used_units + elem_units > received_units)
break;
total_request_units -= elem_units;
//This is the position where the new block must be created
block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address);
assert_alignment(new_block);
//The last block should take all the remaining space
if((low_idx + 1) == n_elements ||
(total_used_units + elem_units +
((!sizeof_element)
? elem_units
: max_value(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units))
> received_units)){
//By default, the new block will use the rest of the buffer
new_block->m_size = received_units - total_used_units;
memory_algo->priv_mark_new_allocated_block(new_block);
//If the remaining units are bigger than needed and we can
//split it obtaining a new free memory block do it.
if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
size_type shrunk_received = shrunk_request;
bool shrink_ok = shrink
(memory_algo
,memory_algo->priv_get_user_buffer(new_block)
,shrunk_request
,shrunk_received);
(void)shrink_ok;
//Shrink must always succeed with passed parameters
BOOST_ASSERT(shrink_ok);
//Some sanity checks
BOOST_ASSERT(shrunk_request == shrunk_received);
BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
//"new_block->m_size" must have been reduced to elem_units by "shrink"
BOOST_ASSERT(new_block->m_size == elem_units);
//Now update the total received units with the reduction
received_units = elem_units + total_used_units;
}
}
else{
new_block->m_size = elem_units;
memory_algo->priv_mark_new_allocated_block(new_block);
}
block_address += new_block->m_size*Alignment;
total_used_units += (size_type)new_block->m_size;
//Check we have enough room to overwrite the intrusive pointer
BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
void_pointer p = ::new(memory_algo->priv_get_user_buffer(new_block), boost_container_new_t())void_pointer(0);
chain.push_back(p);
++low_idx;
}
//Sanity check
BOOST_ASSERT(total_used_units == received_units);
}
if(low_idx != n_elements){
priv_deallocate_many(memory_algo, chain);
}
}
}
static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
{
while(!chain.empty()){
memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front()));
}
}
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_MEM_ALGO_COMMON_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,751 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP
#define BOOST_INTERPROCESS_OFFSET_PTR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/interprocess/detail/cast_tags.hpp>
#include <boost/interprocess/detail/mpl.hpp>
#include <boost/container/detail/type_traits.hpp> //alignment_of, aligned_storage
#include <boost/assert.hpp>
#include <iosfwd>
//!\file
//!Describes a smart pointer that stores the offset between this pointer and
//!target pointee, called offset_ptr.
namespace boost {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Predeclarations
template <class T>
struct has_trivial_destructor;
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace ipcdetail {
template<class OffsetType, std::size_t OffsetAlignment>
union offset_ptr_internal
{
BOOST_STATIC_ASSERT(sizeof(OffsetType) >= sizeof(uintptr_t));
explicit offset_ptr_internal(OffsetType off)
: m_offset(off)
{}
OffsetType m_offset; //Distance between this object and pointee address
typename ::boost::container::container_detail::aligned_storage
< sizeof(OffsetType)//for offset_type_alignment m_offset will be enough
, (OffsetAlignment == offset_type_alignment) ? 1u : OffsetAlignment
>::type alignment_helper;
};
//Note: using the address of a local variable to point to another address
//is not standard conforming and this can be optimized-away by the compiler.
//Non-inlining is a method to remain illegal but correct
//Undef BOOST_INTERPROCESS_OFFSET_PTR_INLINE_XXX if your compiler can inline
//this code without breaking the library
////////////////////////////////////////////////////////////////////////
//
// offset_ptr_to_raw_pointer
//
////////////////////////////////////////////////////////////////////////
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
BOOST_INTERPROCESS_FORCEINLINE void * offset_ptr_to_raw_pointer(const volatile void *this_ptr, uintptr_t offset)
{
typedef pointer_uintptr_caster<void*> caster_t;
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_PTR
if(offset == 1){
return 0;
}
else{
return caster_t(caster_t(this_ptr).uintptr() + offset).pointer();
}
#else
uintptr_t mask = offset == 1;
--mask;
uintptr_t target_offset = caster_t(this_ptr).uintptr() + offset;
target_offset &= mask;
return caster_t(target_offset).pointer();
#endif
}
////////////////////////////////////////////////////////////////////////
//
// offset_ptr_to_offset
//
////////////////////////////////////////////////////////////////////////
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
BOOST_INTERPROCESS_FORCEINLINE uintptr_t offset_ptr_to_offset(const volatile void *ptr, const volatile void *this_ptr)
{
typedef pointer_uintptr_caster<void*> caster_t;
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF
//offset == 1 && ptr != 0 is not legal for this pointer
if(!ptr){
return 1;
}
else{
uintptr_t offset = caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr();
BOOST_ASSERT(offset != 1);
return offset;
}
#else
//const uintptr_t other = -uintptr_t(ptr != 0);
//const uintptr_t offset = (caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr()) & other;
//return offset + uintptr_t(!other);
//
uintptr_t offset = caster_t(ptr).uintptr() - caster_t(this_ptr).uintptr();
--offset;
uintptr_t mask = uintptr_t(ptr == 0);
--mask;
offset &= mask;
return ++offset;
#endif
}
////////////////////////////////////////////////////////////////////////
//
// offset_ptr_to_offset_from_other
//
////////////////////////////////////////////////////////////////////////
#define BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
BOOST_INTERPROCESS_FORCEINLINE uintptr_t offset_ptr_to_offset_from_other
(const volatile void *this_ptr, const volatile void *other_ptr, uintptr_t other_offset)
{
typedef pointer_uintptr_caster<void*> caster_t;
#ifndef BOOST_INTERPROCESS_OFFSET_PTR_BRANCHLESS_TO_OFF_FROM_OTHER
if(other_offset == 1){
return 1;
}
else{
uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr() + other_offset;
BOOST_ASSERT(offset != 1);
return offset;
}
#else
uintptr_t mask = other_offset == 1;
--mask;
uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr();
offset &= mask;
return offset + other_offset;
//uintptr_t mask = -uintptr_t(other_offset != 1);
//uintptr_t offset = caster_t(other_ptr).uintptr() - caster_t(this_ptr).uintptr();
//offset &= mask;
//return offset + other_offset;
#endif
}
////////////////////////////////////////////////////////////////////////
//
// Let's assume cast to void and cv cast don't change any target address
//
////////////////////////////////////////////////////////////////////////
template<class From, class To>
struct offset_ptr_maintains_address
{
static const bool value = ipcdetail::is_cv_same<From, To>::value
|| ipcdetail::is_cv_same<void, To>::value
|| ipcdetail::is_cv_same<char, To>::value
;
};
template<class From, class To, class Ret = void>
struct enable_if_convertible_equal_address
: enable_if_c< ::boost::is_convertible<From*, To*>::value
&& offset_ptr_maintains_address<From, To>::value
, Ret>
{};
template<class From, class To, class Ret = void>
struct enable_if_convertible_unequal_address
: enable_if_c< ::boost::is_convertible<From*, To*>::value
&& !offset_ptr_maintains_address<From, To>::value
, Ret>
{};
} //namespace ipcdetail {
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!A smart pointer that stores the offset between between the pointer and the
//!the object it points. This allows offset allows special properties, since
//!the pointer is independent from the address of the pointee, if the
//!pointer and the pointee are still separated by the same offset. This feature
//!converts offset_ptr in a smart pointer that can be placed in shared memory and
//!memory mapped files mapped in different addresses in every process.
//!
//! \tparam PointedType The type of the pointee.
//! \tparam DifferenceType A signed integer type that can represent the arithmetic operations on the pointer
//! \tparam OffsetType An unsigned integer type that can represent the
//! distance between two pointers reinterpret_cast-ed as unsigned integers. This type
//! should be at least of the same size of std::uintptr_t. In some systems it's possible to communicate
//! between 32 and 64 bit processes using 64 bit offsets.
//! \tparam OffsetAlignment Alignment of the OffsetType stored inside. In some systems might be necessary
//! to align it to 64 bits in order to communicate 32 and 64 bit processes using 64 bit offsets.
//!
//!<b>Note</b>: offset_ptr uses implementation defined properties, present in most platforms, for
//!performance reasons:
//! - Assumes that uintptr_t representation of nullptr is (uintptr_t)zero.
//! - Assumes that incrementing a uintptr_t obtained from a pointer is equivalent
//! to incrementing the pointer and then converting it back to uintptr_t.
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment>
class offset_ptr
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
typedef offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment> self_t;
void unspecified_bool_type_func() const {}
typedef void (self_t::*unspecified_bool_type)() const;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
typedef PointedType element_type;
typedef PointedType * pointer;
typedef typename ipcdetail::
add_reference<PointedType>::type reference;
typedef typename ipcdetail::
remove_volatile<typename ipcdetail::
remove_const<PointedType>::type
>::type value_type;
typedef DifferenceType difference_type;
typedef std::random_access_iterator_tag iterator_category;
typedef OffsetType offset_type;
public: //Public Functions
//!Default constructor (null pointer).
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr() BOOST_NOEXCEPT
: internal(1)
{}
//!Constructor from raw pointer (allows "0" pointer conversion).
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(pointer ptr) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset(ptr, this)))
{}
//!Constructor from other pointer.
//!Never throws.
template <class T>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( T *ptr
, typename ipcdetail::enable_if< ::boost::is_convertible<T*, PointedType*> >::type * = 0) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(ptr), this)))
{}
//!Constructor from other offset_ptr
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr& ptr) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset)))
{}
//!Constructor from other offset_ptr. If pointers of pointee types are
//!convertible, offset_ptrs will be convertibles. Never throws.
template<class T2>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
, typename ipcdetail::enable_if_convertible_equal_address<T2, PointedType>::type* = 0
#endif
) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset())))
{}
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Constructor from other offset_ptr. If pointers of pointee types are
//!convertible, offset_ptrs will be convertibles. Never throws.
template<class T2>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
, typename ipcdetail::enable_if_convertible_unequal_address<T2, PointedType>::type* = 0) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(ptr.get()), this)))
{}
#endif
//!Emulates static_cast operator.
//!Never throws.
template<class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::static_cast_tag) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(r.get()), this)))
{}
//!Emulates const_cast operator.
//!Never throws.
template<class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::const_cast_tag) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset(const_cast<PointedType*>(r.get()), this)))
{}
//!Emulates dynamic_cast operator.
//!Never throws.
template<class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::dynamic_cast_tag) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset(dynamic_cast<PointedType*>(r.get()), this)))
{}
//!Emulates reinterpret_cast operator.
//!Never throws.
template<class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE offset_ptr(const offset_ptr<T2, P2, O2, A2> & r, ipcdetail::reinterpret_cast_tag) BOOST_NOEXCEPT
: internal(static_cast<OffsetType>
(ipcdetail::offset_ptr_to_offset(reinterpret_cast<PointedType*>(r.get()), this)))
{}
//!Obtains raw pointer from offset.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE pointer get() const BOOST_NOEXCEPT
{ return (pointer)ipcdetail::offset_ptr_to_raw_pointer(this, this->internal.m_offset); }
BOOST_INTERPROCESS_FORCEINLINE offset_type get_offset() const BOOST_NOEXCEPT
{ return this->internal.m_offset; }
//!Pointer-like -> operator. It can return 0 pointer.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE pointer operator->() const BOOST_NOEXCEPT
{ return this->get(); }
//!Dereferencing operator, if it is a null offset_ptr behavior
//! is undefined. Never throws.
BOOST_INTERPROCESS_FORCEINLINE reference operator* () const BOOST_NOEXCEPT
{
pointer p = this->get();
reference r = *p;
return r;
}
//!Indexing operator.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE reference operator[](difference_type idx) const BOOST_NOEXCEPT
{ return this->get()[idx]; }
//!Assignment from pointer (saves extra conversion).
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (pointer from) BOOST_NOEXCEPT
{
this->internal.m_offset =
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset(from, this));
return *this;
}
//!Assignment from other offset_ptr.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator= (const offset_ptr & ptr) BOOST_NOEXCEPT
{
this->internal.m_offset =
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.internal.m_offset));
return *this;
}
//!Assignment from related offset_ptr. If pointers of pointee types
//! are assignable, offset_ptrs will be assignable. Never throws.
template<class T2> BOOST_INTERPROCESS_FORCEINLINE
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
typename ipcdetail::enable_if_c
< ::boost::is_convertible<T2*, PointedType*>::value, offset_ptr&>::type
#else
offset_ptr&
#endif
operator= (const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr) BOOST_NOEXCEPT
{
this->assign(ptr, ipcdetail::bool_<ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value>());
return *this;
}
public:
//!offset_ptr += difference_type.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator+= (difference_type offset) BOOST_NOEXCEPT
{ this->inc_offset(offset * sizeof (PointedType)); return *this; }
//!offset_ptr -= difference_type.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr &operator-= (difference_type offset) BOOST_NOEXCEPT
{ this->dec_offset(offset * sizeof (PointedType)); return *this; }
//!++offset_ptr.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator++ (void) BOOST_NOEXCEPT
{ this->inc_offset(sizeof (PointedType)); return *this; }
//!offset_ptr++.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator++ (int) BOOST_NOEXCEPT
{
offset_ptr tmp(*this);
this->inc_offset(sizeof (PointedType));
return tmp;
}
//!--offset_ptr.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr& operator-- (void) BOOST_NOEXCEPT
{ this->dec_offset(sizeof (PointedType)); return *this; }
//!offset_ptr--.
//!Never throws.
BOOST_INTERPROCESS_FORCEINLINE offset_ptr operator-- (int) BOOST_NOEXCEPT
{
offset_ptr tmp(*this);
this->dec_offset(sizeof (PointedType));
return tmp;
}
//!safe bool conversion operator.
//!Never throws.
#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
BOOST_INTERPROCESS_FORCEINLINE operator unspecified_bool_type() const BOOST_NOEXCEPT
{ return this->internal.m_offset != 1? &self_t::unspecified_bool_type_func : 0; }
#else
explicit operator bool() const BOOST_NOEXCEPT
{ return this->internal.m_offset != 1; }
#endif
//!Not operator. Not needed in theory, but improves portability.
//!Never throws
BOOST_INTERPROCESS_FORCEINLINE bool operator! () const BOOST_NOEXCEPT
{ return this->internal.m_offset == 1; }
//!Compatibility with pointer_traits
//!
template <class U>
struct rebind
{ typedef offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment> other; };
//!Compatibility with pointer_traits
//!
BOOST_INTERPROCESS_FORCEINLINE static offset_ptr pointer_to(reference r) BOOST_NOEXCEPT
{ return offset_ptr(&r); }
//!difference_type + offset_ptr
//!operation
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(difference_type diff, offset_ptr right) BOOST_NOEXCEPT
{ right += diff; return right; }
//!offset_ptr + difference_type
//!operation
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator+(offset_ptr left, difference_type diff) BOOST_NOEXCEPT
{ left += diff; return left; }
//!offset_ptr - diff
//!operation
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(offset_ptr left, difference_type diff) BOOST_NOEXCEPT
{ left -= diff; return left; }
//!offset_ptr - diff
//!operation
BOOST_INTERPROCESS_FORCEINLINE friend offset_ptr operator-(difference_type diff, offset_ptr right) BOOST_NOEXCEPT
{ right -= diff; return right; }
//!offset_ptr - offset_ptr
//!operation
BOOST_INTERPROCESS_FORCEINLINE friend difference_type operator-(const offset_ptr &pt, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return difference_type(pt.get()- pt2.get()); }
//Comparison
BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1.get() == pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1.get() != pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1.get() < pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1.get() <= pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1.get() > pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1.get() >= pt2.get(); }
//Comparison to raw ptr to support literal 0
BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1 == pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1 != pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1 < pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1 <= pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1 > pt2.get(); }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(pointer pt1, const offset_ptr &pt2) BOOST_NOEXCEPT
{ return pt1 >= pt2.get(); }
//Comparison
BOOST_INTERPROCESS_FORCEINLINE friend bool operator== (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
{ return pt1.get() == pt2; }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator!= (const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
{ return pt1.get() != pt2; }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
{ return pt1.get() < pt2; }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator<=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
{ return pt1.get() <= pt2; }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
{ return pt1.get() > pt2; }
BOOST_INTERPROCESS_FORCEINLINE friend bool operator>=(const offset_ptr &pt1, pointer pt2) BOOST_NOEXCEPT
{ return pt1.get() >= pt2; }
BOOST_INTERPROCESS_FORCEINLINE friend void swap(offset_ptr &left, offset_ptr &right) BOOST_NOEXCEPT
{
pointer ptr = right.get();
right = left;
left = ptr;
}
private:
template<class T2>
BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr, ipcdetail::bool_<true>) BOOST_NOEXCEPT
{ //no need to pointer adjustment
this->internal.m_offset =
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset_from_other(this, &ptr, ptr.get_offset()));
}
template<class T2>
BOOST_INTERPROCESS_FORCEINLINE void assign(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr, ipcdetail::bool_<false>) BOOST_NOEXCEPT
{ //we must convert to raw before calculating the offset
this->internal.m_offset =
static_cast<OffsetType>(ipcdetail::offset_ptr_to_offset(static_cast<PointedType*>(ptr.get()), this));
}
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
BOOST_INTERPROCESS_FORCEINLINE void inc_offset(DifferenceType bytes) BOOST_NOEXCEPT
{ internal.m_offset += bytes; }
BOOST_INTERPROCESS_FORCEINLINE void dec_offset(DifferenceType bytes) BOOST_NOEXCEPT
{ internal.m_offset -= bytes; }
ipcdetail::offset_ptr_internal<OffsetType, OffsetAlignment> internal;
public:
BOOST_INTERPROCESS_FORCEINLINE const OffsetType &priv_offset() const BOOST_NOEXCEPT
{ return internal.m_offset; }
BOOST_INTERPROCESS_FORCEINLINE OffsetType &priv_offset() BOOST_NOEXCEPT
{ return internal.m_offset; }
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
//!operator<<
//!for offset ptr
template<class E, class T, class W, class X, class Y, std::size_t Z>
inline std::basic_ostream<E, T> & operator<<
(std::basic_ostream<E, T> & os, offset_ptr<W, X, Y, Z> const & p)
{ return os << p.get_offset(); }
//!operator>>
//!for offset ptr
template<class E, class T, class W, class X, class Y, std::size_t Z>
inline std::basic_istream<E, T> & operator>>
(std::basic_istream<E, T> & is, offset_ptr<W, X, Y, Z> & p)
{ return is >> p.get_offset(); }
//!Simulation of static_cast between pointers. Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
static_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
{
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
(r, boost::interprocess::ipcdetail::static_cast_tag());
}
//!Simulation of const_cast between pointers. Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
const_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
{
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
(r, boost::interprocess::ipcdetail::const_cast_tag());
}
//!Simulation of dynamic_cast between pointers. Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
dynamic_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
{
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
(r, boost::interprocess::ipcdetail::dynamic_cast_tag());
}
//!Simulation of reinterpret_cast between pointers. Never throws.
template<class T1, class P1, class O1, std::size_t A1, class T2, class P2, class O2, std::size_t A2>
BOOST_INTERPROCESS_FORCEINLINE boost::interprocess::offset_ptr<T1, P1, O1, A1>
reinterpret_pointer_cast(const boost::interprocess::offset_ptr<T2, P2, O2, A2> & r) BOOST_NOEXCEPT
{
return boost::interprocess::offset_ptr<T1, P1, O1, A1>
(r, boost::interprocess::ipcdetail::reinterpret_cast_tag());
}
} //namespace interprocess {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
///has_trivial_destructor<> == true_type specialization for optimizations
template <class T, class P, class O, std::size_t A>
struct has_trivial_destructor< ::boost::interprocess::offset_ptr<T, P, O, A> >
{
static const bool value = true;
};
namespace move_detail {
///has_trivial_destructor<> == true_type specialization for optimizations
template <class T, class P, class O, std::size_t A>
struct is_trivially_destructible< ::boost::interprocess::offset_ptr<T, P, O, A> >
{
static const bool value = true;
};
} //namespace move_detail {
namespace interprocess {
//!to_raw_pointer() enables boost::mem_fn to recognize offset_ptr.
//!Never throws.
template <class T, class P, class O, std::size_t A>
BOOST_INTERPROCESS_FORCEINLINE T * to_raw_pointer(boost::interprocess::offset_ptr<T, P, O, A> const & p) BOOST_NOEXCEPT
{ return ipcdetail::to_raw_pointer(p); }
} //namespace interprocess
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
} //namespace boost {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace boost{
//This is to support embedding a bit in the pointer
//for intrusive containers, saving space
namespace intrusive {
//Predeclaration to avoid including header
template<class VoidPointer, std::size_t N>
struct max_pointer_plus_bits;
template<std::size_t OffsetAlignment, class P, class O, std::size_t A>
struct max_pointer_plus_bits<boost::interprocess::offset_ptr<void, P, O, A>, OffsetAlignment>
{
//The offset ptr can embed one bit less than the alignment since it
//uses offset == 1 to store the null pointer.
static const std::size_t value = ::boost::interprocess::ipcdetail::ls_zeros<OffsetAlignment>::value - 1;
};
//Predeclaration
template<class Pointer, std::size_t NumBits>
struct pointer_plus_bits;
template<class T, class P, class O, std::size_t A, std::size_t NumBits>
struct pointer_plus_bits<boost::interprocess::offset_ptr<T, P, O, A>, NumBits>
{
typedef boost::interprocess::offset_ptr<T, P, O, A> pointer;
//Bits are stored in the lower bits of the pointer except the LSB,
//because this bit is used to represent the null pointer.
static const uintptr_t Mask = ((uintptr_t(1) << uintptr_t(NumBits)) - uintptr_t(1)) << uintptr_t(1);
BOOST_STATIC_ASSERT(0 ==(Mask&1));
//We must ALWAYS take argument "n" by reference as a copy of a null pointer
//with a bit (e.g. offset == 3) would be incorrectly copied and interpreted as non-null.
BOOST_INTERPROCESS_FORCEINLINE static pointer get_pointer(const pointer &n) BOOST_NOEXCEPT
{
pointer p;
O const tmp_off = n.priv_offset() & O(~Mask);
p.priv_offset() = boost::interprocess::ipcdetail::offset_ptr_to_offset_from_other(&p, &n, tmp_off);
return p;
}
BOOST_INTERPROCESS_FORCEINLINE static void set_pointer(pointer &n, const pointer &p) BOOST_NOEXCEPT
{
BOOST_ASSERT(0 == (get_bits)(p));
O const stored_bits = O(n.priv_offset() & Mask);
n = p;
n.priv_offset() |= stored_bits;
}
BOOST_INTERPROCESS_FORCEINLINE static std::size_t get_bits(const pointer &n) BOOST_NOEXCEPT
{
return std::size_t((n.priv_offset() & Mask) >> 1u);
}
BOOST_INTERPROCESS_FORCEINLINE static void set_bits(pointer &n, std::size_t const b) BOOST_NOEXCEPT
{
BOOST_ASSERT(b < (std::size_t(1) << NumBits));
O tmp = n.priv_offset();
tmp &= O(~Mask);
tmp |= O(b << 1u);
n.priv_offset() = tmp;
}
};
} //namespace intrusive
//Predeclaration
template<class T, class U>
struct pointer_to_other;
//Backwards compatibility with pointer_to_other
template <class PointedType, class DifferenceType, class OffsetType, std::size_t OffsetAlignment, class U>
struct pointer_to_other
< ::boost::interprocess::offset_ptr<PointedType, DifferenceType, OffsetType, OffsetAlignment>, U >
{
typedef ::boost::interprocess::offset_ptr<U, DifferenceType, OffsetType, OffsetAlignment> type;
};
} //namespace boost{
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_OFFSET_PTR_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2012.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DELETER_HPP
#define BOOST_INTERPROCESS_DELETER_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/interprocess_fwd.hpp>
#include <boost/interprocess/detail/utilities.hpp>
#include <boost/intrusive/pointer_traits.hpp>
//!\file
//!Describes the functor to delete objects from the segment.
namespace boost {
namespace interprocess {
//!A deleter that uses the segment manager's destroy_ptr
//!function to destroy the passed pointer resource.
//!
//!This deleter is used
template<class T, class SegmentManager>
class deleter
{
public:
typedef typename boost::intrusive::
pointer_traits<typename SegmentManager::void_pointer>::template
rebind_pointer<T>::type pointer;
private:
typedef typename boost::intrusive::
pointer_traits<pointer>::template
rebind_pointer<SegmentManager>::type segment_manager_pointer;
segment_manager_pointer mp_mngr;
public:
deleter(segment_manager_pointer pmngr)
: mp_mngr(pmngr)
{}
void operator()(const pointer &p)
{ mp_mngr->destroy_ptr(ipcdetail::to_raw_pointer(p)); }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DELETER_HPP

View File

@ -0,0 +1,181 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code:
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/assert.hpp>
#if !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && \
(defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED) && defined (BOOST_INTERPROCESS_POSIX_RECURSIVE_MUTEXES))
#include <boost/interprocess/sync/posix/recursive_mutex.hpp>
#define BOOST_INTERPROCESS_USE_POSIX
//Experimental...
#elif !defined(BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION) && defined (BOOST_INTERPROCESS_WINDOWS)
#include <boost/interprocess/sync/windows/recursive_mutex.hpp>
#define BOOST_INTERPROCESS_USE_WINDOWS
#elif !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
#include <boost/interprocess/sync/spin/recursive_mutex.hpp>
#define BOOST_INTERPROCESS_USE_GENERIC_EMULATION
#endif
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
namespace boost {
namespace interprocess {
namespace ipcdetail{
namespace robust_emulation_helpers {
template<class T>
class mutex_traits;
}}}}
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!\file
//!Describes interprocess_recursive_mutex and shared_recursive_try_mutex classes
namespace boost {
namespace interprocess {
//!Wraps a interprocess_mutex that can be placed in shared memory and can be
//!shared between processes. Allows several locking calls by the same
//!process. Allows timed lock tries
class interprocess_recursive_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
//Non-copyable
interprocess_recursive_mutex(const interprocess_recursive_mutex &);
interprocess_recursive_mutex &operator=(const interprocess_recursive_mutex &);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Throws interprocess_exception on error.
interprocess_recursive_mutex();
//!Destructor. If any process uses the mutex after the destructor is called
//!the result is undefined. Does not throw.
~interprocess_recursive_mutex();
//!Effects: The calling thread tries to obtain ownership of the mutex, and
//! if another thread has ownership of the mutex, it waits until it can
//! obtain the ownership. If a thread takes ownership of the mutex the
//! mutex must be unlocked by the same mutex. The mutex must be unlocked
//! the same number of times it is locked.
//!Throws: interprocess_exception on error.
void lock();
//!Tries to lock the interprocess_mutex, returns false when interprocess_mutex
//!is already locked, returns true when success. The mutex must be unlocked
//!the same number of times it is locked.
//!Throws: interprocess_exception if a severe error is found
bool try_lock();
//!Tries to lock the interprocess_mutex, if interprocess_mutex can't be locked before
//!abs_time time, returns false. The mutex must be unlocked
//! the same number of times it is locked.
//!Throws: interprocess_exception if a severe error is found
bool timed_lock(const boost::posix_time::ptime &abs_time);
//!Effects: The calling thread releases the exclusive ownership of the mutex.
//! If the mutex supports recursive locking, the mutex must be unlocked the
//! same number of times it is locked.
//!Throws: interprocess_exception on error.
void unlock();
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
#if defined (BOOST_INTERPROCESS_USE_GENERIC_EMULATION)
#undef BOOST_INTERPROCESS_USE_GENERIC_EMULATION
void take_ownership(){ mutex.take_ownership(); }
friend class ipcdetail::robust_emulation_helpers::mutex_traits<interprocess_recursive_mutex>;
ipcdetail::spin_recursive_mutex mutex;
#elif defined(BOOST_INTERPROCESS_USE_POSIX)
#undef BOOST_INTERPROCESS_USE_POSIX
ipcdetail::posix_recursive_mutex mutex;
#elif defined(BOOST_INTERPROCESS_USE_WINDOWS)
#undef BOOST_INTERPROCESS_USE_WINDOWS
ipcdetail::windows_recursive_mutex mutex;
#else
#error "Unknown platform for interprocess_mutex"
#endif
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
};
} //namespace interprocess {
} //namespace boost {
namespace boost {
namespace interprocess {
inline interprocess_recursive_mutex::interprocess_recursive_mutex(){}
inline interprocess_recursive_mutex::~interprocess_recursive_mutex(){}
inline void interprocess_recursive_mutex::lock()
{
#ifdef BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING
boost::posix_time::ptime wait_time
= microsec_clock::universal_time()
+ boost::posix_time::milliseconds(BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS);
if (!mutex.timed_lock(wait_time)){
throw interprocess_exception(timeout_when_locking_error, "Interprocess mutex timeout when locking. Possible deadlock: owner died without unlocking?");
}
#else
mutex.lock();
#endif
}
inline bool interprocess_recursive_mutex::try_lock()
{ return mutex.try_lock(); }
inline bool interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{ return mutex.timed_lock(abs_time); }
inline void interprocess_recursive_mutex::unlock()
{ mutex.unlock(); }
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_RECURSIVE_MUTEX_HPP

View File

@ -0,0 +1,60 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
#define BOOST_INTERPROCESS_MUTEX_FAMILY_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/interprocess/sync/null_mutex.hpp>
//!\file
//!Describes a shared interprocess_mutex family fit algorithm used to allocate objects in shared memory.
namespace boost {
namespace interprocess {
//!Describes interprocess_mutex family to use with Interprocess framework
//!based on boost::interprocess synchronization objects.
struct mutex_family
{
typedef boost::interprocess::interprocess_mutex mutex_type;
typedef boost::interprocess::interprocess_recursive_mutex recursive_mutex_type;
};
//!Describes interprocess_mutex family to use with Interprocess frameworks
//!based on null operation synchronization objects.
struct null_mutex_family
{
typedef boost::interprocess::null_mutex mutex_type;
typedef boost::interprocess::null_mutex recursive_mutex_type;
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_MUTEX_FAMILY_HPP

View File

@ -0,0 +1,155 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_NULL_MUTEX_HPP
#define BOOST_INTERPROCESS_NULL_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
//!\file
//!Describes null_mutex classes
namespace boost {
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace posix_time
{ class ptime; }
#endif //#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
namespace interprocess {
//!Implements a mutex that simulates a mutex without doing any operation and
//!simulates a successful operation.
class null_mutex
{
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
null_mutex(const null_mutex&);
null_mutex &operator= (const null_mutex&);
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
//!Constructor.
//!Empty.
null_mutex(){}
//!Destructor.
//!Empty.
~null_mutex(){}
//!Simulates a mutex lock() operation. Empty function.
void lock(){}
//!Simulates a mutex try_lock() operation.
//!Equivalent to "return true;"
bool try_lock()
{ return true; }
//!Simulates a mutex timed_lock() operation.
//!Equivalent to "return true;"
bool timed_lock(const boost::posix_time::ptime &)
{ return true; }
//!Simulates a mutex unlock() operation.
//!Empty function.
void unlock(){}
//!Simulates a mutex lock_sharable() operation.
//!Empty function.
void lock_sharable(){}
//!Simulates a mutex try_lock_sharable() operation.
//!Equivalent to "return true;"
bool try_lock_sharable()
{ return true; }
//!Simulates a mutex timed_lock_sharable() operation.
//!Equivalent to "return true;"
bool timed_lock_sharable(const boost::posix_time::ptime &)
{ return true; }
//!Simulates a mutex unlock_sharable() operation.
//!Empty function.
void unlock_sharable(){}
//!Simulates a mutex lock_upgradable() operation.
//!Empty function.
void lock_upgradable(){}
//!Simulates a mutex try_lock_upgradable() operation.
//!Equivalent to "return true;"
bool try_lock_upgradable()
{ return true; }
//!Simulates a mutex timed_lock_upgradable() operation.
//!Equivalent to "return true;"
bool timed_lock_upgradable(const boost::posix_time::ptime &)
{ return true; }
//!Simulates a mutex unlock_upgradable() operation.
//!Empty function.
void unlock_upgradable(){}
//!Simulates unlock_and_lock_upgradable().
//!Empty function.
void unlock_and_lock_upgradable(){}
//!Simulates unlock_and_lock_sharable().
//!Empty function.
void unlock_and_lock_sharable(){}
//!Simulates unlock_upgradable_and_lock_sharable().
//!Empty function.
void unlock_upgradable_and_lock_sharable(){}
//Promotions
//!Simulates unlock_upgradable_and_lock().
//!Empty function.
void unlock_upgradable_and_lock(){}
//!Simulates try_unlock_upgradable_and_lock().
//!Equivalent to "return true;"
bool try_unlock_upgradable_and_lock()
{ return true; }
//!Simulates timed_unlock_upgradable_and_lock().
//!Equivalent to "return true;"
bool timed_unlock_upgradable_and_lock(const boost::posix_time::ptime &)
{ return true; }
//!Simulates try_unlock_sharable_and_lock().
//!Equivalent to "return true;"
bool try_unlock_sharable_and_lock()
{ return true; }
//!Simulates try_unlock_sharable_and_lock_upgradable().
//!Equivalent to "return true;"
bool try_unlock_sharable_and_lock_upgradable()
{ return true; }
};
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_NULL_MUTEX_HPP

View File

@ -0,0 +1,137 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code:
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/exceptions.hpp>
#ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS
# include <boost/interprocess/detail/os_thread_functions.hpp>
# include <boost/interprocess/sync/detail/common_algorithms.hpp>
#endif
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class posix_recursive_mutex
{
posix_recursive_mutex(const posix_recursive_mutex &);
posix_recursive_mutex &operator=(const posix_recursive_mutex &);
public:
posix_recursive_mutex();
~posix_recursive_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
private:
pthread_mutex_t m_mut;
};
inline posix_recursive_mutex::posix_recursive_mutex()
{
mutexattr_wrapper mut_attr(true);
mutex_initializer mut(m_mut, mut_attr);
mut.release();
}
inline posix_recursive_mutex::~posix_recursive_mutex()
{
int res = pthread_mutex_destroy(&m_mut);
BOOST_ASSERT(res == 0);(void)res;
}
inline void posix_recursive_mutex::lock()
{
if (pthread_mutex_lock(&m_mut) != 0)
throw lock_exception();
}
inline bool posix_recursive_mutex::try_lock()
{
int res = pthread_mutex_trylock(&m_mut);
if (!(res == 0 || res == EBUSY))
throw lock_exception();
return res == 0;
}
inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS
//Posix does not support infinity absolute time so handle it here
if(abs_time == boost::posix_time::pos_infin){
this->lock();
return true;
}
timespec ts = ptime_to_timespec(abs_time);
int res = pthread_mutex_timedlock(&m_mut, &ts);
if (res != 0 && res != ETIMEDOUT)
throw lock_exception();
return res == 0;
#else //BOOST_INTERPROCESS_POSIX_TIMEOUTS
return ipcdetail::try_based_timed_lock(*this, abs_time);
#endif //BOOST_INTERPROCESS_POSIX_TIMEOUTS
}
inline void posix_recursive_mutex::unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mut);
BOOST_ASSERT(res == 0); (void)res;
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //#ifndef BOOST_INTERPROCESS_DETAIL_POSIX_RECURSIVE_MUTEX_HPP

View File

@ -0,0 +1,176 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
//
// Parts of the pthread code come from Boost Threads code:
//
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/exceptions.hpp>
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/cstdint.hpp>
#include <boost/interprocess/detail/os_thread_functions.hpp>
#include <boost/interprocess/sync/spin/mutex.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
class spin_recursive_mutex
{
spin_recursive_mutex(const spin_recursive_mutex &);
spin_recursive_mutex &operator=(const spin_recursive_mutex &);
public:
spin_recursive_mutex();
~spin_recursive_mutex();
void lock();
bool try_lock();
bool timed_lock(const boost::posix_time::ptime &abs_time);
void unlock();
void take_ownership();
private:
spin_mutex m_mutex;
unsigned int m_nLockCount;
volatile ipcdetail::OS_systemwide_thread_id_t m_nOwner;
volatile boost::uint32_t m_s;
};
inline spin_recursive_mutex::spin_recursive_mutex()
: m_nLockCount(0), m_nOwner(ipcdetail::get_invalid_systemwide_thread_id()){}
inline spin_recursive_mutex::~spin_recursive_mutex(){}
inline void spin_recursive_mutex::lock()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)){
if((unsigned int)(m_nLockCount+1) == 0){
//Overflow, throw an exception
throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow");
}
++m_nLockCount;
}
else{
m_mutex.lock();
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
m_nLockCount = 1;
}
}
inline bool spin_recursive_mutex::try_lock()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
if((unsigned int)(m_nLockCount+1) == 0){
//Overflow, throw an exception
throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow");
}
++m_nLockCount;
return true;
}
if(m_mutex.try_lock()){
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
m_nLockCount = 1;
return true;
}
return false;
}
inline bool spin_recursive_mutex::timed_lock(const boost::posix_time::ptime &abs_time)
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
if(ipcdetail::equal_systemwide_thread_id(thr_id , old_id)) { // we own it
if((unsigned int)(m_nLockCount+1) == 0){
//Overflow, throw an exception
throw interprocess_exception("boost::interprocess::spin_recursive_mutex recursive lock overflow");
}
++m_nLockCount;
return true;
}
//m_mutex supports abs_time so no need to check it
if(m_mutex.timed_lock(abs_time)){
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
m_nLockCount = 1;
return true;
}
return false;
}
inline void spin_recursive_mutex::unlock()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
handle_t old_id;
ipcdetail::systemwide_thread_id_copy(m_nOwner, old_id);
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
(void)old_id;
(void)thr_id;
BOOST_ASSERT(ipcdetail::equal_systemwide_thread_id(thr_id, old_id));
--m_nLockCount;
if(!m_nLockCount){
const handle_t new_id(ipcdetail::get_invalid_systemwide_thread_id());
ipcdetail::systemwide_thread_id_copy(new_id, m_nOwner);
m_mutex.unlock();
}
}
inline void spin_recursive_mutex::take_ownership()
{
typedef ipcdetail::OS_systemwide_thread_id_t handle_t;
this->m_nLockCount = 1;
const handle_t thr_id(ipcdetail::get_current_systemwide_thread_id());
ipcdetail::systemwide_thread_id_copy(thr_id, m_nOwner);
}
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_SPIN_RECURSIVE_MUTEX_HPP

View File

@ -0,0 +1,47 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP
#define BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>
#include <boost/interprocess/sync/windows/mutex.hpp>
namespace boost {
namespace interprocess {
namespace ipcdetail {
//Windows mutex is already recursive
class windows_recursive_mutex
: public windows_mutex
{
windows_recursive_mutex(const windows_recursive_mutex &);
windows_recursive_mutex &operator=(const windows_recursive_mutex &);
public:
windows_recursive_mutex() : windows_mutex() {}
};
} //namespace ipcdetail {
} //namespace interprocess {
} //namespace boost {
#include <boost/interprocess/detail/config_end.hpp>
#endif //BOOST_INTERPROCESS_DETAIL_WINDOWS_RECURSIVE_MUTEX_HPP

View File

@ -0,0 +1,338 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_ANY_HOOK_HPP
#define BOOST_INTRUSIVE_ANY_HOOK_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/any_node_and_algorithms.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/generic_hook.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/pointer_rebind.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//! Helper metafunction to define a \c \c any_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void>
#endif
struct make_any_base_hook
{
/// @cond
typedef typename pack_options
< hook_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3
#else
Options...
#endif
>::type packed_options;
typedef generic_hook
< AnyAlgorithm
, any_node_traits<typename packed_options::void_pointer>
, typename packed_options::tag
, packed_options::link_mode
, AnyBaseHookId
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Derive a class from this hook in order to store objects of that class
//! in an intrusive container.
//!
//! The hook admits the following options: \c tag<>, \c void_pointer<> and
//! \c link_mode<>.
//!
//! \c tag<> defines a tag to identify the node.
//! The same tag value can be used in different classes, but if a class is
//! derived from more than one \c any_base_hook, then each \c any_base_hook needs its
//! unique tag.
//!
//! \c link_mode<> will specify the linking mode of the hook (\c normal_link, \c safe_link).
//!
//! \c void_pointer<> is the pointer type that will be used internally in the hook
//! and the container configured to use this hook.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1, class O2, class O3>
#endif
class any_base_hook
: public make_any_base_hook
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
<O1, O2, O3>
#else
<Options...>
#endif
::type
{
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
public:
//! <b>Effects</b>: If link_mode is or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
any_base_hook();
//! <b>Effects</b>: If link_mode is or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
any_base_hook(const any_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
any_base_hook& operator=(const any_base_hook& );
//! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in a container an assertion is raised.
//!
//! <b>Throws</b>: Nothing.
~any_base_hook();
//! <b>Precondition</b>: link_mode must be \c safe_link.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c container::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
#endif
};
//! Helper metafunction to define a \c \c any_member_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void>
#endif
struct make_any_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3
#else
Options...
#endif
>::type packed_options;
typedef generic_hook
< AnyAlgorithm
, any_node_traits<typename packed_options::void_pointer>
, member_tag
, packed_options::link_mode
, NoBaseHookId
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Store this hook in a class to be inserted
//! in an intrusive container.
//!
//! The hook admits the following options: \c void_pointer<> and
//! \c link_mode<>.
//!
//! \c link_mode<> will specify the linking mode of the hook (\c normal_link or \c safe_link).
//!
//! \c void_pointer<> is the pointer type that will be used internally in the hook
//! and the container configured to use this hook.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1, class O2, class O3>
#endif
class any_member_hook
: public make_any_member_hook
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
<O1, O2, O3>
#else
<Options...>
#endif
::type
{
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
public:
//! <b>Effects</b>: If link_mode is or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
any_member_hook();
//! <b>Effects</b>: If link_mode is or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
any_member_hook(const any_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
any_member_hook& operator=(const any_member_hook& );
//! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in a container an assertion is raised.
//!
//! <b>Throws</b>: Nothing.
~any_member_hook();
//! <b>Precondition</b>: link_mode must be \c safe_link.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c container::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
#endif
};
/// @cond
namespace detail{
BOOST_INTRUSIVE_INTERNAL_STATIC_BOOL_IS_TRUE(old_proto_value_traits_base_hook, hooktags::is_base_hook)
//!This option setter specifies that the container
//!must use the specified base hook
template<class BasicHook, template <class> class NodeTraits>
struct any_to_some_hook
{
typedef typename BasicHook::template pack<empty>::proto_value_traits old_proto_value_traits;
template<class Base>
struct pack : public Base
{
struct proto_value_traits
{
//proto_value_traits::hooktags::is_base_hook is used by get_value_traits
//to detect base hooks, so mark it in case BasicHook has it.
struct hooktags
{
static const bool is_base_hook = old_proto_value_traits_base_hook_bool_is_true
<old_proto_value_traits>::value;
};
typedef old_proto_value_traits basic_hook_t;
static const bool is_any_hook = true;
template<class VoidPtr>
struct node_traits_from_voidptr
{ typedef NodeTraits<VoidPtr> type; };
};
};
};
} //namespace detail{
/// @endcond
//!This option setter specifies that
//!any hook should behave as an slist hook
template<class BasicHook>
struct any_to_slist_hook
/// @cond
: public detail::any_to_some_hook<BasicHook, any_slist_node_traits>
/// @endcond
{};
//!This option setter specifies that
//!any hook should behave as an list hook
template<class BasicHook>
struct any_to_list_hook
/// @cond
: public detail::any_to_some_hook<BasicHook, any_list_node_traits>
/// @endcond
{};
//!This option setter specifies that
//!any hook should behave as a set hook
template<class BasicHook>
struct any_to_set_hook
/// @cond
: public detail::any_to_some_hook<BasicHook, any_rbtree_node_traits>
/// @endcond
{};
//!This option setter specifies that
//!any hook should behave as an avl_set hook
template<class BasicHook>
struct any_to_avl_set_hook
/// @cond
: public detail::any_to_some_hook<BasicHook, any_avltree_node_traits>
/// @endcond
{};
//!This option setter specifies that any
//!hook should behave as a bs_set hook
template<class BasicHook>
struct any_to_bs_set_hook
/// @cond
: public detail::any_to_some_hook<BasicHook, any_tree_node_traits>
/// @endcond
{};
//!This option setter specifies that any hook
//!should behave as an unordered set hook
template<class BasicHook>
struct any_to_unordered_set_hook
/// @cond
: public detail::any_to_some_hook<BasicHook, any_unordered_node_traits>
/// @endcond
{};
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_ANY_HOOK_HPP

1073
boost/intrusive/avl_set.hpp Normal file

File diff suppressed because it is too large Load Diff

1069
boost/intrusive/bs_set.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,468 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2014
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP
#define BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/algo_type.hpp>
#include <boost/core/no_exceptions_support.hpp>
#include <cstddef>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//! circular_list_algorithms provides basic algorithms to manipulate nodes
//! forming a circular doubly linked list. An empty circular list is formed by a node
//! whose pointers point to itself.
//!
//! circular_list_algorithms is configured with a NodeTraits class, which encapsulates the
//! information about the node to be manipulated. NodeTraits must support the
//! following interface:
//!
//! <b>Typedefs</b>:
//!
//! <tt>node</tt>: The type of the node that forms the circular list
//!
//! <tt>node_ptr</tt>: A pointer to a node
//!
//! <tt>const_node_ptr</tt>: A pointer to a const node
//!
//! <b>Static functions</b>:
//!
//! <tt>static node_ptr get_previous(const_node_ptr n);</tt>
//!
//! <tt>static void set_previous(node_ptr n, node_ptr prev);</tt>
//!
//! <tt>static node_ptr get_next(const_node_ptr n);</tt>
//!
//! <tt>static void set_next(node_ptr n, node_ptr next);</tt>
template<class NodeTraits>
class circular_list_algorithms
{
public:
typedef typename NodeTraits::node node;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
typedef NodeTraits node_traits;
//! <b>Effects</b>: Constructs an non-used list element, so that
//! inited(this_node) == true
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static void init(const node_ptr &this_node)
{
const node_ptr null_node((node_ptr()));
NodeTraits::set_next(this_node, null_node);
NodeTraits::set_previous(this_node, null_node);
}
//! <b>Effects</b>: Returns true is "this_node" is in a non-used state
//! as if it was initialized by the "init" function.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static bool inited(const const_node_ptr &this_node)
{ return !NodeTraits::get_next(this_node); }
//! <b>Effects</b>: Constructs an empty list, making this_node the only
//! node of the circular list:
//! <tt>NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node)
//! == this_node</tt>.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static void init_header(const node_ptr &this_node)
{
NodeTraits::set_next(this_node, this_node);
NodeTraits::set_previous(this_node, this_node);
}
//! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
//!
//! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:
//! <tt>return NodeTraits::get_next(this_node) == this_node</tt>
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static bool unique(const const_node_ptr &this_node)
{
node_ptr next = NodeTraits::get_next(this_node);
return !next || next == this_node;
}
//! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
//!
//! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list
//! is empty, returns 1.
//!
//! <b>Complexity</b>: Linear
//!
//! <b>Throws</b>: Nothing.
static std::size_t count(const const_node_ptr &this_node)
{
std::size_t result = 0;
const_node_ptr p = this_node;
do{
p = NodeTraits::get_next(p);
++result;
}while (p != this_node);
return result;
}
//! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
//!
//! <b>Effects</b>: Unlinks the node from the circular list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static node_ptr unlink(const node_ptr &this_node)
{
node_ptr next(NodeTraits::get_next(this_node));
node_ptr prev(NodeTraits::get_previous(this_node));
NodeTraits::set_next(prev, next);
NodeTraits::set_previous(next, prev);
return next;
}
//! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
//!
//! <b>Effects</b>: Unlinks the node [b, e) from the circular list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static void unlink(const node_ptr &b, const node_ptr &e)
{
if (b != e) {
node_ptr prevb(NodeTraits::get_previous(b));
NodeTraits::set_previous(e, prevb);
NodeTraits::set_next(prevb, e);
}
}
//! <b>Requires</b>: nxt_node must be a node of a circular list.
//!
//! <b>Effects</b>: Links this_node before nxt_node in the circular list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static void link_before(const node_ptr &nxt_node, const node_ptr &this_node)
{
node_ptr prev(NodeTraits::get_previous(nxt_node));
NodeTraits::set_previous(this_node, prev);
NodeTraits::set_next(this_node, nxt_node);
//nxt_node might be an alias for prev->next_
//so use it before NodeTraits::set_next(prev, ...)
//is called and the reference changes its value
NodeTraits::set_previous(nxt_node, this_node);
NodeTraits::set_next(prev, this_node);
}
//! <b>Requires</b>: prev_node must be a node of a circular list.
//!
//! <b>Effects</b>: Links this_node after prev_node in the circular list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static void link_after(const node_ptr &prev_node, const node_ptr &this_node)
{
node_ptr next(NodeTraits::get_next(prev_node));
NodeTraits::set_previous(this_node, prev_node);
NodeTraits::set_next(this_node, next);
//prev_node might be an alias for next->next_
//so use it before update it before NodeTraits::set_previous(next, ...)
//is called and the reference changes it's value
NodeTraits::set_next(prev_node, this_node);
NodeTraits::set_previous(next, this_node);
}
//! <b>Requires</b>: this_node and other_node must be nodes inserted
//! in circular lists or be empty circular lists.
//!
//! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in
//! other_nodes position in the second circular list and the other_node is inserted
//! in this_node's position in the first circular list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
static void swap_nodes(const node_ptr &this_node, const node_ptr &other_node)
{
if (other_node == this_node)
return;
bool this_inited = inited(this_node);
bool other_inited = inited(other_node);
if(this_inited){
init_header(this_node);
}
if(other_inited){
init_header(other_node);
}
node_ptr next_this(NodeTraits::get_next(this_node));
node_ptr prev_this(NodeTraits::get_previous(this_node));
node_ptr next_other(NodeTraits::get_next(other_node));
node_ptr prev_other(NodeTraits::get_previous(other_node));
//these first two swaps must happen before the other two
swap_prev(next_this, next_other);
swap_next(prev_this, prev_other);
swap_next(this_node, other_node);
swap_prev(this_node, other_node);
if(this_inited){
init(other_node);
}
if(other_inited){
init(this_node);
}
}
//! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
//! and p must be a node of a different circular list or may not be an iterator in
// [b, e).
//!
//! <b>Effects</b>: Removes the nodes from [b, e) range from their circular list and inserts
//! them before p in p's circular list.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
static void transfer(const node_ptr &p, const node_ptr &b, const node_ptr &e)
{
if (b != e) {
node_ptr prev_p(NodeTraits::get_previous(p));
node_ptr prev_b(NodeTraits::get_previous(b));
node_ptr prev_e(NodeTraits::get_previous(e));
NodeTraits::set_next(prev_e, p);
NodeTraits::set_previous(p, prev_e);
NodeTraits::set_next(prev_b, e);
NodeTraits::set_previous(e, prev_b);
NodeTraits::set_next(prev_p, b);
NodeTraits::set_previous(b, prev_p);
}
}
//! <b>Requires</b>: i must a node of a circular list
//! and p must be a node of a different circular list.
//!
//! <b>Effects</b>: Removes the node i from its circular list and inserts
//! it before p in p's circular list.
//! If p == i or p == NodeTraits::get_next(i), this function is a null operation.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
static void transfer(const node_ptr &p, const node_ptr &i)
{
node_ptr n(NodeTraits::get_next(i));
if(n != p && i != p){
node_ptr prev_p(NodeTraits::get_previous(p));
node_ptr prev_i(NodeTraits::get_previous(i));
NodeTraits::set_next(prev_p, i);
NodeTraits::set_previous(i, prev_p);
NodeTraits::set_next(i, p);
NodeTraits::set_previous(p, i);
NodeTraits::set_previous(n, prev_i);
NodeTraits::set_next(prev_i, n);
}
}
//! <b>Effects</b>: Reverses the order of elements in the list.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: This function is linear time.
static void reverse(const node_ptr &p)
{
node_ptr f(NodeTraits::get_next(p));
node_ptr i(NodeTraits::get_next(f)), e(p);
while(i != e) {
node_ptr n = i;
i = NodeTraits::get_next(i);
transfer(f, n, i);
f = n;
}
}
//! <b>Effects</b>: Moves the node p n positions towards the end of the list.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the number of moved positions.
static void move_backwards(const node_ptr &p, std::size_t n)
{
//Null shift, nothing to do
if(!n) return;
node_ptr first = NodeTraits::get_next(p);
//size() == 0 or 1, nothing to do
if(first == NodeTraits::get_previous(p)) return;
unlink(p);
//Now get the new first node
while(n--){
first = NodeTraits::get_next(first);
}
link_before(first, p);
}
//! <b>Effects</b>: Moves the node p n positions towards the beginning of the list.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Complexity</b>: Linear to the number of moved positions.
static void move_forward(const node_ptr &p, std::size_t n)
{
//Null shift, nothing to do
if(!n) return;
node_ptr last = NodeTraits::get_previous(p);
//size() == 0 or 1, nothing to do
if(last == NodeTraits::get_next(p)) return;
unlink(p);
//Now get the new last node
while(n--){
last = NodeTraits::get_previous(last);
}
link_after(last, p);
}
//! <b>Requires</b>: f and l must be in a circular list.
//!
//! <b>Effects</b>: Returns the number of nodes in the range [f, l).
//!
//! <b>Complexity</b>: Linear
//!
//! <b>Throws</b>: Nothing.
static std::size_t distance(const const_node_ptr &f, const const_node_ptr &l)
{
const_node_ptr i(f);
std::size_t result = 0;
while(i != l){
i = NodeTraits::get_next(i);
++result;
}
return result;
}
struct stable_partition_info
{
std::size_t num_1st_partition;
std::size_t num_2nd_partition;
node_ptr beg_2st_partition;
};
template<class Pred>
static void stable_partition(node_ptr beg, const node_ptr &end, Pred pred, stable_partition_info &info)
{
node_ptr bcur = node_traits::get_previous(beg);
node_ptr cur = beg;
node_ptr new_f = end;
std::size_t num1 = 0, num2 = 0;
while(cur != end){
if(pred(cur)){
++num1;
bcur = cur;
cur = node_traits::get_next(cur);
}
else{
++num2;
node_ptr last_to_remove = bcur;
new_f = cur;
bcur = cur;
cur = node_traits::get_next(cur);
BOOST_TRY{
//Main loop
while(cur != end){
if(pred(cur)){ //Might throw
++num1;
//Process current node
node_traits::set_next (last_to_remove, cur);
node_traits::set_previous(cur, last_to_remove);
last_to_remove = cur;
node_ptr nxt = node_traits::get_next(cur);
node_traits::set_next (bcur, nxt);
node_traits::set_previous(nxt, bcur);
cur = nxt;
}
else{
++num2;
bcur = cur;
cur = node_traits::get_next(cur);
}
}
}
BOOST_CATCH(...){
node_traits::set_next (last_to_remove, new_f);
node_traits::set_previous(new_f, last_to_remove);
BOOST_RETHROW;
}
BOOST_CATCH_END
node_traits::set_next(last_to_remove, new_f);
node_traits::set_previous(new_f, last_to_remove);
break;
}
}
info.num_1st_partition = num1;
info.num_2nd_partition = num2;
info.beg_2st_partition = new_f;
}
private:
BOOST_INTRUSIVE_FORCEINLINE static void swap_prev(const node_ptr &this_node, const node_ptr &other_node)
{
node_ptr temp(NodeTraits::get_previous(this_node));
NodeTraits::set_previous(this_node, NodeTraits::get_previous(other_node));
NodeTraits::set_previous(other_node, temp);
}
BOOST_INTRUSIVE_FORCEINLINE static void swap_next(const node_ptr &this_node, const node_ptr &other_node)
{
node_ptr temp(NodeTraits::get_next(this_node));
NodeTraits::set_next(this_node, NodeTraits::get_next(other_node));
NodeTraits::set_next(other_node, temp);
}
};
/// @cond
template<class NodeTraits>
struct get_algo<CircularListAlgorithms, NodeTraits>
{
typedef circular_list_algorithms<NodeTraits> type;
};
/// @endcond
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP

View File

@ -0,0 +1,77 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type will
//!derive from node_traits::node
template<class T, class NodeTraits, link_mode_type LinkMode
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
= safe_link
#endif
>
struct derivation_value_traits
{
public:
typedef NodeTraits node_traits;
typedef T value_type;
typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef typename pointer_traits<node_ptr>::
template rebind_pointer<value_type>::type pointer;
typedef typename pointer_traits<node_ptr>::
template rebind_pointer<const value_type>::type const_pointer;
typedef typename boost::intrusive::
pointer_traits<pointer>::reference reference;
typedef typename boost::intrusive::
pointer_traits<const_pointer>::reference const_reference;
static const link_mode_type link_mode = LinkMode;
static node_ptr to_node_ptr(reference value)
{ return node_ptr(&value); }
static const_node_ptr to_node_ptr(const_reference value)
{ return node_ptr(&value); }
static pointer to_value_ptr(const node_ptr &n)
{
return pointer_traits<pointer>::pointer_to(static_cast<reference>(*n));
}
static const_pointer to_value_ptr(const const_node_ptr &n)
{
return pointer_traits<pointer>::pointer_to(static_cast<const_reference>(*n));
}
};
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_DERIVATION_VALUE_TRAITS_HPP

View File

@ -0,0 +1,297 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2014
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_ANY_NODE_HPP
#define BOOST_INTRUSIVE_ANY_NODE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/pointer_rebind.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/algo_type.hpp>
#include <cstddef>
namespace boost {
namespace intrusive {
template<class VoidPointer>
struct any_node
{
typedef any_node node;
typedef typename pointer_rebind<VoidPointer, node>::type node_ptr;
typedef typename pointer_rebind<VoidPointer, const node>::type const_node_ptr;
node_ptr node_ptr_1;
node_ptr node_ptr_2;
node_ptr node_ptr_3;
std::size_t size_t_1;
};
template<class VoidPointer>
struct any_list_node_traits
{
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const const_node_ptr & n)
{ return n->node_ptr_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_next(const node_ptr & n, const node_ptr & next)
{ n->node_ptr_1 = next; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous(const const_node_ptr & n)
{ return n->node_ptr_2; }
BOOST_INTRUSIVE_FORCEINLINE static void set_previous(const node_ptr & n, const node_ptr & prev)
{ n->node_ptr_2 = prev; }
};
template<class VoidPointer>
struct any_slist_node_traits
{
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const const_node_ptr & n)
{ return n->node_ptr_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_next(const node_ptr & n, const node_ptr & next)
{ n->node_ptr_1 = next; }
};
template<class VoidPointer>
struct any_unordered_node_traits
: public any_slist_node_traits<VoidPointer>
{
typedef any_slist_node_traits<VoidPointer> reduced_slist_node_traits;
typedef typename reduced_slist_node_traits::node node;
typedef typename reduced_slist_node_traits::node_ptr node_ptr;
typedef typename reduced_slist_node_traits::const_node_ptr const_node_ptr;
static const bool store_hash = true;
static const bool optimize_multikey = true;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const const_node_ptr & n)
{ return n->node_ptr_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_next(const node_ptr & n, const node_ptr & next)
{ n->node_ptr_1 = next; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_prev_in_group(const const_node_ptr & n)
{ return n->node_ptr_2; }
BOOST_INTRUSIVE_FORCEINLINE static void set_prev_in_group(const node_ptr & n, const node_ptr & prev)
{ n->node_ptr_2 = prev; }
BOOST_INTRUSIVE_FORCEINLINE static std::size_t get_hash(const const_node_ptr & n)
{ return n->size_t_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_hash(const node_ptr & n, std::size_t h)
{ n->size_t_1 = h; }
};
template<class VoidPointer>
struct any_rbtree_node_traits
{
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
typedef std::size_t color;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_parent(const const_node_ptr & n)
{ return n->node_ptr_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_parent(const node_ptr & n, const node_ptr & p)
{ n->node_ptr_1 = p; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_left(const const_node_ptr & n)
{ return n->node_ptr_2; }
BOOST_INTRUSIVE_FORCEINLINE static void set_left(const node_ptr & n, const node_ptr & l)
{ n->node_ptr_2 = l; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_right(const const_node_ptr & n)
{ return n->node_ptr_3; }
BOOST_INTRUSIVE_FORCEINLINE static void set_right(const node_ptr & n, const node_ptr & r)
{ n->node_ptr_3 = r; }
BOOST_INTRUSIVE_FORCEINLINE static color get_color(const const_node_ptr & n)
{ return n->size_t_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_color(const node_ptr & n, color c)
{ n->size_t_1 = c; }
BOOST_INTRUSIVE_FORCEINLINE static color black()
{ return 0u; }
BOOST_INTRUSIVE_FORCEINLINE static color red()
{ return 1u; }
};
template<class VoidPointer>
struct any_avltree_node_traits
{
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
typedef std::size_t balance;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_parent(const const_node_ptr & n)
{ return n->node_ptr_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_parent(const node_ptr & n, const node_ptr & p)
{ n->node_ptr_1 = p; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_left(const const_node_ptr & n)
{ return n->node_ptr_2; }
BOOST_INTRUSIVE_FORCEINLINE static void set_left(const node_ptr & n, const node_ptr & l)
{ n->node_ptr_2 = l; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_right(const const_node_ptr & n)
{ return n->node_ptr_3; }
BOOST_INTRUSIVE_FORCEINLINE static void set_right(const node_ptr & n, const node_ptr & r)
{ n->node_ptr_3 = r; }
BOOST_INTRUSIVE_FORCEINLINE static balance get_balance(const const_node_ptr & n)
{ return n->size_t_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_balance(const node_ptr & n, balance b)
{ n->size_t_1 = b; }
BOOST_INTRUSIVE_FORCEINLINE static balance negative()
{ return 0u; }
BOOST_INTRUSIVE_FORCEINLINE static balance zero()
{ return 1u; }
BOOST_INTRUSIVE_FORCEINLINE static balance positive()
{ return 2u; }
};
template<class VoidPointer>
struct any_tree_node_traits
{
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_parent(const const_node_ptr & n)
{ return n->node_ptr_1; }
BOOST_INTRUSIVE_FORCEINLINE static void set_parent(const node_ptr & n, const node_ptr & p)
{ n->node_ptr_1 = p; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_left(const const_node_ptr & n)
{ return n->node_ptr_2; }
BOOST_INTRUSIVE_FORCEINLINE static void set_left(const node_ptr & n, const node_ptr & l)
{ n->node_ptr_2 = l; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_right(const const_node_ptr & n)
{ return n->node_ptr_3; }
BOOST_INTRUSIVE_FORCEINLINE static void set_right(const node_ptr & n, const node_ptr & r)
{ n->node_ptr_3 = r; }
};
template<class VoidPointer>
class any_node_traits
{
public:
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
};
template<class VoidPointer>
class any_algorithms
{
template <class T>
static void function_not_available_for_any_hooks(typename detail::enable_if<detail::is_same<T, bool> >::type)
{}
public:
typedef any_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename node::const_node_ptr const_node_ptr;
typedef any_node_traits<VoidPointer> node_traits;
//! <b>Requires</b>: node must not be part of any tree.
//!
//! <b>Effects</b>: After the function unique(node) == true.
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Nodes</b>: If node is inserted in a tree, this function corrupts the tree.
BOOST_INTRUSIVE_FORCEINLINE static void init(const node_ptr & node)
{ node->node_ptr_1 = node_ptr(); };
//! <b>Effects</b>: Returns true if node is in the same state as if called init(node)
//!
//! <b>Complexity</b>: Constant.
//!
//! <b>Throws</b>: Nothing.
BOOST_INTRUSIVE_FORCEINLINE static bool inited(const const_node_ptr & node)
{ return !node->node_ptr_1; };
BOOST_INTRUSIVE_FORCEINLINE static bool unique(const const_node_ptr & node)
{ return !node->node_ptr_1; }
static void unlink(const node_ptr &)
{
//Auto-unlink hooks and unlink() are not available for any hooks
any_algorithms<VoidPointer>::template function_not_available_for_any_hooks<node_ptr>();
}
static void swap_nodes(const node_ptr &, const node_ptr &)
{
//Any nodes have no swap_nodes capability because they don't know
//what algorithm they must use to unlink the node from the container
any_algorithms<VoidPointer>::template function_not_available_for_any_hooks<node_ptr>();
}
};
///@cond
template<class NodeTraits>
struct get_algo<AnyAlgorithm, NodeTraits>
{
typedef typename pointer_rebind<typename NodeTraits::node_ptr, void>::type void_pointer;
typedef any_algorithms<void_pointer> type;
};
///@endcond
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_ANY_NODE_HPP

View File

@ -0,0 +1,286 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2014
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_HASHTABLE_NODE_HPP
#define BOOST_INTRUSIVE_HASHTABLE_NODE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/trivial_value_traits.hpp>
#include <boost/intrusive/slist.hpp> //make_slist
#include <cstddef>
#include <climits>
#include <boost/move/core.hpp>
namespace boost {
namespace intrusive {
namespace detail {
template <class Slist>
struct bucket_impl : public Slist
{
typedef Slist slist_type;
BOOST_INTRUSIVE_FORCEINLINE bucket_impl()
{}
BOOST_INTRUSIVE_FORCEINLINE bucket_impl(const bucket_impl &)
{}
BOOST_INTRUSIVE_FORCEINLINE ~bucket_impl()
{
//This bucket is still being used!
BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
}
BOOST_INTRUSIVE_FORCEINLINE bucket_impl &operator=(const bucket_impl&)
{
//This bucket is still in use!
BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
return *this;
}
};
template<class Slist>
struct bucket_traits_impl
{
private:
BOOST_COPYABLE_AND_MOVABLE(bucket_traits_impl)
public:
/// @cond
typedef typename pointer_traits
<typename Slist::pointer>::template rebind_pointer
< bucket_impl<Slist> >::type bucket_ptr;
typedef Slist slist;
typedef typename Slist::size_type size_type;
/// @endcond
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(bucket_ptr buckets, size_type len)
: buckets_(buckets), buckets_len_(len)
{}
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(const bucket_traits_impl &x)
: buckets_(x.buckets_), buckets_len_(x.buckets_len_)
{}
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(BOOST_RV_REF(bucket_traits_impl) x)
: buckets_(x.buckets_), buckets_len_(x.buckets_len_)
{ x.buckets_ = bucket_ptr(); x.buckets_len_ = 0; }
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl& operator=(BOOST_RV_REF(bucket_traits_impl) x)
{
buckets_ = x.buckets_; buckets_len_ = x.buckets_len_;
x.buckets_ = bucket_ptr(); x.buckets_len_ = 0; return *this;
}
BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl& operator=(BOOST_COPY_ASSIGN_REF(bucket_traits_impl) x)
{
buckets_ = x.buckets_; buckets_len_ = x.buckets_len_; return *this;
}
BOOST_INTRUSIVE_FORCEINLINE const bucket_ptr &bucket_begin() const
{ return buckets_; }
BOOST_INTRUSIVE_FORCEINLINE size_type bucket_count() const
{ return buckets_len_; }
private:
bucket_ptr buckets_;
size_type buckets_len_;
};
template <class NodeTraits>
struct hash_reduced_slist_node_traits
{
template <class U> static detail::no_type test(...);
template <class U> static detail::yes_type test(typename U::reduced_slist_node_traits*);
static const bool value = sizeof(test<NodeTraits>(0)) == sizeof(detail::yes_type);
};
template <class NodeTraits>
struct apply_reduced_slist_node_traits
{
typedef typename NodeTraits::reduced_slist_node_traits type;
};
template <class NodeTraits>
struct reduced_slist_node_traits
{
typedef typename detail::eval_if_c
< hash_reduced_slist_node_traits<NodeTraits>::value
, apply_reduced_slist_node_traits<NodeTraits>
, detail::identity<NodeTraits>
>::type type;
};
template<class NodeTraits>
struct get_slist_impl
{
typedef trivial_value_traits<NodeTraits, normal_link> trivial_traits;
//Reducing symbol length
struct type : make_slist
< typename NodeTraits::node
, boost::intrusive::value_traits<trivial_traits>
, boost::intrusive::constant_time_size<false>
, boost::intrusive::size_type<std::size_t>
>::type
{};
};
} //namespace detail {
template<class BucketValueTraits, bool IsConst>
class hashtable_iterator
{
typedef typename BucketValueTraits::value_traits value_traits;
typedef typename BucketValueTraits::bucket_traits bucket_traits;
typedef iiterator< value_traits, IsConst
, std::forward_iterator_tag> types_t;
public:
typedef typename types_t::iterator_type::difference_type difference_type;
typedef typename types_t::iterator_type::value_type value_type;
typedef typename types_t::iterator_type::pointer pointer;
typedef typename types_t::iterator_type::reference reference;
typedef typename types_t::iterator_type::iterator_category iterator_category;
private:
typedef typename value_traits::node_traits node_traits;
typedef typename node_traits::node_ptr node_ptr;
typedef typename detail::get_slist_impl
< typename detail::reduced_slist_node_traits
<node_traits>::type >::type slist_impl;
typedef typename slist_impl::iterator siterator;
typedef typename slist_impl::const_iterator const_siterator;
typedef detail::bucket_impl<slist_impl> bucket_type;
typedef typename pointer_traits
<pointer>::template rebind_pointer
< const BucketValueTraits >::type const_bucketvaltraits_ptr;
typedef typename slist_impl::size_type size_type;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr downcast_bucket(typename bucket_type::node_ptr p)
{
return pointer_traits<node_ptr>::
pointer_to(static_cast<typename node_traits::node&>(*p));
}
public:
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator ()
: slist_it_() //Value initialization to achieve "null iterators" (N3644)
{}
explicit hashtable_iterator(siterator ptr, const BucketValueTraits *cont)
: slist_it_ (ptr)
, traitsptr_ (cont ? pointer_traits<const_bucketvaltraits_ptr>::pointer_to(*cont) : const_bucketvaltraits_ptr() )
{}
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator(const hashtable_iterator<BucketValueTraits, false> &other)
: slist_it_(other.slist_it()), traitsptr_(other.get_bucket_value_traits())
{}
BOOST_INTRUSIVE_FORCEINLINE const siterator &slist_it() const
{ return slist_it_; }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator<BucketValueTraits, false> unconst() const
{ return hashtable_iterator<BucketValueTraits, false>(this->slist_it(), this->get_bucket_value_traits()); }
BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator& operator++()
{ this->increment(); return *this; }
hashtable_iterator operator++(int)
{
hashtable_iterator result (*this);
this->increment();
return result;
}
BOOST_INTRUSIVE_FORCEINLINE friend bool operator== (const hashtable_iterator& i, const hashtable_iterator& i2)
{ return i.slist_it_ == i2.slist_it_; }
BOOST_INTRUSIVE_FORCEINLINE friend bool operator!= (const hashtable_iterator& i, const hashtable_iterator& i2)
{ return !(i == i2); }
BOOST_INTRUSIVE_FORCEINLINE reference operator*() const
{ return *this->operator ->(); }
BOOST_INTRUSIVE_FORCEINLINE pointer operator->() const
{
return this->priv_value_traits().to_value_ptr
(downcast_bucket(slist_it_.pointed_node()));
}
BOOST_INTRUSIVE_FORCEINLINE const const_bucketvaltraits_ptr &get_bucket_value_traits() const
{ return traitsptr_; }
BOOST_INTRUSIVE_FORCEINLINE const value_traits &priv_value_traits() const
{ return traitsptr_->priv_value_traits(); }
BOOST_INTRUSIVE_FORCEINLINE const bucket_traits &priv_bucket_traits() const
{ return traitsptr_->priv_bucket_traits(); }
private:
void increment()
{
const bucket_traits &rbuck_traits = this->priv_bucket_traits();
bucket_type* const buckets = boost::intrusive::detail::to_raw_pointer(rbuck_traits.bucket_begin());
const size_type buckets_len = rbuck_traits.bucket_count();
++slist_it_;
const typename slist_impl::node_ptr n = slist_it_.pointed_node();
const siterator first_bucket_bbegin = buckets->end();
if(first_bucket_bbegin.pointed_node() <= n && n <= buckets[buckets_len-1].cend().pointed_node()){
//If one-past the node is inside the bucket then look for the next non-empty bucket
//1. get the bucket_impl from the iterator
const bucket_type &b = static_cast<const bucket_type&>
(bucket_type::slist_type::container_from_end_iterator(slist_it_));
//2. Now just calculate the index b has in the bucket array
size_type n_bucket = static_cast<size_type>(&b - buckets);
//3. Iterate until a non-empty bucket is found
do{
if (++n_bucket >= buckets_len){ //bucket overflow, return end() iterator
slist_it_ = buckets->before_begin();
return;
}
}
while (buckets[n_bucket].empty());
slist_it_ = buckets[n_bucket].begin();
}
else{
//++slist_it_ yield to a valid object
}
}
siterator slist_it_;
const_bucketvaltraits_ptr traitsptr_;
};
} //namespace intrusive {
} //namespace boost {
#endif

View File

@ -0,0 +1,134 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_LIST_ITERATOR_HPP
#define BOOST_INTRUSIVE_LIST_ITERATOR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/detail/std_fwd.hpp>
#include <boost/intrusive/detail/iiterator.hpp>
#include <boost/intrusive/detail/mpl.hpp>
namespace boost {
namespace intrusive {
// list_iterator provides some basic functions for a
// node oriented bidirectional iterator:
template<class ValueTraits, bool IsConst>
class list_iterator
{
private:
typedef iiterator
<ValueTraits, IsConst, std::bidirectional_iterator_tag> types_t;
static const bool stateful_value_traits = types_t::stateful_value_traits;
typedef ValueTraits value_traits;
typedef typename types_t::node_traits node_traits;
typedef typename types_t::node node;
typedef typename types_t::node_ptr node_ptr;
typedef typename types_t::const_value_traits_ptr const_value_traits_ptr;
public:
typedef typename types_t::iterator_type::difference_type difference_type;
typedef typename types_t::iterator_type::value_type value_type;
typedef typename types_t::iterator_type::pointer pointer;
typedef typename types_t::iterator_type::reference reference;
typedef typename types_t::iterator_type::iterator_category iterator_category;
BOOST_INTRUSIVE_FORCEINLINE list_iterator()
{}
BOOST_INTRUSIVE_FORCEINLINE explicit list_iterator(const node_ptr & nodeptr, const const_value_traits_ptr &traits_ptr)
: members_(nodeptr, traits_ptr)
{}
BOOST_INTRUSIVE_FORCEINLINE list_iterator(list_iterator<ValueTraits, false> const& other)
: members_(other.pointed_node(), other.get_value_traits())
{}
BOOST_INTRUSIVE_FORCEINLINE const node_ptr &pointed_node() const
{ return members_.nodeptr_; }
BOOST_INTRUSIVE_FORCEINLINE list_iterator &operator=(const node_ptr &node)
{ members_.nodeptr_ = node; return static_cast<list_iterator&>(*this); }
BOOST_INTRUSIVE_FORCEINLINE const_value_traits_ptr get_value_traits() const
{ return members_.get_ptr(); }
public:
BOOST_INTRUSIVE_FORCEINLINE list_iterator& operator++()
{
node_ptr p = node_traits::get_next(members_.nodeptr_);
members_.nodeptr_ = p;
return static_cast<list_iterator&> (*this);
}
BOOST_INTRUSIVE_FORCEINLINE list_iterator operator++(int)
{
list_iterator result (*this);
members_.nodeptr_ = node_traits::get_next(members_.nodeptr_);
return result;
}
BOOST_INTRUSIVE_FORCEINLINE list_iterator& operator--()
{
members_.nodeptr_ = node_traits::get_previous(members_.nodeptr_);
return static_cast<list_iterator&> (*this);
}
BOOST_INTRUSIVE_FORCEINLINE list_iterator operator--(int)
{
list_iterator result (*this);
members_.nodeptr_ = node_traits::get_previous(members_.nodeptr_);
return result;
}
BOOST_INTRUSIVE_FORCEINLINE friend bool operator== (const list_iterator& l, const list_iterator& r)
{ return l.pointed_node() == r.pointed_node(); }
BOOST_INTRUSIVE_FORCEINLINE friend bool operator!= (const list_iterator& l, const list_iterator& r)
{ return !(l == r); }
BOOST_INTRUSIVE_FORCEINLINE reference operator*() const
{ return *operator->(); }
BOOST_INTRUSIVE_FORCEINLINE pointer operator->() const
{ return this->operator_arrow(detail::bool_<stateful_value_traits>()); }
list_iterator<ValueTraits, false> unconst() const
{ return list_iterator<ValueTraits, false>(this->pointed_node(), this->get_value_traits()); }
private:
BOOST_INTRUSIVE_FORCEINLINE pointer operator_arrow(detail::false_) const
{ return ValueTraits::to_value_ptr(members_.nodeptr_); }
BOOST_INTRUSIVE_FORCEINLINE pointer operator_arrow(detail::true_) const
{ return this->get_value_traits()->to_value_ptr(members_.nodeptr_); }
iiterator_members<node_ptr, const_value_traits_ptr, stateful_value_traits> members_;
};
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_LIST_ITERATOR_HPP

View File

@ -0,0 +1,72 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_LIST_NODE_HPP
#define BOOST_INTRUSIVE_LIST_NODE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/pointer_rebind.hpp>
namespace boost {
namespace intrusive {
// list_node_traits can be used with circular_list_algorithms and supplies
// a list_node holding the pointers needed for a double-linked list
// it is used by list_derived_node and list_member_node
template<class VoidPointer>
struct list_node
{
typedef typename pointer_rebind<VoidPointer, list_node>::type node_ptr;
node_ptr next_;
node_ptr prev_;
};
template<class VoidPointer>
struct list_node_traits
{
typedef list_node<VoidPointer> node;
typedef typename node::node_ptr node_ptr;
typedef typename pointer_rebind<VoidPointer, const node>::type const_node_ptr;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous(const const_node_ptr & n)
{ return n->prev_; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_previous(const node_ptr & n)
{ return n->prev_; }
BOOST_INTRUSIVE_FORCEINLINE static void set_previous(const node_ptr & n, const node_ptr & prev)
{ n->prev_ = prev; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const const_node_ptr & n)
{ return n->next_; }
BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_next(const node_ptr & n)
{ return n->next_; }
BOOST_INTRUSIVE_FORCEINLINE static void set_next(const node_ptr & n, const node_ptr & next)
{ n->next_ = next; }
};
} //namespace intrusive
} //namespace boost
#endif //BOOST_INTRUSIVE_LIST_NODE_HPP

View File

@ -0,0 +1,130 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2014-2014
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_DETAIL_NODE_TO_VALUE_HPP
#define BOOST_INTRUSIVE_DETAIL_NODE_TO_VALUE_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/is_stateful_value_traits.hpp>
namespace boost {
namespace intrusive {
namespace detail {
template<class VoidPointer>
struct dummy_constptr
{
typedef typename boost::intrusive::pointer_traits<VoidPointer>::
template rebind_pointer<const void>::type ConstVoidPtr;
explicit dummy_constptr(ConstVoidPtr)
{}
dummy_constptr()
{}
ConstVoidPtr get_ptr() const
{ return ConstVoidPtr(); }
};
template<class VoidPointer>
struct constptr
{
typedef typename boost::intrusive::pointer_traits<VoidPointer>::
template rebind_pointer<const void>::type ConstVoidPtr;
constptr()
{}
explicit constptr(const ConstVoidPtr &ptr)
: const_void_ptr_(ptr)
{}
const void *get_ptr() const
{ return boost::intrusive::detail::to_raw_pointer(const_void_ptr_); }
ConstVoidPtr const_void_ptr_;
};
template <class VoidPointer, bool store_ptr>
struct select_constptr
{
typedef typename if_c
< store_ptr
, constptr<VoidPointer>
, dummy_constptr<VoidPointer>
>::type type;
};
template<class ValueTraits, bool IsConst>
struct node_to_value
: public select_constptr
< typename pointer_traits
<typename ValueTraits::pointer>::template rebind_pointer<void>::type
, is_stateful_value_traits<ValueTraits>::value
>::type
{
static const bool stateful_value_traits = is_stateful_value_traits<ValueTraits>::value;
typedef typename select_constptr
< typename pointer_traits
<typename ValueTraits::pointer>::
template rebind_pointer<void>::type
, stateful_value_traits >::type Base;
typedef ValueTraits value_traits;
typedef typename value_traits::value_type value_type;
typedef typename value_traits::node_traits::node node;
typedef typename add_const_if_c
<value_type, IsConst>::type vtype;
typedef typename add_const_if_c
<node, IsConst>::type ntype;
typedef typename pointer_traits
<typename ValueTraits::pointer>::
template rebind_pointer<ntype>::type npointer;
typedef typename pointer_traits<npointer>::
template rebind_pointer<const ValueTraits>::type const_value_traits_ptr;
node_to_value(const const_value_traits_ptr &ptr)
: Base(ptr)
{}
typedef vtype & result_type;
typedef ntype & first_argument_type;
const_value_traits_ptr get_value_traits() const
{ return pointer_traits<const_value_traits_ptr>::static_cast_from(Base::get_ptr()); }
result_type to_value(first_argument_type arg, false_) const
{ return *(value_traits::to_value_ptr(pointer_traits<npointer>::pointer_to(arg))); }
result_type to_value(first_argument_type arg, true_) const
{ return *(this->get_value_traits()->to_value_ptr(pointer_traits<npointer>::pointer_to(arg))); }
result_type operator()(first_argument_type arg) const
{ return this->to_value(arg, bool_<stateful_value_traits>()); }
};
} //namespace detail{
} //namespace intrusive{
} //namespace boost{
#endif //BOOST_INTRUSIVE_DETAIL_NODE_TO_VALUE_HPP

View File

@ -0,0 +1,172 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP
#define BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/detail/mpl.hpp>
#include <boost/intrusive/detail/iterator.hpp>
namespace boost {
namespace intrusive {
namespace detail {
template <class PseudoReference>
struct operator_arrow_proxy
{
BOOST_INTRUSIVE_FORCEINLINE operator_arrow_proxy(const PseudoReference &px)
: m_value(px)
{}
BOOST_INTRUSIVE_FORCEINLINE PseudoReference* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
mutable PseudoReference m_value;
};
template <class T>
struct operator_arrow_proxy<T&>
{
BOOST_INTRUSIVE_FORCEINLINE operator_arrow_proxy(T &px)
: m_value(px)
{}
BOOST_INTRUSIVE_FORCEINLINE T* operator->() const { return &m_value; }
// This function is needed for MWCW and BCC, which won't call operator->
// again automatically per 13.3.1.2 para 8
// operator T*() const { return &m_value; }
T &m_value;
};
template <class Iterator, class UnaryFunction>
class transform_iterator
{
public:
typedef typename Iterator::iterator_category iterator_category;
typedef typename detail::remove_reference<typename UnaryFunction::result_type>::type value_type;
typedef typename Iterator::difference_type difference_type;
typedef operator_arrow_proxy<typename UnaryFunction::result_type> pointer;
typedef typename UnaryFunction::result_type reference;
explicit transform_iterator(const Iterator &it, const UnaryFunction &f = UnaryFunction())
: members_(it, f)
{}
explicit transform_iterator()
: members_()
{}
BOOST_INTRUSIVE_FORCEINLINE Iterator get_it() const
{ return members_.m_it; }
//Constructors
BOOST_INTRUSIVE_FORCEINLINE transform_iterator& operator++()
{ increment(); return *this; }
BOOST_INTRUSIVE_FORCEINLINE transform_iterator operator++(int)
{
transform_iterator result (*this);
increment();
return result;
}
BOOST_INTRUSIVE_FORCEINLINE friend bool operator== (const transform_iterator& i, const transform_iterator& i2)
{ return i.equal(i2); }
BOOST_INTRUSIVE_FORCEINLINE friend bool operator!= (const transform_iterator& i, const transform_iterator& i2)
{ return !(i == i2); }
BOOST_INTRUSIVE_FORCEINLINE friend typename Iterator::difference_type operator- (const transform_iterator& i, const transform_iterator& i2)
{ return i2.distance_to(i); }
//Arithmetic
transform_iterator& operator+=(typename Iterator::difference_type off)
{ this->advance(off); return *this; }
BOOST_INTRUSIVE_FORCEINLINE transform_iterator operator+(typename Iterator::difference_type off) const
{
transform_iterator other(*this);
other.advance(off);
return other;
}
BOOST_INTRUSIVE_FORCEINLINE friend transform_iterator operator+(typename Iterator::difference_type off, const transform_iterator& right)
{ return right + off; }
BOOST_INTRUSIVE_FORCEINLINE transform_iterator& operator-=(typename Iterator::difference_type off)
{ this->advance(-off); return *this; }
BOOST_INTRUSIVE_FORCEINLINE transform_iterator operator-(typename Iterator::difference_type off) const
{ return *this + (-off); }
BOOST_INTRUSIVE_FORCEINLINE typename UnaryFunction::result_type operator*() const
{ return dereference(); }
BOOST_INTRUSIVE_FORCEINLINE operator_arrow_proxy<typename UnaryFunction::result_type>
operator->() const
{ return operator_arrow_proxy<typename UnaryFunction::result_type>(dereference()); }
private:
struct members
: UnaryFunction
{
BOOST_INTRUSIVE_FORCEINLINE members(const Iterator &it, const UnaryFunction &f)
: UnaryFunction(f), m_it(it)
{}
BOOST_INTRUSIVE_FORCEINLINE members()
{}
Iterator m_it;
} members_;
BOOST_INTRUSIVE_FORCEINLINE void increment()
{ ++members_.m_it; }
BOOST_INTRUSIVE_FORCEINLINE void decrement()
{ --members_.m_it; }
BOOST_INTRUSIVE_FORCEINLINE bool equal(const transform_iterator &other) const
{ return members_.m_it == other.members_.m_it; }
BOOST_INTRUSIVE_FORCEINLINE bool less(const transform_iterator &other) const
{ return other.members_.m_it < members_.m_it; }
typename UnaryFunction::result_type dereference() const
{ return members_(*members_.m_it); }
void advance(typename Iterator::difference_type n)
{ boost::intrusive::iterator_advance(members_.m_it, n); }
typename Iterator::difference_type distance_to(const transform_iterator &other)const
{ return boost::intrusive::iterator_distance(other.members_.m_it, members_.m_it); }
};
} //namespace detail
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_DETAIL_TRANSFORM_ITERATOR_HPP

File diff suppressed because it is too large Load Diff

1509
boost/intrusive/list.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,289 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_LIST_HOOK_HPP
#define BOOST_INTRUSIVE_LIST_HOOK_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/list_node.hpp>
#include <boost/intrusive/circular_list_algorithms.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/generic_hook.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//! Helper metafunction to define a \c \c list_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void>
#endif
struct make_list_base_hook
{
/// @cond
typedef typename pack_options
< hook_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3
#else
Options...
#endif
>::type packed_options;
typedef generic_hook
< CircularListAlgorithms
, list_node_traits<typename packed_options::void_pointer>
, typename packed_options::tag
, packed_options::link_mode
, ListBaseHookId
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Derive a class from this hook in order to store objects of that class
//! in an list.
//!
//! The hook admits the following options: \c tag<>, \c void_pointer<> and
//! \c link_mode<>.
//!
//! \c tag<> defines a tag to identify the node.
//! The same tag value can be used in different classes, but if a class is
//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its
//! unique tag.
//!
//! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
//! \c auto_unlink or \c safe_link).
//!
//! \c void_pointer<> is the pointer type that will be used internally in the hook
//! and the container configured to use this hook.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1, class O2, class O3>
#endif
class list_base_hook
: public make_list_base_hook
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
<O1, O2, O3>
#else
<Options...>
#endif
::type
{
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
public:
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
list_base_hook();
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
list_base_hook(const list_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
list_base_hook& operator=(const list_base_hook& );
//! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in an list an assertion is raised. If link_mode is
//! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
~list_base_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(list_base_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c list::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
void unlink();
#endif
};
//! Helper metafunction to define a \c \c list_member_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void>
#endif
struct make_list_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3
#else
Options...
#endif
>::type packed_options;
typedef generic_hook
< CircularListAlgorithms
, list_node_traits<typename packed_options::void_pointer>
, member_tag
, packed_options::link_mode
, NoBaseHookId
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Store this hook in a class to be inserted
//! in an list.
//!
//! The hook admits the following options: \c void_pointer<> and
//! \c link_mode<>.
//!
//! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
//! \c auto_unlink or \c safe_link).
//!
//! \c void_pointer<> is the pointer type that will be used internally in the hook
//! and the container configured to use this hook.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1, class O2, class O3>
#endif
class list_member_hook
: public make_list_member_hook
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
<O1, O2, O3>
#else
<Options...>
#endif
::type
{
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
public:
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
list_member_hook();
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
list_member_hook(const list_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
list_member_hook& operator=(const list_member_hook& );
//! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in an list an assertion is raised. If link_mode is
//! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
~list_member_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(list_member_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c list::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
void unlink();
#endif
};
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_LIST_HOOK_HPP

View File

@ -0,0 +1,85 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/detail/parent_from_member.hpp>
#include <boost/intrusive/detail/to_raw_pointer.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type will
//!store a node_traits::node
template< class T, class NodeTraits
, typename NodeTraits::node T::* PtrToMember
, link_mode_type LinkMode
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
= safe_link
#endif
>
struct member_value_traits
{
public:
typedef NodeTraits node_traits;
typedef T value_type;
typedef typename node_traits::node node;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef pointer_traits<node_ptr> node_ptr_traits;
typedef typename pointer_traits<node_ptr>::template
rebind_pointer<T>::type pointer;
typedef typename pointer_traits<node_ptr>::template
rebind_pointer<const T>::type const_pointer;
//typedef typename pointer_traits<pointer>::reference reference;
//typedef typename pointer_traits<const_pointer>::reference const_reference;
typedef value_type & reference;
typedef const value_type & const_reference;
static const link_mode_type link_mode = LinkMode;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr to_node_ptr(reference value)
{ return pointer_traits<node_ptr>::pointer_to(value.*PtrToMember); }
BOOST_INTRUSIVE_FORCEINLINE static const_node_ptr to_node_ptr(const_reference value)
{ return pointer_traits<const_node_ptr>::pointer_to(value.*PtrToMember); }
BOOST_INTRUSIVE_FORCEINLINE static pointer to_value_ptr(const node_ptr &n)
{
return pointer_traits<pointer>::pointer_to(*detail::parent_from_member<value_type, node>
(boost::intrusive::detail::to_raw_pointer(n), PtrToMember));
}
BOOST_INTRUSIVE_FORCEINLINE static const_pointer to_value_ptr(const const_node_ptr &n)
{
return pointer_traits<const_pointer>::pointer_to(*detail::parent_from_member<value_type, node>
(boost::intrusive::detail::to_raw_pointer(n), PtrToMember));
}
};
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_MEMBER_VALUE_TRAITS_HPP

View File

@ -0,0 +1,82 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2008
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_PRIORITY_COMPARE_HPP
#define BOOST_INTRUSIVE_PRIORITY_COMPARE_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/detail/minimal_less_equal_header.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
/// @cond
template<class U>
void priority_order();
/// @endcond
template <class T = void>
struct priority_compare
{
//Compatibility with std::binary_function
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T &val, const T &val2) const
{
return priority_order(val, val2);
}
};
template <>
struct priority_compare<void>
{
template<class T, class U>
BOOST_INTRUSIVE_FORCEINLINE bool operator()(const T &t, const U &u) const
{
return priority_order(t, u);
}
};
/// @cond
template<class PrioComp, class T>
struct get_prio
{
typedef PrioComp type;
};
template<class T>
struct get_prio<void, T>
{
typedef ::boost::intrusive::priority_compare<T> type;
};
/// @endcond
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_PRIORITY_COMPARE_HPP

1073
boost/intrusive/set.hpp Normal file

File diff suppressed because it is too large Load Diff

1094
boost/intrusive/sg_set.hpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1344
boost/intrusive/treap.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,699 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2014.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_TREAP_ALGORITHMS_HPP
#define BOOST_INTRUSIVE_TREAP_ALGORITHMS_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <cstddef>
#include <boost/intrusive/detail/assert.hpp>
#include <boost/intrusive/detail/algo_type.hpp>
#include <boost/intrusive/bstree_algorithms.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
namespace detail
{
template<class ValueTraits, class NodePtrPrioCompare, class ExtraChecker>
struct treap_node_extra_checker
: public ExtraChecker
{
typedef ExtraChecker base_checker_t;
typedef ValueTraits value_traits;
typedef typename value_traits::node_traits node_traits;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef typename base_checker_t::return_type return_type;
treap_node_extra_checker(const NodePtrPrioCompare& prio_comp, ExtraChecker extra_checker)
: base_checker_t(extra_checker), prio_comp_(prio_comp)
{}
void operator () (const const_node_ptr& p,
const return_type& check_return_left, const return_type& check_return_right,
return_type& check_return)
{
if (node_traits::get_left(p))
BOOST_INTRUSIVE_INVARIANT_ASSERT(!prio_comp_(node_traits::get_left(p), p));
if (node_traits::get_right(p))
BOOST_INTRUSIVE_INVARIANT_ASSERT(!prio_comp_(node_traits::get_right(p), p));
base_checker_t::operator()(p, check_return_left, check_return_right, check_return);
}
const NodePtrPrioCompare prio_comp_;
};
} // namespace detail
#endif //#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! treap_algorithms provides basic algorithms to manipulate
//! nodes forming a treap.
//!
//! (1) the header node is maintained with links not only to the root
//! but also to the leftmost node of the tree, to enable constant time
//! begin(), and to the rightmost node of the tree, to enable linear time
//! performance when used with the generic set algorithms (set_union,
//! etc.);
//!
//! (2) when a node being deleted has two children its successor node is
//! relinked into its place, rather than copied, so that the only
//! pointers invalidated are those referring to the deleted node.
//!
//! treap_algorithms is configured with a NodeTraits class, which encapsulates the
//! information about the node to be manipulated. NodeTraits must support the
//! following interface:
//!
//! <b>Typedefs</b>:
//!
//! <tt>node</tt>: The type of the node that forms the treap
//!
//! <tt>node_ptr</tt>: A pointer to a node
//!
//! <tt>const_node_ptr</tt>: A pointer to a const node
//!
//! <b>Static functions</b>:
//!
//! <tt>static node_ptr get_parent(const_node_ptr n);</tt>
//!
//! <tt>static void set_parent(node_ptr n, node_ptr parent);</tt>
//!
//! <tt>static node_ptr get_left(const_node_ptr n);</tt>
//!
//! <tt>static void set_left(node_ptr n, node_ptr left);</tt>
//!
//! <tt>static node_ptr get_right(const_node_ptr n);</tt>
//!
//! <tt>static void set_right(node_ptr n, node_ptr right);</tt>
template<class NodeTraits>
class treap_algorithms
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
: public bstree_algorithms<NodeTraits>
#endif
{
public:
typedef NodeTraits node_traits;
typedef typename NodeTraits::node node;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
/// @cond
private:
typedef bstree_algorithms<NodeTraits> bstree_algo;
class rerotate_on_destroy
{
rerotate_on_destroy& operator=(const rerotate_on_destroy&);
public:
rerotate_on_destroy(const node_ptr & header, const node_ptr & p, std::size_t &n)
: header_(header), p_(p), n_(n), remove_it_(true)
{}
~rerotate_on_destroy()
{
if(remove_it_){
rotate_up_n(header_, p_, n_);
}
}
void release()
{ remove_it_ = false; }
const node_ptr header_;
const node_ptr p_;
std::size_t &n_;
bool remove_it_;
};
static void rotate_up_n(const node_ptr header, const node_ptr p, std::size_t n)
{
node_ptr p_parent(NodeTraits::get_parent(p));
node_ptr p_grandparent(NodeTraits::get_parent(p_parent));
while(n--){
if(p == NodeTraits::get_left(p_parent)){ //p is left child
bstree_algo::rotate_right(p_parent, p, p_grandparent, header);
}
else{ //p is right child
bstree_algo::rotate_left(p_parent, p, p_grandparent, header);
}
p_parent = p_grandparent;
p_grandparent = NodeTraits::get_parent(p_parent);
}
}
/// @endcond
public:
//! This type is the information that will be
//! filled by insert_unique_check
struct insert_commit_data
/// @cond
: public bstree_algo::insert_commit_data
/// @endcond
{
/// @cond
std::size_t rotations;
/// @endcond
};
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::get_header(const const_node_ptr&)
static node_ptr get_header(const const_node_ptr & n);
//! @copydoc ::boost::intrusive::bstree_algorithms::begin_node
static node_ptr begin_node(const const_node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::end_node
static node_ptr end_node(const const_node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::swap_tree
static void swap_tree(const node_ptr & header1, const node_ptr & header2);
//! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&)
static void swap_nodes(const node_ptr & node1, const node_ptr & node2);
//! @copydoc ::boost::intrusive::bstree_algorithms::swap_nodes(const node_ptr&,const node_ptr&,const node_ptr&,const node_ptr&)
static void swap_nodes(const node_ptr & node1, const node_ptr & header1, const node_ptr & node2, const node_ptr & header2);
//! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&)
static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & new_node);
//! @copydoc ::boost::intrusive::bstree_algorithms::replace_node(const node_ptr&,const node_ptr&,const node_ptr&)
static void replace_node(const node_ptr & node_to_be_replaced, const node_ptr & header, const node_ptr & new_node);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::unlink(const node_ptr&)
template<class NodePtrPriorityCompare>
static void unlink(const node_ptr & node, NodePtrPriorityCompare pcomp)
{
node_ptr x = NodeTraits::get_parent(node);
if(x){
while(!bstree_algo::is_header(x))
x = NodeTraits::get_parent(x);
erase(x, node, pcomp);
}
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::unlink_leftmost_without_rebalance
static node_ptr unlink_leftmost_without_rebalance(const node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::unique(const const_node_ptr&)
static bool unique(const const_node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::size(const const_node_ptr&)
static std::size_t size(const const_node_ptr & header);
//! @copydoc ::boost::intrusive::bstree_algorithms::next_node(const node_ptr&)
static node_ptr next_node(const node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::prev_node(const node_ptr&)
static node_ptr prev_node(const node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::init(const node_ptr&)
static void init(const node_ptr & node);
//! @copydoc ::boost::intrusive::bstree_algorithms::init_header(const node_ptr&)
static void init_header(const node_ptr & header);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::erase(const node_ptr&,const node_ptr&)
template<class NodePtrPriorityCompare>
static node_ptr erase(const node_ptr & header, const node_ptr & z, NodePtrPriorityCompare pcomp)
{
rebalance_for_erasure(header, z, pcomp);
bstree_algo::erase(header, z);
return z;
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::clone(const const_node_ptr&,const node_ptr&,Cloner,Disposer)
template <class Cloner, class Disposer>
static void clone
(const const_node_ptr & source_header, const node_ptr & target_header, Cloner cloner, Disposer disposer);
//! @copydoc ::boost::intrusive::bstree_algorithms::clear_and_dispose(const node_ptr&,Disposer)
template<class Disposer>
static void clear_and_dispose(const node_ptr & header, Disposer disposer);
//! @copydoc ::boost::intrusive::bstree_algorithms::lower_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static node_ptr lower_bound
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::upper_bound(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static node_ptr upper_bound
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::find(const const_node_ptr&, const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static node_ptr find
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::equal_range(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static std::pair<node_ptr, node_ptr> equal_range
(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
//! @copydoc ::boost::intrusive::bstree_algorithms::bounded_range(const const_node_ptr&,const KeyType&,const KeyType&,KeyNodePtrCompare,bool,bool)
template<class KeyType, class KeyNodePtrCompare>
static std::pair<node_ptr, node_ptr> bounded_range
(const const_node_ptr & header, const KeyType &lower_key, const KeyType &upper_key, KeyNodePtrCompare comp
, bool left_closed, bool right_closed);
//! @copydoc ::boost::intrusive::bstree_algorithms::count(const const_node_ptr&,const KeyType&,KeyNodePtrCompare)
template<class KeyType, class KeyNodePtrCompare>
static std::size_t count(const const_node_ptr & header, const KeyType &key, KeyNodePtrCompare comp);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! <b>Requires</b>: "h" must be the header node of a tree.
//! NodePtrCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the tree. NodePtrCompare compares two node_ptrs.
//! NodePtrPriorityCompare is a priority function object that induces a strict weak
//! ordering compatible with the one used to create the
//! the tree. NodePtrPriorityCompare compares two node_ptrs.
//!
//! <b>Effects</b>: Inserts new_node into the tree before the upper bound
//! according to "comp" and rotates the tree according to "pcomp".
//!
//! <b>Complexity</b>: Average complexity for insert element is at
//! most logarithmic.
//!
//! <b>Throws</b>: If "comp" throw or "pcomp" throw.
template<class NodePtrCompare, class NodePtrPriorityCompare>
static node_ptr insert_equal_upper_bound
(const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, NodePtrPriorityCompare pcomp)
{
insert_commit_data commit_data;
bstree_algo::insert_equal_upper_bound_check(h, new_node, comp, commit_data);
rebalance_check_and_commit(h, new_node, pcomp, commit_data);
return new_node;
}
//! <b>Requires</b>: "h" must be the header node of a tree.
//! NodePtrCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the tree. NodePtrCompare compares two node_ptrs.
//! NodePtrPriorityCompare is a priority function object that induces a strict weak
//! ordering compatible with the one used to create the
//! the tree. NodePtrPriorityCompare compares two node_ptrs.
//!
//! <b>Effects</b>: Inserts new_node into the tree before the upper bound
//! according to "comp" and rotates the tree according to "pcomp".
//!
//! <b>Complexity</b>: Average complexity for insert element is at
//! most logarithmic.
//!
//! <b>Throws</b>: If "comp" throws.
template<class NodePtrCompare, class NodePtrPriorityCompare>
static node_ptr insert_equal_lower_bound
(const node_ptr & h, const node_ptr & new_node, NodePtrCompare comp, NodePtrPriorityCompare pcomp)
{
insert_commit_data commit_data;
bstree_algo::insert_equal_lower_bound_check(h, new_node, comp, commit_data);
rebalance_check_and_commit(h, new_node, pcomp, commit_data);
return new_node;
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! NodePtrCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the tree. NodePtrCompare compares two node_ptrs. "hint" is node from
//! the "header"'s tree.
//! NodePtrPriorityCompare is a priority function object that induces a strict weak
//! ordering compatible with the one used to create the
//! the tree. NodePtrPriorityCompare compares two node_ptrs.
//!
//! <b>Effects</b>: Inserts new_node into the tree, using "hint" as a hint to
//! where it will be inserted. If "hint" is the upper_bound
//! the insertion takes constant time (two comparisons in the worst case).
//! Rotates the tree according to "pcomp".
//!
//! <b>Complexity</b>: Logarithmic in general, but it is amortized
//! constant time if new_node is inserted immediately before "hint".
//!
//! <b>Throws</b>: If "comp" throw or "pcomp" throw.
template<class NodePtrCompare, class NodePtrPriorityCompare>
static node_ptr insert_equal
(const node_ptr & h, const node_ptr & hint, const node_ptr & new_node, NodePtrCompare comp, NodePtrPriorityCompare pcomp)
{
insert_commit_data commit_data;
bstree_algo::insert_equal_check(h, hint, new_node, comp, commit_data);
rebalance_check_and_commit(h, new_node, pcomp, commit_data);
return new_node;
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! "pos" must be a valid node of the tree (including header end) node.
//! "pos" must be a node pointing to the successor to "new_node"
//! once inserted according to the order of already inserted nodes. This function does not
//! check "pos" and this precondition must be guaranteed by the caller.
//! NodePtrPriorityCompare is a priority function object that induces a strict weak
//! ordering compatible with the one used to create the
//! the tree. NodePtrPriorityCompare compares two node_ptrs.
//!
//! <b>Effects</b>: Inserts new_node into the tree before "pos"
//! and rotates the tree according to "pcomp".
//!
//! <b>Complexity</b>: Constant-time.
//!
//! <b>Throws</b>: If "pcomp" throws, strong guarantee.
//!
//! <b>Note</b>: If "pos" is not the successor of the newly inserted "new_node"
//! tree invariants might be broken.
template<class NodePtrPriorityCompare>
static node_ptr insert_before
(const node_ptr & header, const node_ptr & pos, const node_ptr & new_node, NodePtrPriorityCompare pcomp)
{
insert_commit_data commit_data;
bstree_algo::insert_before_check(header, pos, commit_data);
rebalance_check_and_commit(header, new_node, pcomp, commit_data);
return new_node;
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! "new_node" must be, according to the used ordering no less than the
//! greatest inserted key.
//! NodePtrPriorityCompare is a priority function object that induces a strict weak
//! ordering compatible with the one used to create the
//! the tree. NodePtrPriorityCompare compares two node_ptrs.
//!
//! <b>Effects</b>: Inserts x into the tree in the last position
//! and rotates the tree according to "pcomp".
//!
//! <b>Complexity</b>: Constant-time.
//!
//! <b>Throws</b>: If "pcomp" throws, strong guarantee.
//!
//! <b>Note</b>: If "new_node" is less than the greatest inserted key
//! tree invariants are broken. This function is slightly faster than
//! using "insert_before".
template<class NodePtrPriorityCompare>
static void push_back(const node_ptr & header, const node_ptr & new_node, NodePtrPriorityCompare pcomp)
{
insert_commit_data commit_data;
bstree_algo::push_back_check(header, commit_data);
rebalance_check_and_commit(header, new_node, pcomp, commit_data);
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! "new_node" must be, according to the used ordering, no greater than the
//! lowest inserted key.
//! NodePtrPriorityCompare is a priority function object that induces a strict weak
//! ordering compatible with the one used to create the
//! the tree. NodePtrPriorityCompare compares two node_ptrs.
//!
//! <b>Effects</b>: Inserts x into the tree in the first position
//! and rotates the tree according to "pcomp".
//!
//! <b>Complexity</b>: Constant-time.
//!
//! <b>Throws</b>: If "pcomp" throws, strong guarantee.
//!
//! <b>Note</b>: If "new_node" is greater than the lowest inserted key
//! tree invariants are broken. This function is slightly faster than
//! using "insert_before".
template<class NodePtrPriorityCompare>
static void push_front(const node_ptr & header, const node_ptr & new_node, NodePtrPriorityCompare pcomp)
{
insert_commit_data commit_data;
bstree_algo::push_front_check(header, commit_data);
rebalance_check_and_commit(header, new_node, pcomp, commit_data);
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! KeyNodePtrCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the tree. NodePtrCompare compares KeyType with a node_ptr.
//!
//! <b>Effects</b>: Checks if there is an equivalent node to "key" in the
//! tree according to "comp" and obtains the needed information to realize
//! a constant-time node insertion if there is no equivalent node.
//!
//! <b>Returns</b>: If there is an equivalent value
//! returns a pair containing a node_ptr to the already present node
//! and false. If there is not equivalent key can be inserted returns true
//! in the returned pair's boolean and fills "commit_data" that is meant to
//! be used with the "insert_commit" function to achieve a constant-time
//! insertion function.
//!
//! <b>Complexity</b>: Average complexity is at most logarithmic.
//!
//! <b>Throws</b>: If "comp" throws.
//!
//! <b>Notes</b>: This function is used to improve performance when constructing
//! a node is expensive and the user does not want to have two equivalent nodes
//! in the tree: if there is an equivalent value
//! the constructed object must be discarded. Many times, the part of the
//! node that is used to impose the order is much cheaper to construct
//! than the node and this function offers the possibility to use that part
//! to check if the insertion will be successful.
//!
//! If the check is successful, the user can construct the node and use
//! "insert_commit" to insert the node in constant-time. This gives a total
//! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).
//!
//! "commit_data" remains valid for a subsequent "insert_unique_commit" only
//! if no more objects are inserted or erased from the set.
template<class KeyType, class KeyNodePtrCompare, class KeyNodePtrPrioCompare>
static std::pair<node_ptr, bool> insert_unique_check
(const const_node_ptr & header, const KeyType &key
,KeyNodePtrCompare comp, KeyNodePtrPrioCompare pcomp
,insert_commit_data &commit_data)
{
std::pair<node_ptr, bool> ret =
bstree_algo::insert_unique_check(header, key, comp, commit_data);
if(ret.second)
rebalance_after_insertion_check(header, commit_data.node, key, pcomp, commit_data.rotations);
return ret;
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! KeyNodePtrCompare is a function object that induces a strict weak
//! ordering compatible with the strict weak ordering used to create the
//! the tree. NodePtrCompare compares KeyType with a node_ptr.
//! "hint" is node from the "header"'s tree.
//!
//! <b>Effects</b>: Checks if there is an equivalent node to "key" in the
//! tree according to "comp" using "hint" as a hint to where it should be
//! inserted and obtains the needed information to realize
//! a constant-time node insertion if there is no equivalent node.
//! If "hint" is the upper_bound the function has constant time
//! complexity (two comparisons in the worst case).
//!
//! <b>Returns</b>: If there is an equivalent value
//! returns a pair containing a node_ptr to the already present node
//! and false. If there is not equivalent key can be inserted returns true
//! in the returned pair's boolean and fills "commit_data" that is meant to
//! be used with the "insert_commit" function to achieve a constant-time
//! insertion function.
//!
//! <b>Complexity</b>: Average complexity is at most logarithmic, but it is
//! amortized constant time if new_node should be inserted immediately before "hint".
//!
//! <b>Throws</b>: If "comp" throws.
//!
//! <b>Notes</b>: This function is used to improve performance when constructing
//! a node is expensive and the user does not want to have two equivalent nodes
//! in the tree: if there is an equivalent value
//! the constructed object must be discarded. Many times, the part of the
//! node that is used to impose the order is much cheaper to construct
//! than the node and this function offers the possibility to use that part
//! to check if the insertion will be successful.
//!
//! If the check is successful, the user can construct the node and use
//! "insert_commit" to insert the node in constant-time. This gives a total
//! logarithmic complexity to the insertion: check(O(log(N)) + commit(O(1)).
//!
//! "commit_data" remains valid for a subsequent "insert_unique_commit" only
//! if no more objects are inserted or erased from the set.
template<class KeyType, class KeyNodePtrCompare, class KeyNodePtrPrioCompare>
static std::pair<node_ptr, bool> insert_unique_check
(const const_node_ptr & header, const node_ptr & hint, const KeyType &key
,KeyNodePtrCompare comp, KeyNodePtrPrioCompare pcomp, insert_commit_data &commit_data)
{
std::pair<node_ptr, bool> ret =
bstree_algo::insert_unique_check(header, hint, key, comp, commit_data);
if(ret.second)
rebalance_after_insertion_check(header, commit_data.node, key, pcomp, commit_data.rotations);
return ret;
}
//! <b>Requires</b>: "header" must be the header node of a tree.
//! "commit_data" must have been obtained from a previous call to
//! "insert_unique_check". No objects should have been inserted or erased
//! from the set between the "insert_unique_check" that filled "commit_data"
//! and the call to "insert_commit".
//!
//!
//! <b>Effects</b>: Inserts new_node in the set using the information obtained
//! from the "commit_data" that a previous "insert_check" filled.
//!
//! <b>Complexity</b>: Constant time.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Notes</b>: This function has only sense if a "insert_unique_check" has been
//! previously executed to fill "commit_data". No value should be inserted or
//! erased between the "insert_check" and "insert_commit" calls.
static void insert_unique_commit
(const node_ptr & header, const node_ptr & new_node, const insert_commit_data &commit_data)
{
bstree_algo::insert_unique_commit(header, new_node, commit_data);
rotate_up_n(header, new_node, commit_data.rotations);
}
//! @copydoc ::boost::intrusive::bstree_algorithms::transfer_unique
template<class NodePtrCompare, class KeyNodePtrPrioCompare>
static bool transfer_unique
(const node_ptr & header1, NodePtrCompare comp, KeyNodePtrPrioCompare pcomp, const node_ptr &header2, const node_ptr & z)
{
insert_commit_data commit_data;
bool const transferable = insert_unique_check(header1, z, comp, pcomp, commit_data).second;
if(transferable){
erase(header2, z, pcomp);
insert_unique_commit(header1, z, commit_data);
}
return transferable;
}
//! @copydoc ::boost::intrusive::bstree_algorithms::transfer_equal
template<class NodePtrCompare, class KeyNodePtrPrioCompare>
static void transfer_equal
(const node_ptr & header1, NodePtrCompare comp, KeyNodePtrPrioCompare pcomp, const node_ptr &header2, const node_ptr & z)
{
insert_commit_data commit_data;
bstree_algo::insert_equal_upper_bound_check(header1, z, comp, commit_data);
rebalance_after_insertion_check(header1, commit_data.node, z, pcomp, commit_data.rotations);
rebalance_for_erasure(header2, z, pcomp);
bstree_algo::erase(header2, z);
bstree_algo::insert_unique_commit(header1, z, commit_data);
rotate_up_n(header1, z, commit_data.rotations);
}
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::bstree_algorithms::is_header
static bool is_header(const const_node_ptr & p);
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
/// @cond
private:
template<class NodePtrPriorityCompare>
static void rebalance_for_erasure(const node_ptr & header, const node_ptr & z, NodePtrPriorityCompare pcomp)
{
std::size_t n = 0;
rerotate_on_destroy rb(header, z, n);
node_ptr z_left = NodeTraits::get_left(z);
node_ptr z_right = NodeTraits::get_right(z);
while(z_left || z_right){
const node_ptr z_parent(NodeTraits::get_parent(z));
if(!z_right || (z_left && pcomp(z_left, z_right))){
bstree_algo::rotate_right(z, z_left, z_parent, header);
}
else{
bstree_algo::rotate_left(z, z_right, z_parent, header);
}
++n;
z_left = NodeTraits::get_left(z);
z_right = NodeTraits::get_right(z);
}
rb.release();
}
template<class NodePtrPriorityCompare>
static void rebalance_check_and_commit
(const node_ptr & h, const node_ptr & new_node, NodePtrPriorityCompare pcomp, insert_commit_data &commit_data)
{
rebalance_after_insertion_check(h, commit_data.node, new_node, pcomp, commit_data.rotations);
//No-throw
bstree_algo::insert_unique_commit(h, new_node, commit_data);
rotate_up_n(h, new_node, commit_data.rotations);
}
template<class Key, class KeyNodePriorityCompare>
static void rebalance_after_insertion_check
(const const_node_ptr &header, const const_node_ptr & up, const Key &k
, KeyNodePriorityCompare pcomp, std::size_t &num_rotations)
{
const_node_ptr upnode(up);
//First check rotations since pcomp can throw
num_rotations = 0;
std::size_t n = 0;
while(upnode != header && pcomp(k, upnode)){
++n;
upnode = NodeTraits::get_parent(upnode);
}
num_rotations = n;
}
template<class NodePtrPriorityCompare>
static bool check_invariant(const const_node_ptr & header, NodePtrPriorityCompare pcomp)
{
node_ptr beg = begin_node(header);
node_ptr end = end_node(header);
while(beg != end){
node_ptr p = NodeTraits::get_parent(beg);
if(p != header){
if(pcomp(beg, p))
return false;
}
beg = next_node(beg);
}
return true;
}
/// @endcond
};
/// @cond
template<class NodeTraits>
struct get_algo<TreapAlgorithms, NodeTraits>
{
typedef treap_algorithms<NodeTraits> type;
};
template <class ValueTraits, class NodePtrCompare, class ExtraChecker>
struct get_node_checker<TreapAlgorithms, ValueTraits, NodePtrCompare, ExtraChecker>
{
typedef detail::bstree_node_checker<ValueTraits, NodePtrCompare, ExtraChecker> type;
};
/// @endcond
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_TREAP_ALGORITHMS_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP
#define BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/detail/workaround.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//!This value traits template is used to create value traits
//!from user defined node traits where value_traits::value_type and
//!node_traits::node should be equal
template<class NodeTraits, link_mode_type LinkMode
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
= safe_link
#endif
>
struct trivial_value_traits
{
typedef NodeTraits node_traits;
typedef typename node_traits::node_ptr node_ptr;
typedef typename node_traits::const_node_ptr const_node_ptr;
typedef typename node_traits::node value_type;
typedef node_ptr pointer;
typedef const_node_ptr const_pointer;
static const link_mode_type link_mode = LinkMode;
BOOST_INTRUSIVE_FORCEINLINE static node_ptr to_node_ptr (value_type &value)
{ return pointer_traits<node_ptr>::pointer_to(value); }
BOOST_INTRUSIVE_FORCEINLINE static const_node_ptr to_node_ptr (const value_type &value)
{ return pointer_traits<const_node_ptr>::pointer_to(value); }
BOOST_INTRUSIVE_FORCEINLINE static const pointer & to_value_ptr(const node_ptr &n) { return n; }
BOOST_INTRUSIVE_FORCEINLINE static const const_pointer &to_value_ptr(const const_node_ptr &n) { return n; }
};
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_TRIVIAL_VALUE_TRAITS_HPP

View File

@ -0,0 +1,990 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2014
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_UNORDERED_SET_HPP
#define BOOST_INTRUSIVE_UNORDERED_SET_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/hashtable.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/static_assert.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
//! The class template unordered_set is an intrusive container, that mimics most of
//! the interface of std::tr1::unordered_set as described in the C++ TR1.
//!
//! unordered_set is a semi-intrusive container: each object to be stored in the
//! container must contain a proper hook, but the container also needs
//! additional auxiliary memory to work: unordered_set needs a pointer to an array
//! of type `bucket_type` to be passed in the constructor. This bucket array must
//! have at least the same lifetime as the container. This makes the use of
//! unordered_set more complicated than purely intrusive containers.
//! `bucket_type` is default-constructible, copyable and assignable
//!
//! The template parameter \c T is the type to be managed by the container.
//! The user can specify additional options and if no options are provided
//! default options are used.
//!
//! The container supports the following options:
//! \c base_hook<>/member_hook<>/value_traits<>,
//! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<>
//! \c bucket_traits<>, \c power_2_buckets<> and \c cache_begin<>.
//!
//! unordered_set only provides forward iterators but it provides 4 iterator types:
//! iterator and const_iterator to navigate through the whole container and
//! local_iterator and const_local_iterator to navigate through the values
//! stored in a single bucket. Local iterators are faster and smaller.
//!
//! It's not recommended to use non constant-time size unordered_sets because several
//! key functions, like "empty()", become non-constant time functions. Non
//! constant-time size unordered_sets are mainly provided to support auto-unlink hooks.
//!
//! unordered_set, unlike std::unordered_set, does not make automatic rehashings nor
//! offers functions related to a load factor. Rehashing can be explicitly requested
//! and the user must provide a new bucket array that will be used from that moment.
//!
//! Since no automatic rehashing is done, iterators are never invalidated when
//! inserting or erasing elements. Iterators are only invalidated when rehasing.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
template<class T, class ...Options>
#else
template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class SizeType, class BucketTraits, std::size_t BoolFlags>
#endif
class unordered_set_impl
: public hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags|hash_bool_flags::unique_keys_pos>
{
/// @cond
private:
typedef hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags|hash_bool_flags::unique_keys_pos> table_type;
template<class Iterator, class MaybeConstThis, class KeyType, class KeyHasher, class KeyEqual>
static std::pair<Iterator,Iterator> priv_equal_range(MaybeConstThis &c, const KeyType& key, KeyHasher hash_func, KeyEqual equal_func)
{
Iterator const it = c.find(key, hash_func, equal_func);
std::pair<Iterator,Iterator> ret(it, it);
if(it != c.end())
++ret.second;
return ret;
}
//! This class is
//! movable
BOOST_MOVABLE_BUT_NOT_COPYABLE(unordered_set_impl)
typedef table_type implementation_defined;
/// @endcond
public:
typedef typename implementation_defined::value_type value_type;
typedef typename implementation_defined::key_type key_type;
typedef typename implementation_defined::key_of_value key_of_value;
typedef typename implementation_defined::value_traits value_traits;
typedef typename implementation_defined::bucket_traits bucket_traits;
typedef typename implementation_defined::pointer pointer;
typedef typename implementation_defined::const_pointer const_pointer;
typedef typename implementation_defined::reference reference;
typedef typename implementation_defined::const_reference const_reference;
typedef typename implementation_defined::difference_type difference_type;
typedef typename implementation_defined::size_type size_type;
typedef typename implementation_defined::key_equal key_equal;
typedef typename implementation_defined::hasher hasher;
typedef typename implementation_defined::bucket_type bucket_type;
typedef typename implementation_defined::bucket_ptr bucket_ptr;
typedef typename implementation_defined::iterator iterator;
typedef typename implementation_defined::const_iterator const_iterator;
typedef typename implementation_defined::insert_commit_data insert_commit_data;
typedef typename implementation_defined::local_iterator local_iterator;
typedef typename implementation_defined::const_local_iterator const_local_iterator;
typedef typename implementation_defined::node_traits node_traits;
typedef typename implementation_defined::node node;
typedef typename implementation_defined::node_ptr node_ptr;
typedef typename implementation_defined::const_node_ptr const_node_ptr;
typedef typename implementation_defined::node_algorithms node_algorithms;
public:
//! @copydoc ::boost::intrusive::hashtable::hashtable(const bucket_traits &,const hasher &,const key_equal &,const value_traits &)
BOOST_INTRUSIVE_FORCEINLINE explicit unordered_set_impl( const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: table_type(b_traits, hash_func, equal_func, v_traits)
{}
//! @copydoc ::boost::intrusive::hashtable::hashtable(bool,Iterator,Iterator,const bucket_traits &,const hasher &,const key_equal &,const value_traits &)
template<class Iterator>
BOOST_INTRUSIVE_FORCEINLINE unordered_set_impl( Iterator b
, Iterator e
, const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: table_type(true, b, e, b_traits, hash_func, equal_func, v_traits)
{}
//! @copydoc ::boost::intrusive::hashtable::hashtable(hashtable&&)
BOOST_INTRUSIVE_FORCEINLINE unordered_set_impl(BOOST_RV_REF(unordered_set_impl) x)
: table_type(BOOST_MOVE_BASE(table_type, x))
{}
//! @copydoc ::boost::intrusive::hashtable::operator=(hashtable&&)
BOOST_INTRUSIVE_FORCEINLINE unordered_set_impl& operator=(BOOST_RV_REF(unordered_set_impl) x)
{ return static_cast<unordered_set_impl&>(table_type::operator=(BOOST_MOVE_BASE(table_type, x))); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::hashtable::~hashtable()
~unordered_set_impl();
//! @copydoc ::boost::intrusive::hashtable::begin()
iterator begin();
//! @copydoc ::boost::intrusive::hashtable::begin()const
const_iterator begin() const;
//! @copydoc ::boost::intrusive::hashtable::cbegin()const
const_iterator cbegin() const;
//! @copydoc ::boost::intrusive::hashtable::end()
iterator end();
//! @copydoc ::boost::intrusive::hashtable::end()const
const_iterator end() const;
//! @copydoc ::boost::intrusive::hashtable::cend()const
const_iterator cend() const;
//! @copydoc ::boost::intrusive::hashtable::hash_function()const
hasher hash_function() const;
//! @copydoc ::boost::intrusive::hashtable::key_eq()const
key_equal key_eq() const;
//! @copydoc ::boost::intrusive::hashtable::empty()const
bool empty() const;
//! @copydoc ::boost::intrusive::hashtable::size()const
size_type size() const;
//! @copydoc ::boost::intrusive::hashtable::hashtable
void swap(unordered_set_impl& other);
//! @copydoc ::boost::intrusive::hashtable::clone_from(const hashtable&,Cloner,Disposer)
template <class Cloner, class Disposer>
void clone_from(const unordered_set_impl &src, Cloner cloner, Disposer disposer);
#else
using table_type::clone_from;
#endif //#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::hashtable::clone_from(hashtable&&,Cloner,Disposer)
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(unordered_set_impl) src, Cloner cloner, Disposer disposer)
{ table_type::clone_from(BOOST_MOVE_BASE(table_type, src), cloner, disposer); }
//! @copydoc ::boost::intrusive::hashtable::insert_unique(reference)
BOOST_INTRUSIVE_FORCEINLINE std::pair<iterator, bool> insert(reference value)
{ return table_type::insert_unique(value); }
//! @copydoc ::boost::intrusive::hashtable::insert_unique(Iterator,Iterator)
template<class Iterator>
BOOST_INTRUSIVE_FORCEINLINE void insert(Iterator b, Iterator e)
{ table_type::insert_unique(b, e); }
//! @copydoc ::boost::intrusive::hashtable::insert_unique_check(const key_type&,insert_commit_data&)
BOOST_INTRUSIVE_FORCEINLINE std::pair<iterator, bool> insert_check(const key_type &key, insert_commit_data &commit_data)
{ return table_type::insert_unique_check(key, commit_data); }
//! @copydoc ::boost::intrusive::hashtable::insert_unique_check(const KeyType&,KeyHasher,KeyEqual,insert_commit_data&)
template<class KeyType, class KeyHasher, class KeyEqual>
BOOST_INTRUSIVE_FORCEINLINE std::pair<iterator, bool> insert_check
(const KeyType &key, KeyHasher hasher, KeyEqual key_value_equal, insert_commit_data &commit_data)
{ return table_type::insert_unique_check(key, hasher, key_value_equal, commit_data); }
//! @copydoc ::boost::intrusive::hashtable::insert_unique_commit
BOOST_INTRUSIVE_FORCEINLINE iterator insert_commit(reference value, const insert_commit_data &commit_data)
{ return table_type::insert_unique_commit(value, commit_data); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::hashtable::erase(const_iterator)
void erase(const_iterator i);
//! @copydoc ::boost::intrusive::hashtable::erase(const_iterator,const_iterator)
void erase(const_iterator b, const_iterator e);
//! @copydoc ::boost::intrusive::hashtable::erase(const key_type &)
size_type erase(const key_type &key);
//! @copydoc ::boost::intrusive::hashtable::erase(const KeyType&,KeyHasher,KeyEqual)
template<class KeyType, class KeyHasher, class KeyEqual>
size_type erase(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const_iterator,Disposer)
template<class Disposer>
BOOST_INTRUSIVE_DOC1ST(void
, typename detail::disable_if_convertible<Disposer BOOST_INTRUSIVE_I const_iterator>::type)
erase_and_dispose(const_iterator i, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const_iterator,const_iterator,Disposer)
template<class Disposer>
void erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const key_type &,Disposer)
template<class Disposer>
size_type erase_and_dispose(const key_type &key, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const KeyType&,KeyHasher,KeyEqual,Disposer)
template<class KeyType, class KeyHasher, class KeyEqual, class Disposer>
size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::clear
void clear();
//! @copydoc ::boost::intrusive::hashtable::clear_and_dispose
template<class Disposer>
void clear_and_dispose(Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::count(const key_type &)const
size_type count(const key_type &key) const;
//! @copydoc ::boost::intrusive::hashtable::count(const KeyType&,KeyHasher,KeyEqual)const
template<class KeyType, class KeyHasher, class KeyEqual>
size_type count(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func) const;
//! @copydoc ::boost::intrusive::hashtable::find(const key_type &)
iterator find(const key_type &key);
//! @copydoc ::boost::intrusive::hashtable::find(const KeyType &,KeyHasher,KeyEqual)
template<class KeyType, class KeyHasher, class KeyEqual>
iterator find(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func);
//! @copydoc ::boost::intrusive::hashtable::count(const key_type &)const
const_iterator find(const key_type &key) const;
//! @copydoc ::boost::intrusive::hashtable::find(const KeyType &,KeyHasher,KeyEqual)const
template<class KeyType, class KeyHasher, class KeyEqual>
const_iterator find(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func) const;
#endif
//! @copydoc ::boost::intrusive::hashtable::equal_range(const key_type&)
std::pair<iterator,iterator> equal_range(const key_type &key)
{ return this->equal_range(key, this->hash_function(), this->key_eq()); }
//! @copydoc ::boost::intrusive::hashtable::equal_range(const KeyType &,KeyHasher,KeyEqual)
template<class KeyType, class KeyHasher, class KeyEqual>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func)
{ return this->priv_equal_range<iterator>(*this, key, hash_func, equal_func); }
//! @copydoc ::boost::intrusive::hashtable::equal_range(const key_type&)const
std::pair<const_iterator, const_iterator>
equal_range(const key_type &key) const
{ return this->equal_range(key, this->hash_function(), this->key_eq()); }
//! @copydoc ::boost::intrusive::hashtable::equal_range(const KeyType &,KeyHasher,KeyEqual)const
template<class KeyType, class KeyHasher, class KeyEqual>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func) const
{ return this->priv_equal_range<const_iterator>(*this, key, hash_func, equal_func); }
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
//! @copydoc ::boost::intrusive::hashtable::iterator_to(reference)
iterator iterator_to(reference value);
//! @copydoc ::boost::intrusive::hashtable::iterator_to(const_reference)const
const_iterator iterator_to(const_reference value) const;
//! @copydoc ::boost::intrusive::hashtable::s_local_iterator_to(reference)
static local_iterator s_local_iterator_to(reference value);
//! @copydoc ::boost::intrusive::hashtable::s_local_iterator_to(const_reference)
static const_local_iterator s_local_iterator_to(const_reference value);
//! @copydoc ::boost::intrusive::hashtable::local_iterator_to(reference)
local_iterator local_iterator_to(reference value);
//! @copydoc ::boost::intrusive::hashtable::local_iterator_to(const_reference)
const_local_iterator local_iterator_to(const_reference value) const;
//! @copydoc ::boost::intrusive::hashtable::bucket_count
size_type bucket_count() const;
//! @copydoc ::boost::intrusive::hashtable::bucket_size
size_type bucket_size(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::bucket(const key_type&)const
size_type bucket(const key_type& k) const;
//! @copydoc ::boost::intrusive::hashtable::bucket(const KeyType&,KeyHasher)const
template<class KeyType, class KeyHasher>
size_type bucket(const KeyType& k, KeyHasher hash_func) const;
//! @copydoc ::boost::intrusive::hashtable::bucket_pointer
bucket_ptr bucket_pointer() const;
//! @copydoc ::boost::intrusive::hashtable::begin(size_type)
local_iterator begin(size_type n);
//! @copydoc ::boost::intrusive::hashtable::begin(size_type)const
const_local_iterator begin(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::cbegin(size_type)const
const_local_iterator cbegin(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::end(size_type)
local_iterator end(size_type n);
//! @copydoc ::boost::intrusive::hashtable::end(size_type)const
const_local_iterator end(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::cend(size_type)const
const_local_iterator cend(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::rehash(const bucket_traits &)
void rehash(const bucket_traits &new_bucket_traits);
//! @copydoc ::boost::intrusive::hashtable::full_rehash
void full_rehash();
//! @copydoc ::boost::intrusive::hashtable::incremental_rehash(bool)
bool incremental_rehash(bool grow = true);
//! @copydoc ::boost::intrusive::hashtable::incremental_rehash(const bucket_traits &)
bool incremental_rehash(const bucket_traits &new_bucket_traits);
//! @copydoc ::boost::intrusive::hashtable::split_count
size_type split_count() const;
//! @copydoc ::boost::intrusive::hashtable::suggested_upper_bucket_count
static size_type suggested_upper_bucket_count(size_type n);
//! @copydoc ::boost::intrusive::hashtable::suggested_lower_bucket_count
static size_type suggested_lower_bucket_count(size_type n);
#endif // #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
friend bool operator==(const unordered_set_impl &x, const unordered_set_impl &y)
{
if(table_type::constant_time_size && x.size() != y.size()){
return false;
}
//Find each element of x in y
for (const_iterator ix = x.cbegin(), ex = x.cend(), ey = y.cend(); ix != ex; ++ix){
const_iterator iy = y.find(key_of_value()(*ix));
if (iy == ey || !(*ix == *iy))
return false;
}
return true;
}
friend bool operator!=(const unordered_set_impl &x, const unordered_set_impl &y)
{ return !(x == y); }
friend bool operator<(const unordered_set_impl &x, const unordered_set_impl &y)
{ return ::boost::intrusive::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
friend bool operator>(const unordered_set_impl &x, const unordered_set_impl &y)
{ return y < x; }
friend bool operator<=(const unordered_set_impl &x, const unordered_set_impl &y)
{ return !(y < x); }
friend bool operator>=(const unordered_set_impl &x, const unordered_set_impl &y)
{ return !(x < y); }
};
//! Helper metafunction to define an \c unordered_set that yields to the same type when the
//! same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class ...Options>
#else
template<class T, class O1 = void, class O2 = void
, class O3 = void, class O4 = void
, class O5 = void, class O6 = void
, class O7 = void, class O8 = void
, class O9 = void, class O10= void
>
#endif
struct make_unordered_set
{
/// @cond
typedef typename pack_options
< hashtable_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
#else
Options...
#endif
>::type packed_options;
typedef typename detail::get_value_traits
<T, typename packed_options::proto_value_traits>::type value_traits;
typedef typename make_bucket_traits
<T, true, packed_options>::type bucket_traits;
typedef unordered_set_impl
< value_traits
, typename packed_options::key_of_value
, typename packed_options::hash
, typename packed_options::equal
, typename packed_options::size_type
, bucket_traits
, (std::size_t(true)*hash_bool_flags::unique_keys_pos)
| (std::size_t(packed_options::constant_time_size)*hash_bool_flags::constant_time_size_pos)
| (std::size_t(packed_options::power_2_buckets)*hash_bool_flags::power_2_buckets_pos)
| (std::size_t(packed_options::cache_begin)*hash_bool_flags::cache_begin_pos)
| (std::size_t(packed_options::compare_hash)*hash_bool_flags::compare_hash_pos)
| (std::size_t(packed_options::incremental)*hash_bool_flags::incremental_pos)
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10>
#else
template<class T, class ...Options>
#endif
class unordered_set
: public make_unordered_set<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
#else
Options...
#endif
>::type
{
typedef typename make_unordered_set
<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
#else
Options...
#endif
>::type Base;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename Base::value_traits::value_type, T>::value));
BOOST_MOVABLE_BUT_NOT_COPYABLE(unordered_set)
public:
typedef typename Base::value_traits value_traits;
typedef typename Base::bucket_traits bucket_traits;
typedef typename Base::iterator iterator;
typedef typename Base::const_iterator const_iterator;
typedef typename Base::bucket_ptr bucket_ptr;
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
explicit unordered_set ( const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: Base(b_traits, hash_func, equal_func, v_traits)
{}
template<class Iterator>
BOOST_INTRUSIVE_FORCEINLINE unordered_set
( Iterator b, Iterator e
, const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: Base(b, e, b_traits, hash_func, equal_func, v_traits)
{}
BOOST_INTRUSIVE_FORCEINLINE unordered_set(BOOST_RV_REF(unordered_set) x)
: Base(BOOST_MOVE_BASE(Base, x))
{}
BOOST_INTRUSIVE_FORCEINLINE unordered_set& operator=(BOOST_RV_REF(unordered_set) x)
{ return static_cast<unordered_set&>(this->Base::operator=(BOOST_MOVE_BASE(Base, x))); }
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(const unordered_set &src, Cloner cloner, Disposer disposer)
{ Base::clone_from(src, cloner, disposer); }
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(unordered_set) src, Cloner cloner, Disposer disposer)
{ Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
};
#endif
//! The class template unordered_multiset is an intrusive container, that mimics most of
//! the interface of std::tr1::unordered_multiset as described in the C++ TR1.
//!
//! unordered_multiset is a semi-intrusive container: each object to be stored in the
//! container must contain a proper hook, but the container also needs
//! additional auxiliary memory to work: unordered_multiset needs a pointer to an array
//! of type `bucket_type` to be passed in the constructor. This bucket array must
//! have at least the same lifetime as the container. This makes the use of
//! unordered_multiset more complicated than purely intrusive containers.
//! `bucket_type` is default-constructible, copyable and assignable
//!
//! The template parameter \c T is the type to be managed by the container.
//! The user can specify additional options and if no options are provided
//! default options are used.
//!
//! The container supports the following options:
//! \c base_hook<>/member_hook<>/value_traits<>,
//! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<>
//! \c bucket_traits<>, \c power_2_buckets<> and \c cache_begin<>.
//!
//! unordered_multiset only provides forward iterators but it provides 4 iterator types:
//! iterator and const_iterator to navigate through the whole container and
//! local_iterator and const_local_iterator to navigate through the values
//! stored in a single bucket. Local iterators are faster and smaller.
//!
//! It's not recommended to use non constant-time size unordered_multisets because several
//! key functions, like "empty()", become non-constant time functions. Non
//! constant-time size unordered_multisets are mainly provided to support auto-unlink hooks.
//!
//! unordered_multiset, unlike std::unordered_set, does not make automatic rehashings nor
//! offers functions related to a load factor. Rehashing can be explicitly requested
//! and the user must provide a new bucket array that will be used from that moment.
//!
//! Since no automatic rehashing is done, iterators are never invalidated when
//! inserting or erasing elements. Iterators are only invalidated when rehasing.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
template<class T, class ...Options>
#else
template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class SizeType, class BucketTraits, std::size_t BoolFlags>
#endif
class unordered_multiset_impl
: public hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags>
{
/// @cond
private:
typedef hashtable_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, SizeType, BoolFlags> table_type;
/// @endcond
//Movable
BOOST_MOVABLE_BUT_NOT_COPYABLE(unordered_multiset_impl)
typedef table_type implementation_defined;
public:
typedef typename implementation_defined::value_type value_type;
typedef typename implementation_defined::key_type key_type;
typedef typename implementation_defined::value_traits value_traits;
typedef typename implementation_defined::bucket_traits bucket_traits;
typedef typename implementation_defined::pointer pointer;
typedef typename implementation_defined::const_pointer const_pointer;
typedef typename implementation_defined::reference reference;
typedef typename implementation_defined::const_reference const_reference;
typedef typename implementation_defined::difference_type difference_type;
typedef typename implementation_defined::size_type size_type;
typedef typename implementation_defined::key_equal key_equal;
typedef typename implementation_defined::hasher hasher;
typedef typename implementation_defined::bucket_type bucket_type;
typedef typename implementation_defined::bucket_ptr bucket_ptr;
typedef typename implementation_defined::iterator iterator;
typedef typename implementation_defined::const_iterator const_iterator;
typedef typename implementation_defined::insert_commit_data insert_commit_data;
typedef typename implementation_defined::local_iterator local_iterator;
typedef typename implementation_defined::const_local_iterator const_local_iterator;
typedef typename implementation_defined::node_traits node_traits;
typedef typename implementation_defined::node node;
typedef typename implementation_defined::node_ptr node_ptr;
typedef typename implementation_defined::const_node_ptr const_node_ptr;
typedef typename implementation_defined::node_algorithms node_algorithms;
public:
//! @copydoc ::boost::intrusive::hashtable::hashtable(const bucket_traits &,const hasher &,const key_equal &,const value_traits &)
BOOST_INTRUSIVE_FORCEINLINE explicit unordered_multiset_impl ( const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: table_type(b_traits, hash_func, equal_func, v_traits)
{}
//! @copydoc ::boost::intrusive::hashtable::hashtable(bool,Iterator,Iterator,const bucket_traits &,const hasher &,const key_equal &,const value_traits &)
template<class Iterator>
BOOST_INTRUSIVE_FORCEINLINE unordered_multiset_impl ( Iterator b
, Iterator e
, const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: table_type(false, b, e, b_traits, hash_func, equal_func, v_traits)
{}
//! <b>Effects</b>: to-do
//!
BOOST_INTRUSIVE_FORCEINLINE unordered_multiset_impl(BOOST_RV_REF(unordered_multiset_impl) x)
: table_type(BOOST_MOVE_BASE(table_type, x))
{}
//! <b>Effects</b>: to-do
//!
BOOST_INTRUSIVE_FORCEINLINE unordered_multiset_impl& operator=(BOOST_RV_REF(unordered_multiset_impl) x)
{ return static_cast<unordered_multiset_impl&>(table_type::operator=(BOOST_MOVE_BASE(table_type, x))); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::hashtable::~hashtable()
~unordered_multiset_impl();
//! @copydoc ::boost::intrusive::hashtable::begin()
iterator begin();
//! @copydoc ::boost::intrusive::hashtable::begin()const
const_iterator begin() const;
//! @copydoc ::boost::intrusive::hashtable::cbegin()const
const_iterator cbegin() const;
//! @copydoc ::boost::intrusive::hashtable::end()
iterator end();
//! @copydoc ::boost::intrusive::hashtable::end()const
const_iterator end() const;
//! @copydoc ::boost::intrusive::hashtable::cend()const
const_iterator cend() const;
//! @copydoc ::boost::intrusive::hashtable::hash_function()const
hasher hash_function() const;
//! @copydoc ::boost::intrusive::hashtable::key_eq()const
key_equal key_eq() const;
//! @copydoc ::boost::intrusive::hashtable::empty()const
bool empty() const;
//! @copydoc ::boost::intrusive::hashtable::size()const
size_type size() const;
//! @copydoc ::boost::intrusive::hashtable::hashtable
void swap(unordered_multiset_impl& other);
//! @copydoc ::boost::intrusive::hashtable::clone_from(const hashtable&,Cloner,Disposer)
template <class Cloner, class Disposer>
void clone_from(const unordered_multiset_impl &src, Cloner cloner, Disposer disposer);
#else
using table_type::clone_from;
#endif // #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::hashtable::clone_from(hashtable&&,Cloner,Disposer)
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(unordered_multiset_impl) src, Cloner cloner, Disposer disposer)
{ table_type::clone_from(BOOST_MOVE_BASE(table_type, src), cloner, disposer); }
//! @copydoc ::boost::intrusive::hashtable::insert_equal(reference)
BOOST_INTRUSIVE_FORCEINLINE iterator insert(reference value)
{ return table_type::insert_equal(value); }
//! @copydoc ::boost::intrusive::hashtable::insert_equal(Iterator,Iterator)
template<class Iterator>
BOOST_INTRUSIVE_FORCEINLINE void insert(Iterator b, Iterator e)
{ table_type::insert_equal(b, e); }
#ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
//! @copydoc ::boost::intrusive::hashtable::erase(const_iterator)
void erase(const_iterator i);
//! @copydoc ::boost::intrusive::hashtable::erase(const_iterator,const_iterator)
void erase(const_iterator b, const_iterator e);
//! @copydoc ::boost::intrusive::hashtable::erase(const key_type &)
size_type erase(const key_type &key);
//! @copydoc ::boost::intrusive::hashtable::erase(const KeyType&,KeyHasher,KeyEqual)
template<class KeyType, class KeyHasher, class KeyEqual>
size_type erase(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const_iterator,Disposer)
template<class Disposer>
BOOST_INTRUSIVE_DOC1ST(void
, typename detail::disable_if_convertible<Disposer BOOST_INTRUSIVE_I const_iterator>::type)
erase_and_dispose(const_iterator i, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const_iterator,const_iterator,Disposer)
template<class Disposer>
void erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const key_type &,Disposer)
template<class Disposer>
size_type erase_and_dispose(const key_type &key, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::erase_and_dispose(const KeyType&,KeyHasher,KeyEqual,Disposer)
template<class KeyType, class KeyHasher, class KeyEqual, class Disposer>
size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func, Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::clear
void clear();
//! @copydoc ::boost::intrusive::hashtable::clear_and_dispose
template<class Disposer>
void clear_and_dispose(Disposer disposer);
//! @copydoc ::boost::intrusive::hashtable::count(const key_type &)const
size_type count(const key_type &key) const;
//! @copydoc ::boost::intrusive::hashtable::count(const KeyType&,KeyHasher,KeyEqual)const
template<class KeyType, class KeyHasher, class KeyEqual>
size_type count(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func) const;
//! @copydoc ::boost::intrusive::hashtable::find(const key_type &)
iterator find(const key_type &key);
//! @copydoc ::boost::intrusive::hashtable::find(const KeyType &,KeyHasher,KeyEqual)
template<class KeyType, class KeyHasher, class KeyEqual>
iterator find(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func);
//! @copydoc ::boost::intrusive::hashtable::count(const key_type &)const
const_iterator find(const key_type &key) const;
//! @copydoc ::boost::intrusive::hashtable::find(const KeyType &,KeyHasher,KeyEqual)const
template<class KeyType, class KeyHasher, class KeyEqual>
const_iterator find(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func) const;
//! @copydoc ::boost::intrusive::hashtable::equal_range(const key_type&)
std::pair<iterator,iterator> equal_range(const key_type &key);
//! @copydoc ::boost::intrusive::hashtable::equal_range(const KeyType &,KeyHasher,KeyEqual)
template<class KeyType, class KeyHasher, class KeyEqual>
std::pair<iterator,iterator> equal_range(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func);
//! @copydoc ::boost::intrusive::hashtable::equal_range(const key_type&)const
std::pair<const_iterator, const_iterator>
equal_range(const key_type &key) const;
//! @copydoc ::boost::intrusive::hashtable::equal_range(const KeyType &,KeyHasher,KeyEqual)const
template<class KeyType, class KeyHasher, class KeyEqual>
std::pair<const_iterator, const_iterator>
equal_range(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func) const;
//! @copydoc ::boost::intrusive::hashtable::iterator_to(reference)
iterator iterator_to(reference value);
//! @copydoc ::boost::intrusive::hashtable::iterator_to(const_reference)const
const_iterator iterator_to(const_reference value) const;
//! @copydoc ::boost::intrusive::hashtable::s_local_iterator_to(reference)
static local_iterator s_local_iterator_to(reference value);
//! @copydoc ::boost::intrusive::hashtable::s_local_iterator_to(const_reference)
static const_local_iterator s_local_iterator_to(const_reference value);
//! @copydoc ::boost::intrusive::hashtable::local_iterator_to(reference)
local_iterator local_iterator_to(reference value);
//! @copydoc ::boost::intrusive::hashtable::local_iterator_to(const_reference)
const_local_iterator local_iterator_to(const_reference value) const;
//! @copydoc ::boost::intrusive::hashtable::bucket_count
size_type bucket_count() const;
//! @copydoc ::boost::intrusive::hashtable::bucket_size
size_type bucket_size(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::bucket(const key_type&)const
size_type bucket(const key_type& k) const;
//! @copydoc ::boost::intrusive::hashtable::bucket(const KeyType&,KeyHasher)const
template<class KeyType, class KeyHasher>
size_type bucket(const KeyType& k, KeyHasher hash_func) const;
//! @copydoc ::boost::intrusive::hashtable::bucket_pointer
bucket_ptr bucket_pointer() const;
//! @copydoc ::boost::intrusive::hashtable::begin(size_type)
local_iterator begin(size_type n);
//! @copydoc ::boost::intrusive::hashtable::begin(size_type)const
const_local_iterator begin(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::cbegin(size_type)const
const_local_iterator cbegin(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::end(size_type)
local_iterator end(size_type n);
//! @copydoc ::boost::intrusive::hashtable::end(size_type)const
const_local_iterator end(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::cend(size_type)const
const_local_iterator cend(size_type n) const;
//! @copydoc ::boost::intrusive::hashtable::rehash(const bucket_traits &)
void rehash(const bucket_traits &new_bucket_traits);
//! @copydoc ::boost::intrusive::hashtable::full_rehash
void full_rehash();
//! @copydoc ::boost::intrusive::hashtable::incremental_rehash(bool)
bool incremental_rehash(bool grow = true);
//! @copydoc ::boost::intrusive::hashtable::incremental_rehash(const bucket_traits &)
bool incremental_rehash(const bucket_traits &new_bucket_traits);
//! @copydoc ::boost::intrusive::hashtable::split_count
size_type split_count() const;
//! @copydoc ::boost::intrusive::hashtable::suggested_upper_bucket_count
static size_type suggested_upper_bucket_count(size_type n);
//! @copydoc ::boost::intrusive::hashtable::suggested_lower_bucket_count
static size_type suggested_lower_bucket_count(size_type n);
#endif // #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED
};
//! Helper metafunction to define an \c unordered_multiset that yields to the same type when the
//! same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class ...Options>
#else
template<class T, class O1 = void, class O2 = void
, class O3 = void, class O4 = void
, class O5 = void, class O6 = void
, class O7 = void, class O8 = void
, class O9 = void, class O10= void
>
#endif
struct make_unordered_multiset
{
/// @cond
typedef typename pack_options
< hashtable_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
#else
Options...
#endif
>::type packed_options;
typedef typename detail::get_value_traits
<T, typename packed_options::proto_value_traits>::type value_traits;
typedef typename make_bucket_traits
<T, true, packed_options>::type bucket_traits;
typedef unordered_multiset_impl
< value_traits
, typename packed_options::key_of_value
, typename packed_options::hash
, typename packed_options::equal
, typename packed_options::size_type
, bucket_traits
, (std::size_t(false)*hash_bool_flags::unique_keys_pos)
| (std::size_t(packed_options::constant_time_size)*hash_bool_flags::constant_time_size_pos)
| (std::size_t(packed_options::power_2_buckets)*hash_bool_flags::power_2_buckets_pos)
| (std::size_t(packed_options::cache_begin)*hash_bool_flags::cache_begin_pos)
| (std::size_t(packed_options::compare_hash)*hash_bool_flags::compare_hash_pos)
| (std::size_t(packed_options::incremental)*hash_bool_flags::incremental_pos)
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#ifndef BOOST_INTRUSIVE_DOXYGEN_INVOKED
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10>
#else
template<class T, class ...Options>
#endif
class unordered_multiset
: public make_unordered_multiset<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
#else
Options...
#endif
>::type
{
typedef typename make_unordered_multiset
<T,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
#else
Options...
#endif
>::type Base;
//Assert if passed value traits are compatible with the type
BOOST_STATIC_ASSERT((detail::is_same<typename Base::value_traits::value_type, T>::value));
BOOST_MOVABLE_BUT_NOT_COPYABLE(unordered_multiset)
public:
typedef typename Base::value_traits value_traits;
typedef typename Base::bucket_traits bucket_traits;
typedef typename Base::iterator iterator;
typedef typename Base::const_iterator const_iterator;
typedef typename Base::bucket_ptr bucket_ptr;
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
explicit unordered_multiset( const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: Base(b_traits, hash_func, equal_func, v_traits)
{}
template<class Iterator> BOOST_INTRUSIVE_FORCEINLINE
unordered_multiset( Iterator b
, Iterator e
, const bucket_traits &b_traits
, const hasher & hash_func = hasher()
, const key_equal &equal_func = key_equal()
, const value_traits &v_traits = value_traits())
: Base(b, e, b_traits, hash_func, equal_func, v_traits)
{}
BOOST_INTRUSIVE_FORCEINLINE unordered_multiset(BOOST_RV_REF(unordered_multiset) x)
: Base(BOOST_MOVE_BASE(Base, x))
{}
BOOST_INTRUSIVE_FORCEINLINE unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x)
{ return static_cast<unordered_multiset&>(this->Base::operator=(BOOST_MOVE_BASE(Base, x))); }
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(const unordered_multiset &src, Cloner cloner, Disposer disposer)
{ Base::clone_from(src, cloner, disposer); }
template <class Cloner, class Disposer>
BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(unordered_multiset) src, Cloner cloner, Disposer disposer)
{ Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
};
#endif
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_UNORDERED_SET_HPP

View File

@ -0,0 +1,459 @@
/////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Olaf Krzikalla 2004-2006.
// (C) Copyright Ion Gaztanaga 2006-2013
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/intrusive for documentation.
//
/////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
#define BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP
#include <boost/intrusive/detail/config_begin.hpp>
#include <boost/intrusive/intrusive_fwd.hpp>
#include <boost/intrusive/pointer_traits.hpp>
#include <boost/intrusive/slist_hook.hpp>
#include <boost/intrusive/options.hpp>
#include <boost/intrusive/detail/generic_hook.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
namespace boost {
namespace intrusive {
/// @cond
template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
struct unordered_node
: public slist_node<VoidPointer>
{
typedef typename pointer_traits
<VoidPointer>::template rebind_pointer
< unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> >::type
node_ptr;
node_ptr prev_in_group_;
std::size_t hash_;
};
template<class VoidPointer>
struct unordered_node<VoidPointer, false, true>
: public slist_node<VoidPointer>
{
typedef typename pointer_traits
<VoidPointer>::template rebind_pointer
< unordered_node<VoidPointer, false, true> >::type
node_ptr;
node_ptr prev_in_group_;
};
template<class VoidPointer>
struct unordered_node<VoidPointer, true, false>
: public slist_node<VoidPointer>
{
typedef typename pointer_traits
<VoidPointer>::template rebind_pointer
< unordered_node<VoidPointer, true, false> >::type
node_ptr;
std::size_t hash_;
};
template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
struct unordered_node_traits
: public slist_node_traits<VoidPointer>
{
typedef slist_node_traits<VoidPointer> reduced_slist_node_traits;
typedef unordered_node<VoidPointer, StoreHash, OptimizeMultiKey> node;
typedef typename pointer_traits
<VoidPointer>::template rebind_pointer
< node >::type node_ptr;
typedef typename pointer_traits
<VoidPointer>::template rebind_pointer
< const node >::type const_node_ptr;
static const bool store_hash = StoreHash;
static const bool optimize_multikey = OptimizeMultiKey;
static node_ptr get_next(const const_node_ptr & n)
{ return pointer_traits<node_ptr>::static_cast_from(n->next_); }
static void set_next(const node_ptr & n, const node_ptr & next)
{ n->next_ = next; }
static node_ptr get_prev_in_group(const const_node_ptr & n)
{ return n->prev_in_group_; }
static void set_prev_in_group(const node_ptr & n, const node_ptr & prev)
{ n->prev_in_group_ = prev; }
static std::size_t get_hash(const const_node_ptr & n)
{ return n->hash_; }
static void set_hash(const node_ptr & n, std::size_t h)
{ n->hash_ = h; }
};
template<class NodeTraits>
struct unordered_group_adapter
{
typedef typename NodeTraits::node node;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
static node_ptr get_next(const const_node_ptr & n)
{ return NodeTraits::get_prev_in_group(n); }
static void set_next(const node_ptr & n, const node_ptr & next)
{ NodeTraits::set_prev_in_group(n, next); }
};
template<class NodeTraits>
struct unordered_algorithms
: public circular_slist_algorithms<NodeTraits>
{
typedef circular_slist_algorithms<NodeTraits> base_type;
typedef unordered_group_adapter<NodeTraits> group_traits;
typedef circular_slist_algorithms<group_traits> group_algorithms;
typedef NodeTraits node_traits;
typedef typename NodeTraits::node node;
typedef typename NodeTraits::node_ptr node_ptr;
typedef typename NodeTraits::const_node_ptr const_node_ptr;
static void init(typename base_type::node_ptr n)
{
base_type::init(n);
group_algorithms::init(n);
}
static void init_header(typename base_type::node_ptr n)
{
base_type::init_header(n);
group_algorithms::init_header(n);
}
static void unlink(typename base_type::node_ptr n)
{
base_type::unlink(n);
group_algorithms::unlink(n);
}
};
//Class to avoid defining the same algo as a circular list, as hooks would be ambiguous between them
template<class Algo>
struct uset_algo_wrapper : public Algo
{};
template<class VoidPointer, bool StoreHash, bool OptimizeMultiKey>
struct get_uset_node_traits
{
typedef typename detail::if_c
< (StoreHash || OptimizeMultiKey)
, unordered_node_traits<VoidPointer, StoreHash, OptimizeMultiKey>
, slist_node_traits<VoidPointer>
>::type type;
};
template<bool OptimizeMultiKey>
struct get_uset_algo_type
{
static const algo_types value = OptimizeMultiKey ? UnorderedAlgorithms : UnorderedCircularSlistAlgorithms;
};
template<class NodeTraits>
struct get_algo<UnorderedAlgorithms, NodeTraits>
{
typedef unordered_algorithms<NodeTraits> type;
};
template<class NodeTraits>
struct get_algo<UnorderedCircularSlistAlgorithms, NodeTraits>
{
typedef uset_algo_wrapper< circular_slist_algorithms<NodeTraits> > type;
};
/// @endcond
//! Helper metafunction to define a \c unordered_set_base_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
#endif
struct make_unordered_set_base_hook
{
/// @cond
typedef typename pack_options
< hook_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type packed_options;
typedef generic_hook
< get_uset_algo_type <packed_options::optimize_multikey>::value
, typename get_uset_node_traits < typename packed_options::void_pointer
, packed_options::store_hash
, packed_options::optimize_multikey
>::type
, typename packed_options::tag
, packed_options::link_mode
, HashBaseHookId
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Derive a class from unordered_set_base_hook in order to store objects in
//! in an unordered_set/unordered_multi_set. unordered_set_base_hook holds the data necessary to maintain
//! the unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
//!
//! The hook admits the following options: \c tag<>, \c void_pointer<>,
//! \c link_mode<>, \c store_hash<> and \c optimize_multikey<>.
//!
//! \c tag<> defines a tag to identify the node.
//! The same tag value can be used in different classes, but if a class is
//! derived from more than one \c list_base_hook, then each \c list_base_hook needs its
//! unique tag.
//!
//! \c void_pointer<> is the pointer type that will be used internally in the hook
//! and the container configured to use this hook.
//!
//! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
//! \c auto_unlink or \c safe_link).
//!
//! \c store_hash<> will tell the hook to store the hash of the value
//! to speed up rehashings.
//!
//! \c optimize_multikey<> will tell the hook to store a link to form a group
//! with other value with the same value to speed up searches and insertions
//! in unordered_multisets with a great number of with equivalent keys.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1, class O2, class O3, class O4>
#endif
class unordered_set_base_hook
: public make_unordered_set_base_hook<
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type
{
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
public:
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
unordered_set_base_hook();
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
unordered_set_base_hook(const unordered_set_base_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
unordered_set_base_hook& operator=(const unordered_set_base_hook& );
//! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in an unordered_set an assertion is raised. If link_mode is
//! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
~unordered_set_base_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(unordered_set_base_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c unordered_set::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
void unlink();
#endif
};
//! Helper metafunction to define a \c unordered_set_member_hook that yields to the same
//! type when the same options (either explicitly or implicitly) are used.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
#endif
struct make_unordered_set_member_hook
{
/// @cond
typedef typename pack_options
< hook_defaults,
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type packed_options;
typedef generic_hook
< get_uset_algo_type <packed_options::optimize_multikey>::value
, typename get_uset_node_traits < typename packed_options::void_pointer
, packed_options::store_hash
, packed_options::optimize_multikey
>::type
, member_tag
, packed_options::link_mode
, NoBaseHookId
> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
//! Put a public data member unordered_set_member_hook in order to store objects of this class in
//! an unordered_set/unordered_multi_set. unordered_set_member_hook holds the data necessary for maintaining the
//! unordered_set/unordered_multi_set and provides an appropriate value_traits class for unordered_set/unordered_multi_set.
//!
//! The hook admits the following options: \c void_pointer<>,
//! \c link_mode<> and \c store_hash<>.
//!
//! \c void_pointer<> is the pointer type that will be used internally in the hook
//! and the container configured to use this hook.
//!
//! \c link_mode<> will specify the linking mode of the hook (\c normal_link,
//! \c auto_unlink or \c safe_link).
//!
//! \c store_hash<> will tell the hook to store the hash of the value
//! to speed up rehashings.
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1, class O2, class O3, class O4>
#endif
class unordered_set_member_hook
: public make_unordered_set_member_hook<
#if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type
{
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
public:
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state.
//!
//! <b>Throws</b>: Nothing.
unordered_set_member_hook();
//! <b>Effects</b>: If link_mode is \c auto_unlink or \c safe_link
//! initializes the node to an unlinked state. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing a copy-constructor
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
unordered_set_member_hook(const unordered_set_member_hook& );
//! <b>Effects</b>: Empty function. The argument is ignored.
//!
//! <b>Throws</b>: Nothing.
//!
//! <b>Rationale</b>: Providing an assignment operator
//! makes classes using the hook STL-compliant without forcing the
//! user to do some additional work. \c swap can be used to emulate
//! move-semantics.
unordered_set_member_hook& operator=(const unordered_set_member_hook& );
//! <b>Effects</b>: If link_mode is \c normal_link, the destructor does
//! nothing (ie. no code is generated). If link_mode is \c safe_link and the
//! object is stored in an unordered_set an assertion is raised. If link_mode is
//! \c auto_unlink and \c is_linked() is true, the node is unlinked.
//!
//! <b>Throws</b>: Nothing.
~unordered_set_member_hook();
//! <b>Effects</b>: Swapping two nodes swaps the position of the elements
//! related to those nodes in one or two containers. That is, if the node
//! this is part of the element e1, the node x is part of the element e2
//! and both elements are included in the containers s1 and s2, then after
//! the swap-operation e1 is in s2 at the position of e2 and e2 is in s1
//! at the position of e1. If one element is not in a container, then
//! after the swap-operation the other element is not in a container.
//! Iterators to e1 and e2 related to those nodes are invalidated.
//!
//! <b>Complexity</b>: Constant
//!
//! <b>Throws</b>: Nothing.
void swap_nodes(unordered_set_member_hook &other);
//! <b>Precondition</b>: link_mode must be \c safe_link or \c auto_unlink.
//!
//! <b>Returns</b>: true, if the node belongs to a container, false
//! otherwise. This function can be used to test whether \c unordered_set::iterator_to
//! will return a valid iterator.
//!
//! <b>Complexity</b>: Constant
bool is_linked() const;
//! <b>Effects</b>: Removes the node if it's inserted in a container.
//! This function is only allowed if link_mode is \c auto_unlink.
//!
//! <b>Throws</b>: Nothing.
void unlink();
#endif
};
} //namespace intrusive
} //namespace boost
#include <boost/intrusive/detail/config_end.hpp>
#endif //BOOST_INTRUSIVE_UNORDERED_SET_HOOK_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_CONS_STDTUPLE_HPP
#define BOOST_MULTI_INDEX_DETAIL_CONS_STDTUPLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/if.hpp>
#include <boost/tuple/tuple.hpp>
#include <tuple>
namespace boost{
namespace multi_index{
namespace detail{
/* std::tuple wrapper providing the cons-based interface of boost::tuple for
* composite_key interoperability.
*/
template<typename StdTuple,std::size_t N>
struct cons_stdtuple;
struct cons_stdtuple_ctor_terminal
{
typedef boost::tuples::null_type result_type;
template<typename StdTuple>
static result_type create(const StdTuple&)
{
return boost::tuples::null_type();
}
};
template<typename StdTuple,std::size_t N>
struct cons_stdtuple_ctor_normal
{
typedef cons_stdtuple<StdTuple,N> result_type;
static result_type create(const StdTuple& t)
{
return result_type(t);
}
};
template<typename StdTuple,std::size_t N=0>
struct cons_stdtuple_ctor:
boost::mpl::if_c<
N<std::tuple_size<StdTuple>::value,
cons_stdtuple_ctor_normal<StdTuple,N>,
cons_stdtuple_ctor_terminal
>::type
{};
template<typename StdTuple,std::size_t N>
struct cons_stdtuple
{
typedef typename std::tuple_element<N,StdTuple>::type head_type;
typedef cons_stdtuple_ctor<StdTuple,N+1> tail_ctor;
typedef typename tail_ctor::result_type tail_type;
cons_stdtuple(const StdTuple& t_):t(t_){}
const head_type& get_head()const{return std::get<N>(t);}
tail_type get_tail()const{return tail_ctor::create(t);}
const StdTuple& t;
};
template<typename StdTuple>
typename cons_stdtuple_ctor<StdTuple>::result_type
make_cons_stdtuple(const StdTuple& t)
{
return cons_stdtuple_ctor<StdTuple>::create(t);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,173 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_LOADER_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_LOADER_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/rnd_index_ptr_array.hpp>
#include <boost/noncopyable.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* This class implements a serialization rearranger for random access
* indices. In order to achieve O(n) performance, the following strategy
* is followed: the nodes of the index are handled as if in a bidirectional
* list, where the next pointers are stored in the original
* random_access_index_ptr_array and the prev pointers are stored in
* an auxiliary array. Rearranging of nodes in such a bidirectional list
* is constant time. Once all the arrangements are performed (on destruction
* time) the list is traversed in reverse order and
* pointers are swapped and set accordingly so that they recover its
* original semantics ( *(node->up())==node ) while retaining the
* new order.
*/
template<typename Allocator>
class random_access_index_loader_base:private noncopyable
{
protected:
typedef random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
Allocator,
char
>::type
> node_impl_type;
typedef typename node_impl_type::pointer node_impl_pointer;
typedef random_access_index_ptr_array<Allocator> ptr_array;
random_access_index_loader_base(const Allocator& al_,ptr_array& ptrs_):
al(al_),
ptrs(ptrs_),
header(*ptrs.end()),
prev_spc(al,0),
preprocessed(false)
{}
~random_access_index_loader_base()
{
if(preprocessed)
{
node_impl_pointer n=header;
next(n)=n;
for(std::size_t i=ptrs.size();i--;){
n=prev(n);
std::size_t d=position(n);
if(d!=i){
node_impl_pointer m=prev(next_at(i));
std::swap(m->up(),n->up());
next_at(d)=next_at(i);
std::swap(prev_at(d),prev_at(i));
}
next(n)=n;
}
}
}
void rearrange(node_impl_pointer position_,node_impl_pointer x)
{
preprocess(); /* only incur this penalty if rearrange() is ever called */
if(position_==node_impl_pointer(0))position_=header;
next(prev(x))=next(x);
prev(next(x))=prev(x);
prev(x)=position_;
next(x)=next(position_);
next(prev(x))=prev(next(x))=x;
}
private:
void preprocess()
{
if(!preprocessed){
/* get space for the auxiliary prev array */
auto_space<node_impl_pointer,Allocator> tmp(al,ptrs.size()+1);
prev_spc.swap(tmp);
/* prev_spc elements point to the prev nodes */
std::rotate_copy(
&*ptrs.begin(),&*ptrs.end(),&*ptrs.end()+1,&*prev_spc.data());
/* ptrs elements point to the next nodes */
std::rotate(&*ptrs.begin(),&*ptrs.begin()+1,&*ptrs.end()+1);
preprocessed=true;
}
}
std::size_t position(node_impl_pointer x)const
{
return (std::size_t)(x->up()-ptrs.begin());
}
node_impl_pointer& next_at(std::size_t n)const
{
return *ptrs.at(n);
}
node_impl_pointer& prev_at(std::size_t n)const
{
return *(prev_spc.data()+n);
}
node_impl_pointer& next(node_impl_pointer x)const
{
return *(x->up());
}
node_impl_pointer& prev(node_impl_pointer x)const
{
return prev_at(position(x));
}
Allocator al;
ptr_array& ptrs;
node_impl_pointer header;
auto_space<node_impl_pointer,Allocator> prev_spc;
bool preprocessed;
};
template<typename Node,typename Allocator>
class random_access_index_loader:
private random_access_index_loader_base<Allocator>
{
typedef random_access_index_loader_base<Allocator> super;
typedef typename super::node_impl_pointer node_impl_pointer;
typedef typename super::ptr_array ptr_array;
public:
random_access_index_loader(const Allocator& al_,ptr_array& ptrs_):
super(al_,ptrs_)
{}
void rearrange(Node* position_,Node *x)
{
super::rearrange(
position_?position_->impl():node_impl_pointer(0),x->impl());
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,273 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_NODE_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_NODE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/integer/common_factor_rt.hpp>
#include <boost/multi_index/detail/raw_ptr.hpp>
#include <cstddef>
#include <functional>
namespace boost{
namespace multi_index{
namespace detail{
template<typename Allocator>
struct random_access_index_node_impl
{
typedef typename
boost::detail::allocator::rebind_to<
Allocator,random_access_index_node_impl
>::type::pointer pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,random_access_index_node_impl
>::type::const_pointer const_pointer;
typedef typename
boost::detail::allocator::rebind_to<
Allocator,pointer
>::type::pointer ptr_pointer;
ptr_pointer& up(){return up_;}
ptr_pointer up()const{return up_;}
/* interoperability with rnd_node_iterator */
static void increment(pointer& x)
{
x=*(x->up()+1);
}
static void decrement(pointer& x)
{
x=*(x->up()-1);
}
static void advance(pointer& x,std::ptrdiff_t n)
{
x=*(x->up()+n);
}
static std::ptrdiff_t distance(pointer x,pointer y)
{
return y->up()-x->up();
}
/* algorithmic stuff */
static void relocate(ptr_pointer pos,ptr_pointer x)
{
pointer n=*x;
if(x<pos){
extract(x,pos);
*(pos-1)=n;
n->up()=pos-1;
}
else{
while(x!=pos){
*x=*(x-1);
(*x)->up()=x;
--x;
}
*pos=n;
n->up()=pos;
}
};
static void relocate(ptr_pointer pos,ptr_pointer first,ptr_pointer last)
{
ptr_pointer begin,middle,end;
if(pos<first){
begin=pos;
middle=first;
end=last;
}
else{
begin=first;
middle=last;
end=pos;
}
std::ptrdiff_t n=end-begin;
std::ptrdiff_t m=middle-begin;
std::ptrdiff_t n_m=n-m;
std::ptrdiff_t p=integer::gcd(n,m);
for(std::ptrdiff_t i=0;i<p;++i){
pointer tmp=begin[i];
for(std::ptrdiff_t j=i,k;;){
if(j<n_m)k=j+m;
else k=j-n_m;
if(k==i){
*(begin+j)=tmp;
(*(begin+j))->up()=begin+j;
break;
}
else{
*(begin+j)=*(begin+k);
(*(begin+j))->up()=begin+j;
}
if(k<n_m)j=k+m;
else j=k-n_m;
if(j==i){
*(begin+k)=tmp;
(*(begin+k))->up()=begin+k;
break;
}
else{
*(begin+k)=*(begin+j);
(*(begin+k))->up()=begin+k;
}
}
}
};
static void extract(ptr_pointer x,ptr_pointer pend)
{
--pend;
while(x!=pend){
*x=*(x+1);
(*x)->up()=x;
++x;
}
}
static void transfer(
ptr_pointer pbegin0,ptr_pointer pend0,ptr_pointer pbegin1)
{
while(pbegin0!=pend0){
*pbegin1=*pbegin0++;
(*pbegin1)->up()=pbegin1;
++pbegin1;
}
}
static void reverse(ptr_pointer pbegin,ptr_pointer pend)
{
std::ptrdiff_t d=(pend-pbegin)/2;
for(std::ptrdiff_t i=0;i<d;++i){
std::swap(*pbegin,*--pend);
(*pbegin)->up()=pbegin;
(*pend)->up()=pend;
++pbegin;
}
}
private:
ptr_pointer up_;
};
template<typename Super>
struct random_access_index_node_trampoline:
random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
>
{
typedef random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
typename Super::allocator_type,
char
>::type
> impl_type;
};
template<typename Super>
struct random_access_index_node:
Super,random_access_index_node_trampoline<Super>
{
private:
typedef random_access_index_node_trampoline<Super> trampoline;
public:
typedef typename trampoline::impl_type impl_type;
typedef typename trampoline::pointer impl_pointer;
typedef typename trampoline::const_pointer const_impl_pointer;
typedef typename trampoline::ptr_pointer impl_ptr_pointer;
impl_ptr_pointer& up(){return trampoline::up();}
impl_ptr_pointer up()const{return trampoline::up();}
impl_pointer impl()
{
return static_cast<impl_pointer>(
static_cast<impl_type*>(static_cast<trampoline*>(this)));
}
const_impl_pointer impl()const
{
return static_cast<const_impl_pointer>(
static_cast<const impl_type*>(static_cast<const trampoline*>(this)));
}
static random_access_index_node* from_impl(impl_pointer x)
{
return
static_cast<random_access_index_node*>(
static_cast<trampoline*>(
raw_ptr<impl_type*>(x)));
}
static const random_access_index_node* from_impl(const_impl_pointer x)
{
return
static_cast<const random_access_index_node*>(
static_cast<const trampoline*>(
raw_ptr<const impl_type*>(x)));
}
/* interoperability with rnd_node_iterator */
static void increment(random_access_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::increment(xi);
x=from_impl(xi);
}
static void decrement(random_access_index_node*& x)
{
impl_pointer xi=x->impl();
trampoline::decrement(xi);
x=from_impl(xi);
}
static void advance(random_access_index_node*& x,std::ptrdiff_t n)
{
impl_pointer xi=x->impl();
trampoline::advance(xi,n);
x=from_impl(xi);
}
static std::ptrdiff_t distance(
random_access_index_node* x,random_access_index_node* y)
{
return trampoline::distance(x->impl(),y->impl());
}
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,203 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_OPS_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_OPS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/multi_index/detail/rnd_index_ptr_array.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* Common code for random_access_index memfuns having templatized and
* non-templatized versions.
*/
template<typename Node,typename Allocator,typename Predicate>
Node* random_access_index_remove(
random_access_index_ptr_array<Allocator>& ptrs,Predicate pred)
{
typedef typename Node::value_type value_type;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
impl_ptr_pointer first=ptrs.begin(),
res=first,
last=ptrs.end();
for(;first!=last;++first){
if(!pred(
const_cast<const value_type&>(Node::from_impl(*first)->value()))){
if(first!=res){
std::swap(*first,*res);
(*first)->up()=first;
(*res)->up()=res;
}
++res;
}
}
return Node::from_impl(*res);
}
template<typename Node,typename Allocator,class BinaryPredicate>
Node* random_access_index_unique(
random_access_index_ptr_array<Allocator>& ptrs,BinaryPredicate binary_pred)
{
typedef typename Node::value_type value_type;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
impl_ptr_pointer first=ptrs.begin(),
res=first,
last=ptrs.end();
if(first!=last){
for(;++first!=last;){
if(!binary_pred(
const_cast<const value_type&>(Node::from_impl(*res)->value()),
const_cast<const value_type&>(Node::from_impl(*first)->value()))){
++res;
if(first!=res){
std::swap(*first,*res);
(*first)->up()=first;
(*res)->up()=res;
}
}
}
++res;
}
return Node::from_impl(*res);
}
template<typename Node,typename Allocator,typename Compare>
void random_access_index_inplace_merge(
const Allocator& al,
random_access_index_ptr_array<Allocator>& ptrs,
BOOST_DEDUCED_TYPENAME Node::impl_ptr_pointer first1,Compare comp)
{
typedef typename Node::value_type value_type;
typedef typename Node::impl_pointer impl_pointer;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
auto_space<impl_pointer,Allocator> spc(al,ptrs.size());
impl_ptr_pointer first0=ptrs.begin(),
last0=first1,
last1=ptrs.end(),
out=spc.data();
while(first0!=last0&&first1!=last1){
if(comp(
const_cast<const value_type&>(Node::from_impl(*first1)->value()),
const_cast<const value_type&>(Node::from_impl(*first0)->value()))){
*out++=*first1++;
}
else{
*out++=*first0++;
}
}
std::copy(&*first0,&*last0,&*out);
std::copy(&*first1,&*last1,&*out);
first1=ptrs.begin();
out=spc.data();
while(first1!=last1){
*first1=*out++;
(*first1)->up()=first1;
++first1;
}
}
/* sorting */
/* auxiliary stuff */
template<typename Node,typename Compare>
struct random_access_index_sort_compare
{
typedef typename Node::impl_pointer first_argument_type;
typedef typename Node::impl_pointer second_argument_type;
typedef bool result_type;
random_access_index_sort_compare(Compare comp_=Compare()):comp(comp_){}
bool operator()(
typename Node::impl_pointer x,typename Node::impl_pointer y)const
{
typedef typename Node::value_type value_type;
return comp(
const_cast<const value_type&>(Node::from_impl(x)->value()),
const_cast<const value_type&>(Node::from_impl(y)->value()));
}
private:
Compare comp;
};
template<typename Node,typename Allocator,class Compare>
void random_access_index_sort(
const Allocator& al,
random_access_index_ptr_array<Allocator>& ptrs,
Compare comp)
{
/* The implementation is extremely simple: an auxiliary
* array of pointers is sorted using stdlib facilities and
* then used to rearrange the index. This is suboptimal
* in space and time, but has some advantages over other
* possible approaches:
* - Use std::stable_sort() directly on ptrs using some
* special iterator in charge of maintaining pointers
* and up() pointers in sync: we cannot guarantee
* preservation of the container invariants in the face of
* exceptions, if, for instance, std::stable_sort throws
* when ptrs transitorily contains duplicate elements.
* - Rewrite the internal algorithms of std::stable_sort
* adapted for this case: besides being a fair amount of
* work, making a stable sort compatible with Boost.MultiIndex
* invariants (basically, no duplicates or missing elements
* even if an exception is thrown) is complicated, error-prone
* and possibly won't perform much better than the
* solution adopted.
*/
if(ptrs.size()<=1)return;
typedef typename Node::impl_pointer impl_pointer;
typedef typename Node::impl_ptr_pointer impl_ptr_pointer;
typedef random_access_index_sort_compare<
Node,Compare> ptr_compare;
impl_ptr_pointer first=ptrs.begin();
impl_ptr_pointer last=ptrs.end();
auto_space<
impl_pointer,
Allocator> spc(al,ptrs.size());
impl_ptr_pointer buf=spc.data();
std::copy(&*first,&*last,&*buf);
std::stable_sort(&*buf,&*buf+ptrs.size(),ptr_compare(comp));
while(first!=last){
*first=*buf++;
(*first)->up()=first;
++first;
}
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,144 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_INDEX_PTR_ARRAY_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_INDEX_PTR_ARRAY_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/detail/allocator_utilities.hpp>
#include <boost/multi_index/detail/auto_space.hpp>
#include <boost/multi_index/detail/rnd_index_node.hpp>
#include <boost/noncopyable.hpp>
#include <cstddef>
namespace boost{
namespace multi_index{
namespace detail{
/* pointer structure for use by random access indices */
template<typename Allocator>
class random_access_index_ptr_array:private noncopyable
{
typedef random_access_index_node_impl<
typename boost::detail::allocator::rebind_to<
Allocator,
char
>::type
> node_impl_type;
public:
typedef typename node_impl_type::pointer value_type;
typedef typename boost::detail::allocator::rebind_to<
Allocator,value_type
>::type::pointer pointer;
random_access_index_ptr_array(
const Allocator& al,value_type end_,std::size_t sz):
size_(sz),
capacity_(sz),
spc(al,capacity_+1)
{
*end()=end_;
end_->up()=end();
}
std::size_t size()const{return size_;}
std::size_t capacity()const{return capacity_;}
void room_for_one()
{
if(size_==capacity_){
reserve(capacity_<=10?15:capacity_+capacity_/2);
}
}
void reserve(std::size_t c)
{
if(c>capacity_)set_capacity(c);
}
void shrink_to_fit()
{
if(capacity_>size_)set_capacity(size_);
}
pointer begin()const{return ptrs();}
pointer end()const{return ptrs()+size_;}
pointer at(std::size_t n)const{return ptrs()+n;}
void push_back(value_type x)
{
*(end()+1)=*end();
(*(end()+1))->up()=end()+1;
*end()=x;
(*end())->up()=end();
++size_;
}
void erase(value_type x)
{
node_impl_type::extract(x->up(),end()+1);
--size_;
}
void clear()
{
*begin()=*end();
(*begin())->up()=begin();
size_=0;
}
void swap(random_access_index_ptr_array& x)
{
std::swap(size_,x.size_);
std::swap(capacity_,x.capacity_);
spc.swap(x.spc);
}
private:
std::size_t size_;
std::size_t capacity_;
auto_space<value_type,Allocator> spc;
pointer ptrs()const
{
return spc.data();
}
void set_capacity(std::size_t c)
{
auto_space<value_type,Allocator> spc1(spc.get_allocator(),c+1);
node_impl_type::transfer(begin(),end()+1,spc1.data());
spc.swap(spc1);
capacity_=c;
}
};
template<typename Allocator>
void swap(
random_access_index_ptr_array<Allocator>& x,
random_access_index_ptr_array<Allocator>& y)
{
x.swap(y);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,140 @@
/* Copyright 2003-2014 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RND_NODE_ITERATOR_HPP
#define BOOST_MULTI_INDEX_DETAIL_RND_NODE_ITERATOR_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/operators.hpp>
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#endif
namespace boost{
namespace multi_index{
namespace detail{
/* Iterator class for node-based indices with random access iterators. */
template<typename Node>
class rnd_node_iterator:
public random_access_iterator_helper<
rnd_node_iterator<Node>,
typename Node::value_type,
std::ptrdiff_t,
const typename Node::value_type*,
const typename Node::value_type&>
{
public:
/* coverity[uninit_ctor]: suppress warning */
rnd_node_iterator(){}
explicit rnd_node_iterator(Node* node_):node(node_){}
const typename Node::value_type& operator*()const
{
return node->value();
}
rnd_node_iterator& operator++()
{
Node::increment(node);
return *this;
}
rnd_node_iterator& operator--()
{
Node::decrement(node);
return *this;
}
rnd_node_iterator& operator+=(std::ptrdiff_t n)
{
Node::advance(node,n);
return *this;
}
rnd_node_iterator& operator-=(std::ptrdiff_t n)
{
Node::advance(node,-n);
return *this;
}
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
/* Serialization. As for why the following is public,
* see explanation in safe_mode_iterator notes in safe_mode.hpp.
*/
BOOST_SERIALIZATION_SPLIT_MEMBER()
typedef typename Node::base_type node_base_type;
template<class Archive>
void save(Archive& ar,const unsigned int)const
{
node_base_type* bnode=node;
ar<<serialization::make_nvp("pointer",bnode);
}
template<class Archive>
void load(Archive& ar,const unsigned int)
{
node_base_type* bnode;
ar>>serialization::make_nvp("pointer",bnode);
node=static_cast<Node*>(bnode);
}
#endif
/* get_node is not to be used by the user */
typedef Node node_type;
Node* get_node()const{return node;}
private:
Node* node;
};
template<typename Node>
bool operator==(
const rnd_node_iterator<Node>& x,
const rnd_node_iterator<Node>& y)
{
return x.get_node()==y.get_node();
}
template<typename Node>
bool operator<(
const rnd_node_iterator<Node>& x,
const rnd_node_iterator<Node>& y)
{
return Node::distance(x.get_node(),y.get_node())>0;
}
template<typename Node>
std::ptrdiff_t operator-(
const rnd_node_iterator<Node>& x,
const rnd_node_iterator<Node>& y)
{
return Node::distance(y.get_node(),x.get_node());
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,300 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_RNK_INDEX_OPS_HPP
#define BOOST_MULTI_INDEX_DETAIL_RNK_INDEX_OPS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/and.hpp>
#include <boost/multi_index/detail/promotes_arg.hpp>
#include <cstddef>
#include <utility>
namespace boost{
namespace multi_index{
namespace detail{
/* Common code for ranked_index memfuns having templatized and
* non-templatized versions.
*/
template<typename Pointer>
inline std::size_t ranked_node_size(Pointer x)
{
return x!=Pointer(0)?x->size:0;
}
template<typename Pointer>
inline Pointer ranked_index_nth(std::size_t n,Pointer end_)
{
Pointer top=end_->parent();
if(top==Pointer(0)||n>=top->size)return end_;
for(;;){
std::size_t s=ranked_node_size(top->left());
if(n==s)return top;
if(n<s)top=top->left();
else{
top=top->right();
n-=s+1;
}
}
}
template<typename Pointer>
inline std::size_t ranked_index_rank(Pointer x,Pointer end_)
{
Pointer top=end_->parent();
if(top==Pointer(0))return 0;
if(x==end_)return top->size;
std::size_t s=ranked_node_size(x->left());
while(x!=top){
Pointer z=x->parent();
if(x==z->right()){
s+=ranked_node_size(z->left())+1;
}
x=z;
}
return s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_find_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_find_rank(
top,y,key,x,comp,
mpl::and_<
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey> >());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::size_t ranked_index_find_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_find_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_find_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return 0;
std::size_t s=top->size,
s0=s;
Node* y0=y;
do{
if(!comp(key(top->value()),x)){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}while(top);
return (y==y0||comp(x,key(y->value())))?s0:s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_lower_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_lower_bound_rank(
top,y,key,x,comp,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey>());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::size_t ranked_index_lower_bound_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_lower_bound_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_lower_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return 0;
std::size_t s=top->size;
do{
if(!comp(key(top->value()),x)){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}while(top);
return s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_upper_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_upper_bound_rank(
top,y,key,x,comp,
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::size_t ranked_index_upper_bound_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_upper_bound_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::size_t ranked_index_upper_bound_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return 0;
std::size_t s=top->size;
do{
if(comp(x,key(top->value()))){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else top=Node::from_impl(top->right());
}while(top);
return s;
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::pair<std::size_t,std::size_t> ranked_index_equal_range_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp)
{
typedef typename KeyFromValue::result_type key_type;
return ranked_index_equal_range_rank(
top,y,key,x,comp,
mpl::and_<
promotes_1st_arg<CompatibleCompare,CompatibleKey,key_type>,
promotes_2nd_arg<CompatibleCompare,key_type,CompatibleKey> >());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleCompare
>
inline std::pair<std::size_t,std::size_t> ranked_index_equal_range_rank(
Node* top,Node* y,const KeyFromValue& key,
const BOOST_DEDUCED_TYPENAME KeyFromValue::result_type& x,
const CompatibleCompare& comp,mpl::true_)
{
return ranked_index_equal_range_rank(top,y,key,x,comp,mpl::false_());
}
template<
typename Node,typename KeyFromValue,
typename CompatibleKey,typename CompatibleCompare
>
inline std::pair<std::size_t,std::size_t> ranked_index_equal_range_rank(
Node* top,Node* y,const KeyFromValue& key,const CompatibleKey& x,
const CompatibleCompare& comp,mpl::false_)
{
if(!top)return std::pair<std::size_t,std::size_t>(0,0);
std::size_t s=top->size;
do{
if(comp(key(top->value()),x)){
top=Node::from_impl(top->right());
}
else if(comp(x,key(top->value()))){
y=top;
s-=ranked_node_size(y->right())+1;
top=Node::from_impl(top->left());
}
else{
return std::pair<std::size_t,std::size_t>(
s-top->size+
ranked_index_lower_bound_rank(
Node::from_impl(top->left()),top,key,x,comp,mpl::false_()),
s-ranked_node_size(top->right())+
ranked_index_upper_bound_rank(
Node::from_impl(top->right()),y,key,x,comp,mpl::false_()));
}
}while(top);
return std::pair<std::size_t,std::size_t>(s,s);
}
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,185 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_GLOBAL_FUN_HPP
#define BOOST_MULTI_INDEX_GLOBAL_FUN_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/workaround.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/enable_if.hpp>
#if !defined(BOOST_NO_SFINAE)
#include <boost/type_traits/is_convertible.hpp>
#endif
namespace boost{
template<class T> class reference_wrapper; /* fwd decl. */
namespace multi_index{
namespace detail{
/* global_fun is a read-only key extractor from Value based on a given global
* (or static member) function with signature:
*
* Type f([const] Value [&]);
*
* Additionally, global_fun and const_global_fun are overloaded to support
* referece_wrappers of Value and "chained pointers" to Value's. By chained
* pointer to T we mean a type P such that, given a p of Type P
* *...n...*x is convertible to T&, for some n>=1.
* Examples of chained pointers are raw and smart pointers, iterators and
* arbitrary combinations of these (vg. T** or unique_ptr<T*>.)
*/
template<class Value,typename Type,Type (*PtrToFunction)(Value)>
struct const_ref_global_fun_base
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<const ChainedPtr&,Value>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(Value x)const
{
return PtrToFunction(x);
}
Type operator()(
const reference_wrapper<
typename remove_reference<Value>::type>& x)const
{
return operator()(x.get());
}
Type operator()(
const reference_wrapper<
typename remove_const<
typename remove_reference<Value>::type>::type>& x
#if BOOST_WORKAROUND(BOOST_MSVC,==1310)
/* http://lists.boost.org/Archives/boost/2015/10/226135.php */
,int=0
#endif
)const
{
return operator()(x.get());
}
};
template<class Value,typename Type,Type (*PtrToFunction)(Value)>
struct non_const_ref_global_fun_base
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<ChainedPtr&,Value>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(Value x)const
{
return PtrToFunction(x);
}
Type operator()(
const reference_wrapper<
typename remove_reference<Value>::type>& x)const
{
return operator()(x.get());
}
};
template<class Value,typename Type,Type (*PtrToFunction)(Value)>
struct non_ref_global_fun_base
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<const ChainedPtr&,const Value&>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(const Value& x)const
{
return PtrToFunction(x);
}
Type operator()(const reference_wrapper<const Value>& x)const
{
return operator()(x.get());
}
Type operator()(
const reference_wrapper<typename remove_const<Value>::type>& x)const
{
return operator()(x.get());
}
};
} /* namespace multi_index::detail */
template<class Value,typename Type,Type (*PtrToFunction)(Value)>
struct global_fun:
mpl::if_c<
is_reference<Value>::value,
typename mpl::if_c<
is_const<typename remove_reference<Value>::type>::value,
detail::const_ref_global_fun_base<Value,Type,PtrToFunction>,
detail::non_const_ref_global_fun_base<Value,Type,PtrToFunction>
>::type,
detail::non_ref_global_fun_base<Value,Type,PtrToFunction>
>::type
{
};
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,22 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_KEY_EXTRACTORS_HPP
#define BOOST_MULTI_INDEX_KEY_EXTRACTORS_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/global_fun.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#endif

View File

@ -0,0 +1,205 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_MEM_FUN_HPP
#define BOOST_MULTI_INDEX_MEM_FUN_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/mpl/if.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/enable_if.hpp>
#if !defined(BOOST_NO_SFINAE)
#include <boost/type_traits/is_convertible.hpp>
#endif
namespace boost{
template<class T> class reference_wrapper; /* fwd decl. */
namespace multi_index{
/* mem_fun implements a read-only key extractor based on a given non-const
* member function of a class.
* const_mem_fun does the same for const member functions.
* Additionally, mem_fun and const_mem_fun are overloaded to support
* referece_wrappers of T and "chained pointers" to T's. By chained pointer
* to T we mean a type P such that, given a p of Type P
* *...n...*x is convertible to T&, for some n>=1.
* Examples of chained pointers are raw and smart pointers, iterators and
* arbitrary combinations of these (vg. T** or unique_ptr<T*>.)
*/
template<class Class,typename Type,Type (Class::*PtrToMemberFunction)()const>
struct const_mem_fun
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<const ChainedPtr&,const Class&>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(const Class& x)const
{
return (x.*PtrToMemberFunction)();
}
Type operator()(const reference_wrapper<const Class>& x)const
{
return operator()(x.get());
}
Type operator()(const reference_wrapper<Class>& x)const
{
return operator()(x.get());
}
};
template<class Class,typename Type,Type (Class::*PtrToMemberFunction)()>
struct mem_fun
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<ChainedPtr&,Class&>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(Class& x)const
{
return (x.*PtrToMemberFunction)();
}
Type operator()(const reference_wrapper<Class>& x)const
{
return operator()(x.get());
}
};
/* MSVC++ 6.0 has problems with const member functions as non-type template
* parameters, somehow it takes them as non-const. const_mem_fun_explicit
* workarounds this deficiency by accepting an extra type parameter that
* specifies the signature of the member function. The workaround was found at:
* Daniel, C.:"Re: weird typedef problem in VC",
* news:microsoft.public.vc.language, 21st nov 2002,
* http://groups.google.com/groups?
* hl=en&lr=&ie=UTF-8&selm=ukwvg3O0BHA.1512%40tkmsftngp05
*
* MSVC++ 6.0 support has been dropped and [const_]mem_fun_explicit is
* deprecated.
*/
template<
class Class,typename Type,
typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction>
struct const_mem_fun_explicit
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<const ChainedPtr&,const Class&>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(const Class& x)const
{
return (x.*PtrToMemberFunction)();
}
Type operator()(const reference_wrapper<const Class>& x)const
{
return operator()(x.get());
}
Type operator()(const reference_wrapper<Class>& x)const
{
return operator()(x.get());
}
};
template<
class Class,typename Type,
typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction>
struct mem_fun_explicit
{
typedef typename remove_reference<Type>::type result_type;
template<typename ChainedPtr>
#if !defined(BOOST_NO_SFINAE)
typename disable_if<
is_convertible<ChainedPtr&,Class&>,Type>::type
#else
Type
#endif
operator()(const ChainedPtr& x)const
{
return operator()(*x);
}
Type operator()(Class& x)const
{
return (x.*PtrToMemberFunction)();
}
Type operator()(const reference_wrapper<Class>& x)const
{
return operator()(x.get());
}
};
/* BOOST_MULTI_INDEX_CONST_MEM_FUN and BOOST_MULTI_INDEX_MEM_FUN used to
* resolve to [const_]mem_fun_explicit for MSVC++ 6.0 and to
* [const_]mem_fun otherwise. Support for this compiler having been dropped,
* they are now just wrappers over [const_]mem_fun kept for backwards-
* compatibility reasons.
*/
#define BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) \
::boost::multi_index::const_mem_fun< Class,Type,&Class::MemberFunName >
#define BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) \
::boost::multi_index::mem_fun< Class,Type,&Class::MemberFunName >
} /* namespace multi_index */
} /* namespace boost */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_RANDOM_ACCESS_INDEX_FWD_HPP
#define BOOST_MULTI_INDEX_RANDOM_ACCESS_INDEX_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/multi_index/tag.hpp>
namespace boost{
namespace multi_index{
namespace detail{
template<typename SuperMeta,typename TagList>
class random_access_index;
template<
typename SuperMeta1,typename TagList1,
typename SuperMeta2,typename TagList2
>
bool operator==(
const random_access_index<SuperMeta1,TagList1>& x,
const random_access_index<SuperMeta2,TagList2>& y);
template<
typename SuperMeta1,typename TagList1,
typename SuperMeta2,typename TagList2
>
bool operator<(
const random_access_index<SuperMeta1,TagList1>& x,
const random_access_index<SuperMeta2,TagList2>& y);
template<
typename SuperMeta1,typename TagList1,
typename SuperMeta2,typename TagList2
>
bool operator!=(
const random_access_index<SuperMeta1,TagList1>& x,
const random_access_index<SuperMeta2,TagList2>& y);
template<
typename SuperMeta1,typename TagList1,
typename SuperMeta2,typename TagList2
>
bool operator>(
const random_access_index<SuperMeta1,TagList1>& x,
const random_access_index<SuperMeta2,TagList2>& y);
template<
typename SuperMeta1,typename TagList1,
typename SuperMeta2,typename TagList2
>
bool operator>=(
const random_access_index<SuperMeta1,TagList1>& x,
const random_access_index<SuperMeta2,TagList2>& y);
template<
typename SuperMeta1,typename TagList1,
typename SuperMeta2,typename TagList2
>
bool operator<=(
const random_access_index<SuperMeta1,TagList1>& x,
const random_access_index<SuperMeta2,TagList2>& y);
template<typename SuperMeta,typename TagList>
void swap(
random_access_index<SuperMeta,TagList>& x,
random_access_index<SuperMeta,TagList>& y);
} /* namespace multi_index::detail */
/* index specifiers */
template <typename TagList=tag<> >
struct random_access;
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,382 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_RANKED_INDEX_HPP
#define BOOST_MULTI_INDEX_RANKED_INDEX_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/multi_index/detail/ord_index_impl.hpp>
#include <boost/multi_index/detail/rnk_index_ops.hpp>
#include <boost/multi_index/ranked_index_fwd.hpp>
namespace boost{
namespace multi_index{
namespace detail{
/* ranked_index augments a given ordered index to provide rank operations */
template<typename OrderedIndexNodeImpl>
struct ranked_node:OrderedIndexNodeImpl
{
std::size_t size;
};
template<typename OrderedIndexImpl>
class ranked_index:public OrderedIndexImpl
{
typedef OrderedIndexImpl super;
protected:
typedef typename super::node_type node_type;
typedef typename super::node_impl_pointer node_impl_pointer;
public:
typedef typename super::ctor_args_list ctor_args_list;
typedef typename super::allocator_type allocator_type;
typedef typename super::iterator iterator;
/* rank operations */
iterator nth(std::size_t n)const
{
return this->make_iterator(node_type::from_impl(
ranked_index_nth(n,this->header()->impl())));
}
std::size_t rank(iterator position)const
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
return ranked_index_rank(
position.get_node()->impl(),this->header()->impl());
}
template<typename CompatibleKey>
std::size_t find_rank(const CompatibleKey& x)const
{
return ranked_index_find_rank(
this->root(),this->header(),this->key,x,this->comp_);
}
template<typename CompatibleKey,typename CompatibleCompare>
std::size_t find_rank(
const CompatibleKey& x,const CompatibleCompare& comp)const
{
return ranked_index_find_rank(
this->root(),this->header(),this->key,x,comp);
}
template<typename CompatibleKey>
std::size_t lower_bound_rank(const CompatibleKey& x)const
{
return ranked_index_lower_bound_rank(
this->root(),this->header(),this->key,x,this->comp_);
}
template<typename CompatibleKey,typename CompatibleCompare>
std::size_t lower_bound_rank(
const CompatibleKey& x,const CompatibleCompare& comp)const
{
return ranked_index_lower_bound_rank(
this->root(),this->header(),this->key,x,comp);
}
template<typename CompatibleKey>
std::size_t upper_bound_rank(const CompatibleKey& x)const
{
return ranked_index_upper_bound_rank(
this->root(),this->header(),this->key,x,this->comp_);
}
template<typename CompatibleKey,typename CompatibleCompare>
std::size_t upper_bound_rank(
const CompatibleKey& x,const CompatibleCompare& comp)const
{
return ranked_index_upper_bound_rank(
this->root(),this->header(),this->key,x,comp);
}
template<typename CompatibleKey>
std::pair<std::size_t,std::size_t> equal_range_rank(
const CompatibleKey& x)const
{
return ranked_index_equal_range_rank(
this->root(),this->header(),this->key,x,this->comp_);
}
template<typename CompatibleKey,typename CompatibleCompare>
std::pair<std::size_t,std::size_t> equal_range_rank(
const CompatibleKey& x,const CompatibleCompare& comp)const
{
return ranked_index_equal_range_rank(
this->root(),this->header(),this->key,x,comp);
}
template<typename LowerBounder,typename UpperBounder>
std::pair<std::size_t,std::size_t>
range_rank(LowerBounder lower,UpperBounder upper)const
{
typedef typename mpl::if_<
is_same<LowerBounder,unbounded_type>,
BOOST_DEDUCED_TYPENAME mpl::if_<
is_same<UpperBounder,unbounded_type>,
both_unbounded_tag,
lower_unbounded_tag
>::type,
BOOST_DEDUCED_TYPENAME mpl::if_<
is_same<UpperBounder,unbounded_type>,
upper_unbounded_tag,
none_unbounded_tag
>::type
>::type dispatch;
return range_rank(lower,upper,dispatch());
}
protected:
ranked_index(const ranked_index& x):super(x){};
ranked_index(const ranked_index& x,do_not_copy_elements_tag):
super(x,do_not_copy_elements_tag()){};
ranked_index(
const ctor_args_list& args_list,const allocator_type& al):
super(args_list,al){}
private:
template<typename LowerBounder,typename UpperBounder>
std::pair<std::size_t,std::size_t>
range_rank(LowerBounder lower,UpperBounder upper,none_unbounded_tag)const
{
node_type* y=this->header();
node_type* z=this->root();
if(!z)return std::pair<std::size_t,std::size_t>(0,0);
std::size_t s=z->size;
do{
if(!lower(this->key(z->value()))){
z=node_type::from_impl(z->right());
}
else if(!upper(this->key(z->value()))){
y=z;
s-=ranked_node_size(y->right())+1;
z=node_type::from_impl(z->left());
}
else{
return std::pair<std::size_t,std::size_t>(
s-z->size+
lower_range_rank(node_type::from_impl(z->left()),z,lower),
s-ranked_node_size(z->right())+
upper_range_rank(node_type::from_impl(z->right()),y,upper));
}
}while(z);
return std::pair<std::size_t,std::size_t>(s,s);
}
template<typename LowerBounder,typename UpperBounder>
std::pair<std::size_t,std::size_t>
range_rank(LowerBounder,UpperBounder upper,lower_unbounded_tag)const
{
return std::pair<std::size_t,std::size_t>(
0,
upper_range_rank(this->root(),this->header(),upper));
}
template<typename LowerBounder,typename UpperBounder>
std::pair<std::size_t,std::size_t>
range_rank(LowerBounder lower,UpperBounder,upper_unbounded_tag)const
{
return std::pair<std::size_t,std::size_t>(
lower_range_rank(this->root(),this->header(),lower),
this->size());
}
template<typename LowerBounder,typename UpperBounder>
std::pair<std::size_t,std::size_t>
range_rank(LowerBounder,UpperBounder,both_unbounded_tag)const
{
return std::pair<std::size_t,std::size_t>(0,this->size());
}
template<typename LowerBounder>
std::size_t
lower_range_rank(node_type* top,node_type* y,LowerBounder lower)const
{
if(!top)return 0;
std::size_t s=top->size;
do{
if(lower(this->key(top->value()))){
y=top;
s-=ranked_node_size(y->right())+1;
top=node_type::from_impl(top->left());
}
else top=node_type::from_impl(top->right());
}while(top);
return s;
}
template<typename UpperBounder>
std::size_t
upper_range_rank(node_type* top,node_type* y,UpperBounder upper)const
{
if(!top)return 0;
std::size_t s=top->size;
do{
if(!upper(this->key(top->value()))){
y=top;
s-=ranked_node_size(y->right())+1;
top=node_type::from_impl(top->left());
}
else top=node_type::from_impl(top->right());
}while(top);
return s;
}
};
/* augmenting policy for ordered_index */
struct rank_policy
{
template<typename OrderedIndexNodeImpl>
struct augmented_node
{
typedef ranked_node<OrderedIndexNodeImpl> type;
};
template<typename OrderedIndexImpl>
struct augmented_interface
{
typedef ranked_index<OrderedIndexImpl> type;
};
/* algorithmic stuff */
template<typename Pointer>
static void add(Pointer x,Pointer root)
{
x->size=1;
while(x!=root){
x=x->parent();
++(x->size);
}
}
template<typename Pointer>
static void remove(Pointer x,Pointer root)
{
while(x!=root){
x=x->parent();
--(x->size);
}
}
template<typename Pointer>
static void copy(Pointer x,Pointer y)
{
y->size=x->size;
}
template<typename Pointer>
static void rotate_left(Pointer x,Pointer y) /* in: x==y->left() */
{
y->size=x->size;
x->size=ranked_node_size(x->left())+ranked_node_size(x->right())+1;
}
template<typename Pointer>
static void rotate_right(Pointer x,Pointer y) /* in: x==y->right() */
{
rotate_left(x,y);
}
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
/* invariant stuff */
template<typename Pointer>
static bool invariant(Pointer x)
{
return x->size==ranked_node_size(x->left())+ranked_node_size(x->right())+1;
}
#endif
};
} /* namespace multi_index::detail */
/* ranked_index specifiers */
template<typename Arg1,typename Arg2,typename Arg3>
struct ranked_unique
{
typedef typename detail::ordered_index_args<
Arg1,Arg2,Arg3> index_args;
typedef typename index_args::tag_list_type::type tag_list_type;
typedef typename index_args::key_from_value_type key_from_value_type;
typedef typename index_args::compare_type compare_type;
template<typename Super>
struct node_class
{
typedef detail::ordered_index_node<detail::rank_policy,Super> type;
};
template<typename SuperMeta>
struct index_class
{
typedef detail::ordered_index<
key_from_value_type,compare_type,
SuperMeta,tag_list_type,detail::ordered_unique_tag,
detail::rank_policy> type;
};
};
template<typename Arg1,typename Arg2,typename Arg3>
struct ranked_non_unique
{
typedef detail::ordered_index_args<
Arg1,Arg2,Arg3> index_args;
typedef typename index_args::tag_list_type::type tag_list_type;
typedef typename index_args::key_from_value_type key_from_value_type;
typedef typename index_args::compare_type compare_type;
template<typename Super>
struct node_class
{
typedef detail::ordered_index_node<detail::rank_policy,Super> type;
};
template<typename SuperMeta>
struct index_class
{
typedef detail::ordered_index<
key_from_value_type,compare_type,
SuperMeta,tag_list_type,detail::ordered_non_unique_tag,
detail::rank_policy> type;
};
};
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@ -0,0 +1,35 @@
/* Copyright 2003-2015 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_RANKED_INDEX_FWD_HPP
#define BOOST_MULTI_INDEX_RANKED_INDEX_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/multi_index/detail/ord_index_args.hpp>
#include <boost/multi_index/detail/ord_index_impl_fwd.hpp>
namespace boost{
namespace multi_index{
/* ranked_index specifiers */
template<typename Arg1,typename Arg2=mpl::na,typename Arg3=mpl::na>
struct ranked_unique;
template<typename Arg1,typename Arg2=mpl::na,typename Arg3=mpl::na>
struct ranked_non_unique;
} /* namespace multi_index */
} /* namespace boost */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
# circular_buffer.idx index script file
# for Boost.circular_buffer Quickbook Doxygen documentation Auto-indexing forcircular_buffer library.
# Copyright (c) 2011 Paul A. Bristow
# Copyright (c) 2003 - 2008 Jan Gaspar
# boost-no-inspect
# Use, modification and distribution is subject to the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt
# or copy at http://www.boost.org/LICENSE_1_0.txt)
# All header files, recursing down to include sub-folders.
!scan-path "boost/circular_buffer" ".*\.hpp" true
# All example source files, assuming no sub-folders.
!scan-path "libs/circular_buffer/example" ".*\.cpp"

View File

@ -1,626 +0,0 @@
[article Boost.Circular Buffer
[quickbook 1.6]
[id circular_buffer]
[copyright 2003-2013 Jan Gaspar]
[license
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
[@http://www.boost.org/LICENSE_1_0.txt])
]
[authors [Gaspar, Jan]]
[source-mode c++]
]
[/ Links - by (most common) convention, prefixed with double underscore so not confused with other names.]
[def __alert [$./images/alert.png]] [/ Examples of your own images (in doc/html/images/ .]
[def __tip [$./images/tip.png]]
[/ If you provide a file type like .png, you will probably find that the file is missing in the pdf version.]
[/ This is because the default file type specified is .png in html, but .svg for pdf version.]
[/ Some links to external sources.]
[/ You often want to link more than once, so using a def ensures you always refer to the same location.]
[def __boost [@http://www.boost.org/ Boost]] [/Boost.org]
[def __boostroot [@boost: Boost root]] [/ Your boost root]
[/Note the custom boost root url schema for linking to files within the Boost distribution.]
[/Note It can't be used for images, nor for pdf, so not so useful.]
[/def __boostlicense [@http://www.boost.org/LICENSE_1_0.txt Boost License]]
[/ Or refer to your most recent version of Boost.]
[def __boostlicense [@boost:/LICENSE_1_0.txt Boost License]]
[def __boostbook [@http://www.boost.org/doc/html/boostbook.html BoostBook]]
[def __boostbook_docs [@http://www.boost.org/doc/libs/1_53_0/doc/html/boostbook.html BoostBook documentation]]
[def __quickbook [@http://www.boost.org/doc/tools/quickbook/index.html Quickbook]]
[def __quickbook_syntax [@http://www.boost.org/doc/libs/1_53_0/doc/html/quickbook/ref.html Quickbook Syntax Compendium]]
[def __docbook [@http://www.docbook.org/ DocBook]]
[def __doxygen [@http://www.doxygen.org/ Doxygen]]
[def __autoindex [@boost:/tools/auto_index/doc/html/index.html AutoIndex]]
[def __pdf [@http://www.adobe.com/products/acrobat/adobepdf.html PDF]]
[def __textpad [@http://www.textpad.com Textpad]]
[def __emacs [@http://www.gnu.org/software/emacs/ GNU emacs]]
[def __css [@http://en.wikipedia.org/wiki/Cascading_Style_Sheets Cascading Style Sheet]]
[def __intro [link circular_buffer.intro Introduction]] [/Link to a Quickbook section (see below).]
[def __docbook_params [@http://docbook.sourceforge.net/release/xsl/current/doc/ Docbook xsl:param format options]]
[def __cb [classref boost::circular_buffer circular_buffer]]
[def __cbso [classref boost::circular_buffer_space_optimized circular_buffer_space_optimized]]
[def __min_capacity [memberref boost::circular_buffer_space_optimized::min_capacity() min_capacity]]
[def __capacity_control [memberref boost::circular_buffer_space_optimized::capacity_control () capacity_control ]]
[def __debug_support [link circular_buffer.implmentation.debug_support debug support]]
[include ../../../tools/auto_index/include/auto_index_helpers.qbk]
[/ Must be first included file!]
[note A printer-friendly PDF version of this manual is also available.]
[section:intro Introduction]
A Circular Buffer.
[h2 Description]
The term [@http://en.wikipedia.org/wiki/Circular_buffer circular buffer]
(also called a ['ring] or ['cyclic buffer])
refers to an area in memory which is used to store incoming data.
When the buffer is filled,
new data is written starting at the beginning of the buffer and overwriting the old.
[classref boost::circular_buffer] is a STL compliant container.
It is a kind of sequence similar to [@http://www.sgi.com/tech/stl/List.html std::list]
or [@http://www.sgi.com/tech/stl/Deque.html std::deque].
It supports random access iterators, constant time insert and erase operations
at the beginning or the end of the buffer and interoperability with std algorithms.
The __cb is especially designed to provide [*fixed capacity] storage.
When its capacity is exhausted, newly inserted elements will cause elements
to be overwritten, either at the beginning or end of the buffer
(depending on what insert operation is used).
The __cb only allocates memory when created,
when the capacity is adjusted explicitly,
or as necessary to accommodate resizing or assign operations.
[$../../libs/circular_buffer/doc/images/circular_buffer.png]
There is also a __cbso version available.
[$../../libs/circular_buffer/doc/images/space_optimized.png]
__cbso is an adaptation of the __cb
which [*does not allocate memory all at once when created],
instead it allocates memory as needed.
The predictive memory allocation is similar to typical `std::vector` implementation.
Memory is automatically freed as the size of the container decreases.
The memory allocation process of the space-optimized circular buffer.
The __min_capacity of the capacity controller represents
the minimal guaranteed amount of allocated memory.
The allocated memory will never drop under this value.
The default value of the `min_capacity` is set to 0.
The `min_capacity` can be set using the constructor parameter __capacity_control
or the function `set_capacity`.
The space-optimized version is, of course, a little slower.
[endsect] [/section:intro Introduction]
[section:example Circular_buffer example]
Here is a simple example to introduce the class __cb.
[import ../example/circular_buffer_example.cpp]
[circular_buffer_example_1]
This example shows contruction, inserting elements, overwriting and popping.
[circular_buffer_example_2]
[/circular_buffer_example_output - there is no output for this example]
You can see the full example code at [@boost:libs/circular_buffer/example/circular_buffer_example.cpp circular_buffer_example.cpp].
The full annotated description is in the C++ Reference section.
[endsect] [/section:example circular_buffer example]
[section:rationale Rationale]
The basic motivation behind the __cb was to create a container which would [*work seamlessly with STL].
Additionally, the design of the __cb was guided by the following principles:
* Maximum ['efficiency] for envisaged applications.
* Suitable for ['general purpose use].
* The behaviour of the buffer as ['intuitive] as possible.
* Suitable for ['specialization] by means of adaptors. (The __cbso is such an example of the adaptor.)
* Easy to ['debug]. (See Debug Support for details.)
In order to achieve maximum efficiency, the __cb and __cbso store their elements in a
[*contiguous region of memory], which then enables:
* Use of fixed memory and no implicit or unexpected memory allocation.
* Fast constant-time insertion and removal of elements from the front and back.
* Fast constant-time random access of elements.
* Suitability for real-time and performance critical applications.
Possible applications of the circular buffer include:
* Storage of the ['most recently received samples], overwriting the oldest as new samples arrive.
* As an underlying container for a ['bounded buffer]
(see the Bounded Buffer example, code at [@boost:libs/circular_buffer/example/circular_buffer_bound_example.cpp circular_buffer_bound_example.cpp]).
* A kind of ['cache] storing a specified number of last inserted elements.
* Efficient fixed capacity ['FIFO (First In, First Out)],
* Efficient fixed capacity ['LIFO (Last In, First Out)] queue which removes the oldest (inserted as first) elements when full.
[endsect] [/section:rationale Rationale]
[section:implementation Implementation ]
The following paragraphs describe issues that had to be considered during the implementation of the circular_buffer:
[h3 Thread-Safety]
The thread-safety of the __cb is the same as the thread-safety of containers in most STL implementations.
This means the __cb is not fully thread-safe.
The thread-safety is guaranteed only in the sense that simultaneous accesses
to distinct instances of the __cb are safe,
and simultaneous read accesses to a shared __cb are safe.
If multiple threads access a single __cb,
and at least one of the threads may potentially write,
then the user is responsible for ensuring mutual exclusion between the threads during the container accesses.
The mutual exclusion between the threads can be achieved by wrapping
operations of the underlying __cb with a lock acquisition and release.
(See the Bounded Buffer example code at [@boost:libs/circular_buffer/example/circular_buffer_bound_example.cpp circular_buffer_bound_example.cpp])
[h3 Overwrite Operation]
Overwrite operation occurs when an element is inserted into a full __cb -
the old element is being overwritten by the new one.
There was a discussion what exactly "overwriting of an element" means during the formal review.
It may be either a destruction of the original element and
a consequent inplace construction of a new element
or it may be an assignment of a new element into an old one.
The __cb implements assignment because it is more effective.
From the point of business logic of a stored element,
the destruction/construction operation and assignment usually mean the same.
However, in very rare cases (if in any) they may differ.
If there is a requirement for elements to be destructed/constructed instead of being assigned,
consider implementing a wrapper of the element which would implement the assign operator,
and store the wrappers instead.
It is necessary to note that storing such wrappers has a drawback.
The destruction/construction will be invoked on every assignment of the wrapper -
not only when a wrapper is being overwritten (when the buffer is full)
but also when the stored wrappers are being shifted
(e.g. as a result of insertion into the middle of container).
[h3 Writing to a Full Buffer]
There are several options how to cope if a data source produces more data than can fit in the fixed-sized buffer:
* Inform the data source to wait until there is room in the buffer (e.g. by throwing an overflow exception).
* If the oldest data is the most important, ignore new data from the source until there is room in the buffer again.
* If the latest data is the most important, write over the oldest data.
* Let the producer to be responsible for checking the size of the buffer prior writing into it.
It is apparent that the __cb implements the third option.
But it may be less apparent it does not implement any other option -
especially the first two.
One can get an impression that the __cb should implement first three options
and offer a mechanism of choosing among them. This impression is wrong.
The __cb was designed and optimized to be circular
(which means overwriting the oldest data when full).
If such a controlling mechanism had been enabled,
it would just complicate the matters
and the usage of the __cb would be probably less straightforward.
Moreover, the first two options (and the fourth option as well)
do not require the buffer to be circular at all.
If there is a need for the first or second option, consider implementing an adaptor of e.g. std::vector.
In this case the __cb is not suitable for adapting, because,
contrary to std::vector, it bears an overhead for its circular behaviour.
[h3 Reading/Removing from an Empty Buffer]
When reading or removing an element from an empty buffer,
the buffer should be able to notify the data consumer
(e.g. by throwing underflow exception) that there are no elements stored in it.
The __cb does not implement such a behaviour for two reasons:
* It would introduce a performance overhead.
* No other std container implements it this way.
It is considered to be a bug to read or remove an element
(e.g. by calling [memberref boost::circular_buffer::front() front()]
or [memberref boost::circular_buffer::pop_back() pop_back()])
from an empty std container and from an empty __cb as well.
The data consumer has to test if the container is not empty before reading/removing from it by testing
[memberref boost::circular_buffer::empty empty()].
However, when reading from the __cb,
there is an option to rely on the [memberref boost::circular_buffer::at() at()]
method which throws an exception when the index is out of range.
[h3 Iterator Invalidation]
An iterator is usually considered to be invalidated if an element,
the iterator pointed to, had been removed or overwritten by an another element.
This definition is enforced by the Debug Support and is documented for every method.
However, some applications utilizing __cb may require less strict definition:
an iterator is invalid only if it points to an uninitialized memory.
Consider following example:
[import ../example/circular_buffer_iter_example.cpp]
[circular_buffer_iter_example_1]
The iterator does not point to the original element any more
(and is considered to be invalid from the "strict" point of view)
but it still points to the same valid place in the memory.
This "soft" definition of iterator invalidation is supported by the __cb
but should be considered as an implementation detail rather than a full-fledged feature.
The rules when the iterator is still valid can be inferred from the code in
[@boost:libs/circular_buffer/test/soft_iterator_invalidation.cpp soft_iterator_invalidation.cpp].
[h3 Move emulation and rvalues]
Since Boost 1.54.0 support for move semantics was implemented using
the [@boost:libs/move/index.html Boost.Move] library.
If rvalue references are available __cb will use them, but if not it uses a close,
but imperfect emulation. On such compilers:
* Non-copyable objects can be stored in the containers.
They can be constructed in place using `emplace`, or if they support
Boost.Move, moved into place.
* The containers themselves are not movable.
* Argument forwarding is not perfect.
__cb will use rvalues and move emulations for value types only if move constructor and move assignment operator of the value type do not throw;
or if the value type has no copy constructor.
Some methods won't use move constructor for the value type at all, if the constructor throws. This is
required for data consistency and avoidance of situations, when aftrer an exception __cb
contains moved away objects along with the good ones.
See documentation for [@boost:libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html `is_copy_constructible`], [@boost:libs/type_traits/doc/html/boost_typetraits/reference/is_nothrow_move_assignable.html `is_nothrow_move_assignable`] and [@boost:libs/type_traits/doc/html/boost_typetraits/reference/is_nothrow_move_constructible.html `is_nothrow_move_constructible`] type triats.
There you'll find information about how to make constructor of class noexcept and how to make a non-copyable
class in C++03 and C++98.
Performance of __cb will *greatly improve* if value type has noexcept move constructor and noexcept move assignment.
[h3 Exceptions of move_if_noexcept(T&)]
Reference documentation of the __cb contains notes like "Throws: See Exceptions of `move_if_noexcept(T&)`".
That note means the following: `move_if_noexcept(T& value)` does not throws exceptions at all, but it returns
`value` as rvalue reference only if class `T` have noexcept move constructor and noexcept move assignment operator;
or if it has no copy constructor. Otherwise `move_if_noexcept(T& value)` returns `value` as const reference.
This leads us to the following situation:
* If `value` has a noexcept move constructor and noexcept move assignment operator, then no exceptions will be thrown at all.
* If `value` has a throwing move constructor and some copy constructor, then method may throw exceptions of copy constructor.
* If `value` has no copy constructor, then method may throw exceptions of move constructor.
`move_if_noexcept(T&)` uses [@boost:libs/move/index.html Boost.Move], [@boost:libs/type_traits/doc/html/boost_typetraits/reference/is_copy_constructible.html `is_copy_constructible`], [@boost:libs/type_traits/doc/html/boost_typetraits/reference/is_nothrow_move_assignable.html `is_nothrow_move_assignable`] and [@boost:libs/type_traits/doc/html/boost_typetraits/reference/is_nothrow_move_constructible.html `is_nothrow_move_constructible`] type triats.
[h3 Caveats]
The __cb should not be used for storing pointers to dynamically allocated objects.
When a circular buffer becomes full, further insertion will overwrite the stored pointers
- resulting in a [*memory leak]. One recommend alternative is the use of smart pointers, for example
[@http://www.boost.org/doc/libs/1_53_0/libs/smart_ptr/smart_ptr.htm Boost Smart pointers].
[@http://en.wikipedia.org/wiki/Std::auto_ptr std::auto_ptr]
[caution Any container of `std::auto_ptr` is considered particularly hazardous.]
[tip Never create a circular buffer of `std::auto_ptr`.
Refer to Scott Meyers' excellent book Effective STL for a detailed discussion.
(Meyers S., Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library.
Addison-Wesley, 2001.)
]
While internals of a __cb are circular, [*iterators are not].
Iterators of a __cb are only valid for the range `\[begin(), end()\]`,
so for example: iterators `(begin() - 1)` and `(end() + 1)` are both invalid.
[h3 Debug Support]
In order to help a programmer to avoid and find common bugs,
the __cb can be enabled to provide a kind of debug support.
When the debugging functionality is enabled, the __cb maintains a list of valid iterators.
As soon as any element gets destroyed all iterators pointing to this element
are removed from this list and explicitly invalidated (an invalidation flag is set).
The debug support also consists of many assertions (`BOOST_ASSERT` macros)
which ensure the __cb and its iterators are used in the correct manner at runtime.
In case an invalid iterator is used, the assertion will report an error.
The connection of explicit iterator invalidation and assertions
makes a very robust debug technique which catches most of the errors.
Moreover, the uninitialized memory allocated by __cb is filled with the value `0xcc` in the debug mode.
When debugging the code, this can help the programmer to recognize the initialized memory from the uninitialized.
For details refer the source code [@boost:boost/circular_buffer/debug.hpp circular_buffer/debug.hpp].
[caution Since the debugging code makes __cb and its iterators more interconnected, thread safety guarantees of __cb
are different when debug support is enabled. In addition to the container itself, all iterators tracked by the container
(including any copies thereof) must be protected from concurrent access. In particular, this includes copying, destroying or
obtaining iterators from the container, even if for read-only access.]
The debug support is disabled by default. To enable it, one has to define `BOOST_CB_ENABLE_DEBUG` macro with the value of 1
while compiling the code using __cb.
[h3 Compatibility with Interprocess library]
The __cb is compatible with the [@boost:libs/interprocess/index.html Boost.Interprocess]
[/ This should be in @boost:libs/interprocess/doc/index.html ]
library used for interprocess communication.
Considering that the circular_buffer's debug support relies on 'raw' pointers
(which is not permited by the Interprocess library)
the code has to compiled with debug support disabled (i.e. with `BOOST_CB_ENABLE_DEBUG` macro not defined or defined to 0).
Not doing that will cause the compilation to fail.
[endsect] [/section:implementation Implementation ]
[section:examples More Examples]
[h3 Summing all the values in a circular buffer]
[import ../example/circular_buffer_sum_example.cpp]
[circular_buffer_sum_example_1]
[/circular_buffer_example_output - there is no output for this example]
The __cb has a capacity of three `int`.
Therefore, the size of the buffer will never exceed three.
The `std::accumulate` algorithm evaluates the sum of the stored elements.
The semantics of the __cb can be inferred from the assertions.
You can see the full example code at [@boost:libs/circular_buffer/example/circular_buffer_sum_example.cpp circular_buffer_sum_example.cpp].
[h3 Bounded Buffer Example]
The bounded buffer is normally used in a producer-consumer mode:
producer threads produce items and store them in the container
and consumer threads remove these items and process them.
The bounded buffer has to guarantee that
* producers do not insert items into the container when the container is full,
* consumers do not try to remove items when the container is empty,
* each produced item is consumed by exactly one consumer.
[import ../example/circular_buffer_bound_example.cpp]
[circular_buffer_bound_example_1]
[/ there is no output for this example]
The bounded_buffer relies on [@boost:/doc/html/thread.html Boost.Thread]
and [@boost:libs/bind/index.html Boost.Bind] libraries
and [@boost:libs/utility/call_traits.htm Boost.call_traits utility].
The [memberref boost::circular_buffer::push_front() push_front()]
method is called by the producer thread in order to insert a new item into the buffer.
The method locks the mutex and waits until there is a space for the new item.
(The mutex is unlocked during the waiting stage and has to be regained when the condition is met.)
If there is a space in the buffer available,
the execution continues and the method inserts the item at the end of the __cb.
Then it increments the number of unread items and unlocks the mutex
(in case an exception is thrown before the mutex is unlocked,
the mutex is unlocked automatically by the destructor of the scoped_lock).
At last the method notifies one of the consumer threads
waiting for a new item to be inserted into the buffer.
The [memberref boost::circular_buffer::pop_back() pop_back()]
method is called by the consumer thread in order to read the next item from the buffer.
The method locks the mutex and waits until there is an unread item in the buffer.
If there is at least one unread item,
the method decrements the number of unread items and reads the next item from the __cb.
Then it unlocks the mutex and notifies one of the producer threads
waiting for the buffer to free a space for the next item.
The `bounded buffer::pop_back()`
method [*does not remove the item] but the item is left
in the circular_buffer which then [*replaces it with a new one]
(inserted by a producer) when the circular_buffer is full.
This technique is more effective than removing the item
explicitly by calling the [memberref boost::circular_buffer::pop_back() circular_buffer::pop_back()]
method of the __cb.
This claim is based on the assumption that an assignment (replacement)
of a new item into an old one is more effective than a destruction
(removal) of an old item and a consequent inplace construction (insertion) of a new item.
For comparison of bounded buffers based on different containers compile and
run [@boost:libs/circular_buffer/test/bounded_buffer_comparison.cpp bounded_buffer_comparison.cpp].
The test should reveal the bounded buffer based on the __cb is most effective
closely followed by the `std::deque` based bounded buffer.
(In reality, the result may differ sometimes because the test
is always affected by external factors such as immediate CPU load.)
[import ../test/bounded_buffer_comparison.cpp]
You can see the full test code at [@boost:libs/circular_buffer/test/bounded_buffer_comparison.cpp bounded_buffer_comparison.cpp],
and an example of output is [bounded_buffer_comparison_output].
[endsect] [/section:examples More examples]
[section:headers Header Files]
The circular buffer library is defined in the file [@boost:boost/circular_buffer.hpp circular_buffer.hpp].
#include <boost/circular_buffer.hpp>
(There is also a forward declaration for the __cb
in the header file [@boost:boost/circular_buffer_fwd.hpp circular_buffer_fwd.hpp]).
The __cb is defined in the file [@boost:boost/circular_buffer/base.hpp base.hpp].
The __cbso is defined in the file [@boost:boost/circular_buffer/space_optimized.hpp space_optimized.hpp].
[endsect] [/section:headers Header Files]
[section:concepts Modelled Concepts]
[@http://www.sgi.com/tech/stl/RandomAccessContainer.html Random Access Container],
[@http://www.sgi.com/tech/stl/FrontInsertionSequence.html Front Insertion Sequence], and
[@http://www.sgi.com/tech/stl/BackInsertionSequence.html Back Insertion sequence]
[endsect] [/section:concepts Modelled Concepts]
[section:template_params Template Parameters]
[table:templ Template parameter requirements
[[parameter] [Requirements]]
[[T] [The type of the elements stored in the circular_buffer.
The T has to be [@boost:libs/utility/Assignable.html Assignable]
and [@boost:libs/utility/CopyConstructible.html CopyConstructible].
Moreover T has to be [@http://www.sgi.com/tech/stl/DefaultConstructible.html DefaultConstructible]
if supplied as a default parameter when invoking some of the circular_buffer's methods,
e.g. `insert(iterator pos, const value_type& item = value_type())`.
And [@http://www.sgi.com/tech/stl/EqualityComparable.html EqualityComparable]
and/or [@boost:libs/utility/LessThanComparable.html LessThanComparable]
if the circular_buffer will be compared with another container.]]
[[Alloc] [The allocator type used for all internal memory management.
The Alloc has to meet the allocator requirements imposed by STL.]]
]
[endsect] [/section:template_params Template Parameters]
[section:tickets Trac Tickets]
Report and view bugs and features by adding a ticket at [@https://svn.boost.org/trac/boost Boost.Trac].
Existing open tickets for this library alone can be viewed
[@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=circular_buffer&col=id&col=summary&col=status&col=owner&col=type&col=milestone&order=priority here].
Existing tickets for this library - including closed ones - can be viewed
[@https://svn.boost.org/trac/boost/query?status=assigned&status=closed&status=new&status=reopened&component=circular_buffer&col=id&col=summary&col=status&col=owner&col=type&col=milestone&order=priority here].
Type: Bugs
[@https://svn.boost.org/trac/boost/ticket/4100 #4100] Some boost classes have sizeof that depends on NDEBUG.
[@https://svn.boost.org/trac/boost/ticket/5362 #5362] circular_buffer does not compile with BOOST_NO_EXCEPTIONS.
[@https://svn.boost.org/trac/boost/ticket/6277 #6277] Checked iterators are not threadsafe.
[@https://svn.boost.org/trac/boost/ticket/6747 #6747] Circular_Buffer / Bounded_Buffer inside Template class problem.
[@https://svn.boost.org/trac/boost/ticket/7025 #7025] circular buffer reports warning: " type qualifiers ignored on function return type" while compile.
[@https://svn.boost.org/trac/boost/ticket/7950 #7950] Eliminate W4-warnings under VS2005.
[@https://svn.boost.org/trac/boost/ticket/8012 #8012] Inconsistency in `linearize()`.
[@https://svn.boost.org/trac/boost/ticket/8438 #8438] `vector` & __cb storage misbehave when using compiler optimizations.
Type: Feature Requests
[@https://svn.boost.org/trac/boost/ticket/5511 #5511] Documentation needs some improvement.
[@https://svn.boost.org/trac/boost/ticket/7888 #7888] circular_buffer should support move semantics.
Type: Patches
[@https://svn.boost.org/trac/boost/ticket/8032 #8032] Warning fixes in circular_buffer.
[endsect] [/section:tickets Trac Tickets]
[section:release Release Notes]
[h4 Boost 1.56]
* C++11 allocator model support implemented by Glen Fernandes using Boost allocator_traits.
[h4 Boost 1.55]
* Documentation refactored by Paul A. Bristow using Quickbook, Doxygen and Autoindexing.
* Rvalue references emulation added by Antony Polukhin using Boost.Move.
[h4 Boost 1.42]
* Added methods erase_begin(size_type) and erase_end(size_type) with constant complexity for such types of stored elements which do not need an explicit destruction e.g. int or double.
* Similarly changed implementation of the clear() method and the destructor so their complexity is now constant for such types of stored elements which do not require an explicit destruction (the complexity for other types remains linear).
[h4 Boost 1.37]
*Added new methods is_linearized() and rotate(const_iterator).
* Fixed bugs:
[@https://svn.boost.org/trac/boost/ticket/1987 #1987] Patch to make circular_buffer.hpp #includes absolute.
[@https://svn.boost.org/trac/boost/ticket/1852 #1852] Copy constructor does not copy capacity.
[h4 Boost 1.36]
* Changed behaviour of the circular_buffer(const allocator_type&) constructor.
Since this version the constructor does not allocate any memory and both capacity and size are set to zero.
* Fixed bug:
[@https://svn.boost.org/trac/boost/ticket/191 #1919] Default constructed circular buffer throws std::bad_alloc.
[h4 Boost 1.35]
* Initial release.
[endsect] [/section:release Release Notes]
[section:acknowledgements Acknowledgements]
Thomas Witt in 2002 produced a prototype called cyclic buffer.
The circular_buffer has a short history. Its first version was a std::deque adaptor.
This container was not very effective because of many reallocations when inserting/removing an element.
Thomas Wenish did a review of this version and
motivated me to create a circular buffer which allocates memory at once when created.
The second version adapted `std::vector` but it has been abandoned soon
because of limited control over iterator invalidation.
The current version is a full-fledged STL compliant container.
Pavel Vozenilek did a thorough review of this version and came with many good ideas and improvements.
The idea of the space optimized circular buffer has been introduced by Pavel Vozenilek.
Also, I would like to thank Howard Hinnant, Nigel Stewart and everyone
who participated at the formal review for valuable comments and ideas.
Paul A. Bristow refactored the documentation in 2013 to use the full power of Quickbook, Doxygen and Autoindexing.
[endsect] [/section:acknowledgements Acknowledgements]
[section:version_id Documentation Version Info]
Last edit to Quickbook file __FILENAME__ was at __TIME__ on __DATE__.
[tip This should appear on the pdf version
(but may be redundant on a html version where the last edit date is on the first (home) page).]
[warning Home page "Last revised" is GMT, not local time. Last edit date is local time.]
[/See also Adobe Reader pdf File Properties for creation date, and PDF producer, version and page count.]
[endsect] [/section:version_id Version Info]
[xinclude autodoc.xml] [/ Using Doxygen reference documentation.]
[/ The position of this in the Quickbook determines the location of the Doxygen references section.]
[/ Index(es) should be invoked in the main module, not within a section.]
'''
<index/>
'''
[/ circular_buffer.qbk
Copyright 2013 Paul A. Bristow.
Copyright 2003-2008 Jan Gaspar.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

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