mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-12-15 15:33:38 -05:00
Merge branch 'hotfix-2.0.0-rc4' of bitbucket.org:k1jt/wsjtx into hotfix-2.0.0-rc4
This commit is contained in:
commit
2098a65fe4
@ -281,10 +281,9 @@ set (jt9_CXXSRCS
|
||||
)
|
||||
|
||||
set (wsjtx_CXXSRCS
|
||||
logbook/adif.cpp
|
||||
logbook/countrydat.cpp
|
||||
logbook/countriesworked.cpp
|
||||
logbook/logbook.cpp
|
||||
logbook/WorkedBefore.cpp
|
||||
psk_reporter.cpp
|
||||
Modulator.cpp
|
||||
Detector.cpp
|
||||
|
||||
@ -525,6 +525,7 @@ private:
|
||||
|
||||
DecodeHighlightingModel decode_highlighing_model_;
|
||||
DecodeHighlightingModel next_decode_highlighing_model_;
|
||||
bool highlight_by_mode_;
|
||||
int LotW_days_since_upload_;
|
||||
|
||||
TransceiverFactory::ParameterPack rig_params_;
|
||||
@ -708,6 +709,7 @@ bool Configuration::pwrBandTxMemory () const {return m_->pwrBandTxMemory_;}
|
||||
bool Configuration::pwrBandTuneMemory () const {return m_->pwrBandTuneMemory_;}
|
||||
LotWUsers const& Configuration::lotw_users () const {return m_->lotw_users_;}
|
||||
DecodeHighlightingModel const& Configuration::decode_highlighting () const {return m_->decode_highlighing_model_;}
|
||||
bool Configuration::highlight_by_mode () const {return m_->highlight_by_mode_;}
|
||||
|
||||
void Configuration::set_calibration (CalibrationParams params)
|
||||
{
|
||||
@ -903,6 +905,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
|
||||
, station_delete_action_ {tr ("&Delete"), nullptr}
|
||||
, station_insert_action_ {tr ("&Insert ..."), nullptr}
|
||||
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
|
||||
, highlight_by_mode_ {false}
|
||||
, LotW_days_since_upload_ {0}
|
||||
, last_port_type_ {TransceiverFactory::Capabilities::none}
|
||||
, rig_is_dummy_ {false}
|
||||
@ -1266,6 +1269,7 @@ void Configuration::impl::initialize_models ()
|
||||
next_stations_.station_list (stations_.station_list ());
|
||||
|
||||
next_decode_highlighing_model_.items (decode_highlighing_model_.items ());
|
||||
ui_->highlight_by_mode_check_box->setChecked (highlight_by_mode_);
|
||||
ui_->LotW_days_since_upload_spin_box->setValue (LotW_days_since_upload_);
|
||||
|
||||
set_rig_invariants ();
|
||||
@ -1411,6 +1415,7 @@ void Configuration::impl::read_settings ()
|
||||
stations_.station_list (settings_->value ("stations").value<StationList::Stations> ());
|
||||
|
||||
decode_highlighing_model_.items (settings_->value ("DecodeHighlighting", QVariant::fromValue (DecodeHighlightingModel::default_items ())).value<DecodeHighlightingModel::HighlightItems> ());
|
||||
highlight_by_mode_ = settings_->value("HighlightByMode", false).toBool ();
|
||||
LotW_days_since_upload_ = settings_->value ("LotWDaysSinceLastUpload", 365).toInt ();
|
||||
lotw_users_.set_age_constraint (LotW_days_since_upload_);
|
||||
|
||||
@ -1524,6 +1529,7 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ()));
|
||||
settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
|
||||
settings_->setValue ("DecodeHighlighting", QVariant::fromValue (decode_highlighing_model_.items ()));
|
||||
settings_->setValue ("HighlightByMode", highlight_by_mode_);
|
||||
settings_->setValue ("LotWDaysSinceLastUpload", LotW_days_since_upload_);
|
||||
settings_->setValue ("toRTTY", log_as_RTTY_);
|
||||
settings_->setValue ("dBtoComments", report_in_comments_);
|
||||
@ -2026,6 +2032,7 @@ void Configuration::impl::accept ()
|
||||
decode_highlighing_model_.items (next_decode_highlighing_model_.items ());
|
||||
Q_EMIT self_->decode_highlighting_changed (decode_highlighing_model_);
|
||||
}
|
||||
highlight_by_mode_ = ui_->highlight_by_mode_check_box->isChecked ();
|
||||
LotW_days_since_upload_ = ui_->LotW_days_since_upload_spin_box->value ();
|
||||
lotw_users_.set_age_constraint (LotW_days_since_upload_);
|
||||
|
||||
|
||||
@ -176,6 +176,7 @@ public:
|
||||
bool pwrBandTuneMemory () const;
|
||||
LotWUsers const& lotw_users () const;
|
||||
DecodeHighlightingModel const& decode_highlighting () const;
|
||||
bool highlight_by_mode () const;
|
||||
|
||||
struct CalibrationParams
|
||||
{
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>534</width>
|
||||
<height>546</height>
|
||||
<width>527</width>
|
||||
<height>540</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -2235,6 +2235,20 @@ Right click for insert and delete options.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="highlight_by_mode_check_box">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Check to indicate new DXCC entities, grid squares, and callsigns per mode.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Highlight by Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -2313,19 +2327,6 @@ Right click for insert and delete options.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_8">
|
||||
<property name="orientation">
|
||||
@ -2339,6 +2340,19 @@ Right click for insert and delete options.</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="advanced_tab">
|
||||
@ -2905,6 +2919,7 @@ Right click for insert and delete options.</string>
|
||||
<tabstop>stations_table_view</tabstop>
|
||||
<tabstop>highlighting_list_view</tabstop>
|
||||
<tabstop>reset_highlighting_to_defaults_push_button</tabstop>
|
||||
<tabstop>highlight_by_mode_check_box</tabstop>
|
||||
<tabstop>LotW_CSV_URL_line_edit</tabstop>
|
||||
<tabstop>LotW_CSV_fetch_push_button</tabstop>
|
||||
<tabstop>LotW_days_since_upload_spin_box</tabstop>
|
||||
@ -2994,12 +3009,12 @@ Right click for insert and delete options.</string>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="CAT_handshake_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
<buttongroup name="split_mode_button_group"/>
|
||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||
<buttongroup name="CAT_data_bits_button_group"/>
|
||||
<buttongroup name="TX_mode_button_group"/>
|
||||
<buttongroup name="PTT_method_button_group"/>
|
||||
<buttongroup name="TX_audio_source_button_group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
||||
@ -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
|
||||
|
||||
767
boost/boost/date_time/date_facet.hpp
Normal file
767
boost/boost/date_time/date_facet.hpp
Normal 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
|
||||
265
boost/boost/date_time/date_generator_formatter.hpp
Normal file
265
boost/boost/date_time/date_generator_formatter.hpp
Normal 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___
|
||||
330
boost/boost/date_time/date_generator_parser.hpp
Normal file
330
boost/boost/date_time/date_generator_parser.hpp
Normal 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__
|
||||
|
||||
731
boost/boost/date_time/format_date_parser.hpp
Normal file
731
boost/boost/date_time/format_date_parser.hpp
Normal 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
|
||||
|
||||
|
||||
|
||||
38
boost/boost/date_time/gregorian/gregorian.hpp
Normal file
38
boost/boost/date_time/gregorian/gregorian.hpp
Normal 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
|
||||
784
boost/boost/date_time/gregorian/gregorian_io.hpp
Normal file
784
boost/boost/date_time/gregorian/gregorian_io.hpp
Normal 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__
|
||||
196
boost/boost/date_time/period_formatter.hpp
Normal file
196
boost/boost/date_time/period_formatter.hpp
Normal 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
|
||||
198
boost/boost/date_time/period_parser.hpp
Normal file
198
boost/boost/date_time/period_parser.hpp
Normal 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___
|
||||
39
boost/boost/date_time/posix_time/posix_time.hpp
Normal file
39
boost/boost/date_time/posix_time/posix_time.hpp
Normal 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
|
||||
|
||||
236
boost/boost/date_time/posix_time/posix_time_io.hpp
Normal file
236
boost/boost/date_time/posix_time/posix_time_io.hpp
Normal 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__
|
||||
153
boost/boost/date_time/posix_time/posix_time_legacy_io.hpp
Normal file
153
boost/boost/date_time/posix_time/posix_time_legacy_io.hpp
Normal 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___
|
||||
289
boost/boost/date_time/posix_time/time_formatters.hpp
Normal file
289
boost/boost/date_time/posix_time/time_formatters.hpp
Normal 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
|
||||
|
||||
212
boost/boost/date_time/posix_time/time_formatters_limited.hpp
Normal file
212
boost/boost/date_time/posix_time/time_formatters_limited.hpp
Normal 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
|
||||
|
||||
48
boost/boost/date_time/posix_time/time_parsers.hpp
Normal file
48
boost/boost/date_time/posix_time/time_parsers.hpp
Normal 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
|
||||
|
||||
96
boost/boost/date_time/special_values_formatter.hpp
Normal file
96
boost/boost/date_time/special_values_formatter.hpp
Normal 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
|
||||
159
boost/boost/date_time/special_values_parser.hpp
Normal file
159
boost/boost/date_time/special_values_parser.hpp
Normal 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__
|
||||
|
||||
32
boost/boost/date_time/string_convert.hpp
Normal file
32
boost/boost/date_time/string_convert.hpp
Normal 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___
|
||||
278
boost/boost/date_time/string_parse_tree.hpp
Normal file
278
boost/boost/date_time/string_parse_tree.hpp
Normal 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
|
||||
125
boost/boost/date_time/strings_from_facet.hpp
Normal file
125
boost/boost/date_time/strings_from_facet.hpp
Normal 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
|
||||
1368
boost/boost/date_time/time_facet.hpp
Normal file
1368
boost/boost/date_time/time_facet.hpp
Normal file
File diff suppressed because it is too large
Load Diff
122
boost/boost/date_time/time_formatting_streams.hpp
Normal file
122
boost/boost/date_time/time_formatting_streams.hpp
Normal 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
|
||||
324
boost/boost/date_time/time_parsing.hpp
Normal file
324
boost/boost/date_time/time_parsing.hpp
Normal 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
|
||||
307
boost/boost/interprocess/allocators/allocator.hpp
Normal file
307
boost/boost/interprocess/allocators/allocator.hpp
Normal 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
|
||||
|
||||
858
boost/boost/interprocess/allocators/detail/allocator_common.hpp
Normal file
858
boost/boost/interprocess/allocators/detail/allocator_common.hpp
Normal 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
|
||||
44
boost/boost/interprocess/containers/allocation_type.hpp
Normal file
44
boost/boost/interprocess/containers/allocation_type.hpp
Normal 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
|
||||
44
boost/boost/interprocess/containers/containers_fwd.hpp
Normal file
44
boost/boost/interprocess/containers/containers_fwd.hpp
Normal 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
|
||||
37
boost/boost/interprocess/containers/string.hpp
Normal file
37
boost/boost/interprocess/containers/string.hpp
Normal 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
|
||||
37
boost/boost/interprocess/containers/vector.hpp
Normal file
37
boost/boost/interprocess/containers/vector.hpp
Normal 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
|
||||
|
||||
37
boost/boost/interprocess/containers/version_type.hpp
Normal file
37
boost/boost/interprocess/containers/version_type.hpp
Normal 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
|
||||
|
||||
31
boost/boost/interprocess/detail/cast_tags.hpp
Normal file
31
boost/boost/interprocess/detail/cast_tags.hpp
Normal 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
|
||||
212
boost/boost/interprocess/detail/file_wrapper.hpp
Normal file
212
boost/boost/interprocess/detail/file_wrapper.hpp
Normal 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
|
||||
77
boost/boost/interprocess/detail/in_place_interface.hpp
Normal file
77
boost/boost/interprocess/detail/in_place_interface.hpp
Normal 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
|
||||
775
boost/boost/interprocess/detail/managed_memory_impl.hpp
Normal file
775
boost/boost/interprocess/detail/managed_memory_impl.hpp
Normal 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
|
||||
|
||||
118
boost/boost/interprocess/detail/math_functions.hpp
Normal file
118
boost/boost/interprocess/detail/math_functions.hpp
Normal 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
|
||||
316
boost/boost/interprocess/detail/named_proxy.hpp
Normal file
316
boost/boost/interprocess/detail/named_proxy.hpp
Normal 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
|
||||
42
boost/boost/interprocess/detail/nothrow.hpp
Normal file
42
boost/boost/interprocess/detail/nothrow.hpp
Normal 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
|
||||
518
boost/boost/interprocess/detail/segment_manager_helper.hpp
Normal file
518
boost/boost/interprocess/detail/segment_manager_helper.hpp
Normal 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
|
||||
|
||||
200
boost/boost/interprocess/detail/transform_iterator.hpp
Normal file
200
boost/boost/interprocess/detail/transform_iterator.hpp
Normal 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
|
||||
35
boost/boost/interprocess/detail/variadic_templates_tools.hpp
Normal file
35
boost/boost/interprocess/detail/variadic_templates_tools.hpp
Normal 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
|
||||
199
boost/boost/interprocess/file_mapping.hpp
Normal file
199
boost/boost/interprocess/file_mapping.hpp
Normal 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
|
||||
158
boost/boost/interprocess/indexes/iset_index.hpp
Normal file
158
boost/boost/interprocess/indexes/iset_index.hpp
Normal 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
|
||||
250
boost/boost/interprocess/managed_mapped_file.hpp
Normal file
250
boost/boost/interprocess/managed_mapped_file.hpp
Normal 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
|
||||
262
boost/boost/interprocess/managed_shared_memory.hpp
Normal file
262
boost/boost/interprocess/managed_shared_memory.hpp
Normal 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
|
||||
|
||||
596
boost/boost/interprocess/mem_algo/detail/mem_algo_common.hpp
Normal file
596
boost/boost/interprocess/mem_algo/detail/mem_algo_common.hpp
Normal 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
|
||||
1400
boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp
Normal file
1400
boost/boost/interprocess/mem_algo/rbtree_best_fit.hpp
Normal file
File diff suppressed because it is too large
Load Diff
751
boost/boost/interprocess/offset_ptr.hpp
Normal file
751
boost/boost/interprocess/offset_ptr.hpp
Normal 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
|
||||
1343
boost/boost/interprocess/segment_manager.hpp
Normal file
1343
boost/boost/interprocess/segment_manager.hpp
Normal file
File diff suppressed because it is too large
Load Diff
68
boost/boost/interprocess/smart_ptr/deleter.hpp
Normal file
68
boost/boost/interprocess/smart_ptr/deleter.hpp
Normal 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
|
||||
181
boost/boost/interprocess/sync/interprocess_recursive_mutex.hpp
Normal file
181
boost/boost/interprocess/sync/interprocess_recursive_mutex.hpp
Normal 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
|
||||
60
boost/boost/interprocess/sync/mutex_family.hpp
Normal file
60
boost/boost/interprocess/sync/mutex_family.hpp
Normal 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
|
||||
|
||||
|
||||
155
boost/boost/interprocess/sync/null_mutex.hpp
Normal file
155
boost/boost/interprocess/sync/null_mutex.hpp
Normal 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
|
||||
137
boost/boost/interprocess/sync/posix/recursive_mutex.hpp
Normal file
137
boost/boost/interprocess/sync/posix/recursive_mutex.hpp
Normal 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
|
||||
176
boost/boost/interprocess/sync/spin/recursive_mutex.hpp
Normal file
176
boost/boost/interprocess/sync/spin/recursive_mutex.hpp
Normal 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
|
||||
47
boost/boost/interprocess/sync/windows/recursive_mutex.hpp
Normal file
47
boost/boost/interprocess/sync/windows/recursive_mutex.hpp
Normal 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
|
||||
338
boost/boost/intrusive/any_hook.hpp
Normal file
338
boost/boost/intrusive/any_hook.hpp
Normal 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/boost/intrusive/avl_set.hpp
Normal file
1073
boost/boost/intrusive/avl_set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1069
boost/boost/intrusive/bs_set.hpp
Normal file
1069
boost/boost/intrusive/bs_set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
468
boost/boost/intrusive/circular_list_algorithms.hpp
Normal file
468
boost/boost/intrusive/circular_list_algorithms.hpp
Normal 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
|
||||
77
boost/boost/intrusive/derivation_value_traits.hpp
Normal file
77
boost/boost/intrusive/derivation_value_traits.hpp
Normal 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
|
||||
297
boost/boost/intrusive/detail/any_node_and_algorithms.hpp
Normal file
297
boost/boost/intrusive/detail/any_node_and_algorithms.hpp
Normal 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
|
||||
286
boost/boost/intrusive/detail/hashtable_node.hpp
Normal file
286
boost/boost/intrusive/detail/hashtable_node.hpp
Normal 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
|
||||
134
boost/boost/intrusive/detail/list_iterator.hpp
Normal file
134
boost/boost/intrusive/detail/list_iterator.hpp
Normal 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
|
||||
72
boost/boost/intrusive/detail/list_node.hpp
Normal file
72
boost/boost/intrusive/detail/list_node.hpp
Normal 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
|
||||
130
boost/boost/intrusive/detail/node_to_value.hpp
Normal file
130
boost/boost/intrusive/detail/node_to_value.hpp
Normal 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
|
||||
172
boost/boost/intrusive/detail/transform_iterator.hpp
Normal file
172
boost/boost/intrusive/detail/transform_iterator.hpp
Normal 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
|
||||
3585
boost/boost/intrusive/hashtable.hpp
Normal file
3585
boost/boost/intrusive/hashtable.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1509
boost/boost/intrusive/list.hpp
Normal file
1509
boost/boost/intrusive/list.hpp
Normal file
File diff suppressed because it is too large
Load Diff
289
boost/boost/intrusive/list_hook.hpp
Normal file
289
boost/boost/intrusive/list_hook.hpp
Normal 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
|
||||
85
boost/boost/intrusive/member_value_traits.hpp
Normal file
85
boost/boost/intrusive/member_value_traits.hpp
Normal 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
|
||||
82
boost/boost/intrusive/priority_compare.hpp
Normal file
82
boost/boost/intrusive/priority_compare.hpp
Normal 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/boost/intrusive/set.hpp
Normal file
1073
boost/boost/intrusive/set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1094
boost/boost/intrusive/sg_set.hpp
Normal file
1094
boost/boost/intrusive/sg_set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1110
boost/boost/intrusive/splay_set.hpp
Normal file
1110
boost/boost/intrusive/splay_set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1344
boost/boost/intrusive/treap.hpp
Normal file
1344
boost/boost/intrusive/treap.hpp
Normal file
File diff suppressed because it is too large
Load Diff
699
boost/boost/intrusive/treap_algorithms.hpp
Normal file
699
boost/boost/intrusive/treap_algorithms.hpp
Normal 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
|
||||
1106
boost/boost/intrusive/treap_set.hpp
Normal file
1106
boost/boost/intrusive/treap_set.hpp
Normal file
File diff suppressed because it is too large
Load Diff
59
boost/boost/intrusive/trivial_value_traits.hpp
Normal file
59
boost/boost/intrusive/trivial_value_traits.hpp
Normal 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
|
||||
990
boost/boost/intrusive/unordered_set.hpp
Normal file
990
boost/boost/intrusive/unordered_set.hpp
Normal 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
|
||||
459
boost/boost/intrusive/unordered_set_hook.hpp
Normal file
459
boost/boost/intrusive/unordered_set_hook.hpp
Normal 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
|
||||
1513
boost/boost/multi_index/composite_key.hpp
Normal file
1513
boost/boost/multi_index/composite_key.hpp
Normal file
File diff suppressed because it is too large
Load Diff
93
boost/boost/multi_index/detail/cons_stdtuple.hpp
Normal file
93
boost/boost/multi_index/detail/cons_stdtuple.hpp
Normal 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
|
||||
173
boost/boost/multi_index/detail/rnd_index_loader.hpp
Normal file
173
boost/boost/multi_index/detail/rnd_index_loader.hpp
Normal 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
|
||||
273
boost/boost/multi_index/detail/rnd_index_node.hpp
Normal file
273
boost/boost/multi_index/detail/rnd_index_node.hpp
Normal 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
|
||||
203
boost/boost/multi_index/detail/rnd_index_ops.hpp
Normal file
203
boost/boost/multi_index/detail/rnd_index_ops.hpp
Normal 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
|
||||
144
boost/boost/multi_index/detail/rnd_index_ptr_array.hpp
Normal file
144
boost/boost/multi_index/detail/rnd_index_ptr_array.hpp
Normal 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
|
||||
140
boost/boost/multi_index/detail/rnd_node_iterator.hpp
Normal file
140
boost/boost/multi_index/detail/rnd_node_iterator.hpp
Normal 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
|
||||
300
boost/boost/multi_index/detail/rnk_index_ops.hpp
Normal file
300
boost/boost/multi_index/detail/rnk_index_ops.hpp
Normal 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
|
||||
185
boost/boost/multi_index/global_fun.hpp
Normal file
185
boost/boost/multi_index/global_fun.hpp
Normal 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
|
||||
22
boost/boost/multi_index/key_extractors.hpp
Normal file
22
boost/boost/multi_index/key_extractors.hpp
Normal 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
|
||||
205
boost/boost/multi_index/mem_fun.hpp
Normal file
205
boost/boost/multi_index/mem_fun.hpp
Normal 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
|
||||
1167
boost/boost/multi_index/random_access_index.hpp
Normal file
1167
boost/boost/multi_index/random_access_index.hpp
Normal file
File diff suppressed because it is too large
Load Diff
91
boost/boost/multi_index/random_access_index_fwd.hpp
Normal file
91
boost/boost/multi_index/random_access_index_fwd.hpp
Normal 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
|
||||
382
boost/boost/multi_index/ranked_index.hpp
Normal file
382
boost/boost/multi_index/ranked_index.hpp
Normal 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
|
||||
35
boost/boost/multi_index/ranked_index_fwd.hpp
Normal file
35
boost/boost/multi_index/ranked_index_fwd.hpp
Normal 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
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user