Merge branch 'hotfix-2.0.0-rc4'

This commit is contained in:
Bill Somerville 2018-11-12 22:13:04 +00:00
commit a891ad6d9d
2490 changed files with 59534 additions and 278252 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ jnq*
*.exe
*.o
*.mod
*.pro.user

View File

@ -36,7 +36,8 @@ namespace
{
if (id)
{
auto len = std::min (size_t (4), strlen (id));
auto end = reinterpret_cast<char const *> (::memchr (id, '\0', 4u));
auto len = end ? end - id : 4u;
memcpy (id_.data (), id, len);
if (len < 4u)
{
@ -45,7 +46,7 @@ namespace
}
else
{
memcpy (id_.data (), "JUNK", 4);
memcpy (id_.data (), "JUNK", 4u);
}
}
@ -831,7 +832,8 @@ void BWFFile::bext_coding_history (QByteArray const& text)
m_->header_dirty_ = true;
m_->bext (); // ensure we have a correctly
// initialized m_->bext_
auto length = std::min (strlen (text.constData ()), size_t (text.size ()));
auto end = static_cast<char const *> (::memchr (text.constData (), '\0', size_t (text.size ())));
auto length = end ? end - text.constData () : size_t (text.size ());
m_->bext_.resize (sizeof (BroadcastAudioExtension) + length);
std::strncpy (m_->bext ()->coding_history_, text.constData (), length);
}

View File

@ -215,22 +215,22 @@ set (WSJT_QT_CONF_DESTINATION ${QT_CONF_DESTINATION} CACHE PATH "Path for the qt
#
set (wsjt_qt_CXXSRCS
qt_helpers.cpp
MessageBox.cpp
widgets/MessageBox.cpp
MetaDataRegistry.cpp
NetworkServerLookup.cpp
revision_utils.cpp
WFPalette.cpp
Radio.cpp
RadioMetaType.cpp
IARURegions.cpp
Bands.cpp
Modes.cpp
FrequencyList.cpp
StationList.cpp
FrequencyLineEdit.cpp
CandidateKeyFilter.cpp
ForeignKeyDelegate.cpp
LiveFrequencyValidator.cpp
models/IARURegions.cpp
models/Bands.cpp
models/Modes.cpp
models/FrequencyList.cpp
models/StationList.cpp
widgets/FrequencyLineEdit.cpp
item_delegates/CandidateKeyFilter.cpp
item_delegates/ForeignKeyDelegate.cpp
validators/LiveFrequencyValidator.cpp
GetUserId.cpp
TraceFile.cpp
AudioDevice.cpp
@ -244,10 +244,10 @@ set (wsjt_qt_CXXSRCS
DXLabSuiteCommanderTransceiver.cpp
NetworkMessage.cpp
MessageClient.cpp
LettersSpinBox.cpp
HintedSpinBox.cpp
RestrictedSpinBox.cpp
HelpTextWindow.cpp
widgets/LettersSpinBox.cpp
widgets/HintedSpinBox.cpp
widgets/RestrictedSpinBox.cpp
widgets/HelpTextWindow.cpp
SampleDownloader.cpp
SampleDownloader/DirectoryDelegate.cpp
SampleDownloader/Directory.cpp
@ -255,16 +255,21 @@ set (wsjt_qt_CXXSRCS
SampleDownloader/RemoteFile.cpp
DisplayManual.cpp
MultiSettings.cpp
MaidenheadLocatorValidator.cpp
CallsignValidator.cpp
ExchangeValidator.cpp
SplashScreen.cpp
validators/MaidenheadLocatorValidator.cpp
validators/CallsignValidator.cpp
widgets/SplashScreen.cpp
EqualizationToolsDialog.cpp
DoubleClickablePushButton.cpp
DoubleClickableRadioButton.cpp
widgets/DoubleClickablePushButton.cpp
widgets/DoubleClickableRadioButton.cpp
LotWUsers.cpp
DecodeHighlightingModel.cpp
DecodeHighlightingListView.cpp
models/DecodeHighlightingModel.cpp
widgets/DecodeHighlightingListView.cpp
models/FoxLog.cpp
widgets/FoxLogWindow.cpp
widgets/CabrilloLogWindow.cpp
item_delegates/CallsignDelegate.cpp
item_delegates/MaidenheadLocatorDelegate.cpp
models/CabrilloLog.cpp
)
set (wsjt_qtmm_CXXSRCS
@ -281,38 +286,37 @@ set (jt9_CXXSRCS
)
set (wsjtx_CXXSRCS
logbook/adif.cpp
logbook/countrydat.cpp
logbook/countriesworked.cpp
logbook/logbook.cpp
logbook/WorkedBefore.cpp
logbook/AD1CCty.cpp
psk_reporter.cpp
Modulator.cpp
Detector.cpp
logqso.cpp
displaytext.cpp
widgets/logqso.cpp
widgets/displaytext.cpp
decodedtext.cpp
getfile.cpp
soundout.cpp
soundin.cpp
meterwidget.cpp
signalmeter.cpp
plotter.cpp
widegraph.cpp
echograph.cpp
echoplot.cpp
fastgraph.cpp
fastplot.cpp
about.cpp
astro.cpp
messageaveraging.cpp
colorhighlighting.cpp
widgets/meterwidget.cpp
widgets/signalmeter.cpp
widgets/plotter.cpp
widgets/widegraph.cpp
widgets/echograph.cpp
widgets/echoplot.cpp
widgets/fastgraph.cpp
widgets/fastplot.cpp
widgets/about.cpp
widgets/astro.cpp
widgets/messageaveraging.cpp
widgets/colorhighlighting.cpp
WsprTxScheduler.cpp
mainwindow.cpp
widgets/mainwindow.cpp
Configuration.cpp
main.cpp
wsprnet.cpp
WSPRBandHopping.cpp
ExportCabrillo.cpp
widgets/ExportCabrillo.cpp
)
set (wsjt_CXXSRCS
@ -450,19 +454,15 @@ set (wsjt_FSRCS
lib/fqso_first.f90
lib/freqcal.f90
lib/ft8/ft8apset.f90
lib/ft8/ft8apset_174_91.f90
lib/ft8/ft8b_1.f90
lib/ft8/ft8b_2.f90
lib/ft8/ft8b.f90
lib/ft8/ft8code.f90
lib/ft8/ft8_downsample.f90
lib/ft8/ft8sim.f90
lib/ft8/ft8sim2.f90
lib/gen4.f90
lib/gen65.f90
lib/gen9.f90
lib/geniscat.f90
lib/ft8/genft8.f90
lib/ft8/genft8_174_91.f90
lib/genmsk_128_90.f90
lib/genmsk40.f90
lib/genqra64.f90
@ -497,7 +497,7 @@ set (wsjt_FSRCS
lib/moondopjpl.f90
lib/morse.f90
lib/move.f90
lib/msk144d2.f90
lib/msk144d.f90
lib/msk40decodeframe.f90
lib/msk144decodeframe.f90
lib/msk144sd.f90
@ -515,7 +515,6 @@ set (wsjt_FSRCS
lib/ft8/osd174.f90
lib/wsprd/osdwspr.f90
lib/ft8/osd174_91.f90
lib/77bit/parse77.f90
lib/pctile.f90
lib/peakdt9.f90
lib/peakup.f90
@ -619,6 +618,8 @@ set (wsjt_CSRCS
set (wsjt_qt_UISRCS
wf_palette_design_dialog.ui
widgets/FoxLogWindow.ui
widgets/CabrilloLogWindow.ui
)
set (wsprsim_CSRCS
@ -642,17 +643,17 @@ set (wsprd_CSRCS
)
set (wsjtx_UISRCS
mainwindow.ui
about.ui
astro.ui
colorhighlighting.ui
echograph.ui
fastgraph.ui
messageaveraging.ui
widegraph.ui
logqso.ui
widgets/mainwindow.ui
widgets/about.ui
widgets/astro.ui
widgets/colorhighlighting.ui
widgets/echograph.ui
widgets/fastgraph.ui
widgets/messageaveraging.ui
widgets/widegraph.ui
widgets/logqso.ui
Configuration.ui
ExportCabrillo.ui
widgets/ExportCabrillo.ui
)
set (UDP_library_CXXSRCS
@ -674,7 +675,7 @@ set (message_aggregator_CXXSRCS
UDPExamples/DecodesModel.cpp
UDPExamples/BeaconsModel.cpp
UDPExamples/ClientWidget.cpp
MaidenheadLocatorValidator.cpp
validators/MaidenheadLocatorValidator.cpp
)
set (message_aggregator_STYLESHEETS
@ -866,6 +867,7 @@ message (STATUS "hamlib_LIBRARY_DIRS: ${hamlib_LIBRARY_DIRS}")
find_package (Qt5Widgets 5 REQUIRED)
find_package (Qt5Multimedia 5 REQUIRED)
find_package (Qt5PrintSupport 5 REQUIRED)
find_package (Qt5Sql 5 REQUIRED)
if (WIN32)
add_definitions (-DQT_NEEDS_QTMAIN)
@ -1146,7 +1148,7 @@ target_link_libraries (qcp Qt5::Widgets Qt5::PrintSupport)
add_library (wsjt_qt STATIC ${wsjt_qt_CXXSRCS} ${wsjt_qt_GENUISRCS} ${GENAXSRCS})
# set wsjtx_udp exports to static variants
target_compile_definitions (wsjt_qt PUBLIC UDP_STATIC_DEFINE)
target_link_libraries (wsjt_qt qcp Qt5::Widgets Qt5::Network)
target_link_libraries (wsjt_qt qcp Qt5::Widgets Qt5::Network Qt5::Sql)
target_include_directories (wsjt_qt BEFORE PRIVATE ${hamlib_INCLUDE_DIRS})
if (WIN32)
target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
@ -1250,17 +1252,14 @@ target_link_libraries (ft8code wsjt_fort wsjt_cxx)
add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc)
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
add_executable (ft8sim2 lib/ft8/ft8sim2.f90 wsjtx.rc)
target_link_libraries (ft8sim2 wsjt_fort wsjt_cxx)
add_executable (msk144sd lib/msk144sd.f90 wsjtx.rc)
target_link_libraries (msk144sd wsjt_fort wsjt_cxx)
add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc)
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
add_executable (msk144d2 lib/msk144d2.f90 wsjtx.rc)
target_link_libraries (msk144d2 wsjt_fort wsjt_cxx)
add_executable (msk144d lib/msk144d.f90 wsjtx.rc)
target_link_libraries (msk144d wsjt_fort wsjt_cxx)
endif(WSJT_BUILD_UTILS)
# build the main application
@ -1557,6 +1556,13 @@ if (NOT is_debug_build)
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
PATTERN "*_debug${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
)
install (
FILES
${QT_PLUGINS_DIR}/sqldrivers/libqsqlite${CMAKE_SHARED_LIBRARY_SUFFIX}
DESTINATION ${WSJT_PLUGIN_DESTINATION}/sqldrivers
CONFIGURATIONS Release MinSizeRel
#COMPONENT runtime
)
# install (
# DIRECTORY
# ${QT_PLUGINS_DIR}/platforms
@ -1605,6 +1611,13 @@ if (NOT is_debug_build)
PATTERN "*quick*${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
PATTERN "*d${CMAKE_SHARED_LIBRARY_SUFFIX}" EXCLUDE
)
install (
FILES
${QT_PLUGINS_DIR}/sqldrivers/qsqlite${CMAKE_SHARED_LIBRARY_SUFFIX}
DESTINATION ${WSJT_PLUGIN_DESTINATION}/sqldrivers
CONFIGURATIONS Release MinSizeRel
#COMPONENT runtime
)
# install (
# DIRECTORY
# ${QT_PLUGINS_DIR}/platforms

View File

@ -1,89 +0,0 @@
#include "CandidateKeyFilter.hpp"
#include <QModelIndex>
#include <QAbstractItemModel>
#include "pimpl_impl.hpp"
class CandidateKeyFilter::impl final
{
public:
explicit impl (int referenced_key_column
, int referenced_key_role
, QAbstractItemModel const * referencing_model
, int referencing_key_column
, int referencing_key_role)
: referencing_ {referencing_model}
, referencing_key_column_ {referencing_key_column}
, referencing_key_role_ {referencing_key_role}
, referenced_key_column_ {referenced_key_column}
, referenced_key_role_ {referenced_key_role}
{
}
QAbstractItemModel const * referencing_;
int referencing_key_column_;
int referencing_key_role_;
int referenced_key_column_;
int referenced_key_role_;
QModelIndex active_key_;
};
CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel * referenced_model
, int referenced_key_column
, QObject * parent
, int referenced_key_role)
: QSortFilterProxyModel {parent}
, m_ {referenced_key_column, referenced_key_role, nullptr, 0, Qt::EditRole}
{
setSourceModel (referenced_model);
}
CandidateKeyFilter::CandidateKeyFilter (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent
, int referenced_key_role
, int referencing_key_role)
: QSortFilterProxyModel {parent}
, m_ {referenced_key_column, referenced_key_role, referencing_model, referencing_key_column, referencing_key_role}
{
setSourceModel (referenced_model);
}
CandidateKeyFilter::~CandidateKeyFilter ()
{
}
void CandidateKeyFilter::set_active_key (QModelIndex const& index)
{
if (m_->referencing_)
{
if (index.isValid () )
{
Q_ASSERT (index.column () == m_->referencing_key_column_);
m_->active_key_ = index;
}
invalidateFilter ();
}
}
bool CandidateKeyFilter::filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const
{
if (!m_->referencing_) // many to many passes all
{
return true;
}
auto candidate_key = sourceModel ()->index (candidate_row, m_->referenced_key_column_, candidate_parent).data (m_->referenced_key_role_);
// Include the current key.
if (m_->active_key_.isValid () && candidate_key == m_->active_key_.data (m_->referencing_key_role_))
{
return true;
}
// Filter out any candidates already in the referencing key rows.
return m_->referencing_->match (m_->referencing_->index (0, m_->referencing_key_column_), m_->referencing_key_role_, candidate_key, 1, Qt::MatchExactly).isEmpty ();
}

View File

@ -1,41 +0,0 @@
#ifndef CANDIDATE_KEY_FILTER_HPP_
#define CANDIDATE_KEY_FILTER_HPP_
#include <QSortFilterProxyModel>
#include <QModelIndex>
#include "pimpl_h.hpp"
class QAbstractItemModel;
class CandidateKeyFilter final
: public QSortFilterProxyModel
{
public:
explicit CandidateKeyFilter (QAbstractItemModel * referenced_model
, int referenced_key_column
, QObject * parent = nullptr
, int referenced_key_role = Qt::EditRole);
explicit CandidateKeyFilter (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent = nullptr
, int referenced_key_role = Qt::EditRole
, int referencing_key_role = Qt::EditRole);
~CandidateKeyFilter ();
// this key is not to be filtered, usually because we want to allow
// it since we are editing the row that contains it this it is valid
// even though it is in use
void set_active_key (QModelIndex const& index = QModelIndex {});
protected:
bool filterAcceptsRow (int candidate_row, QModelIndex const& candidate_parent) const override;
private:
class impl;
pimpl<impl> m_;
};
#endif

View File

@ -150,7 +150,8 @@
#include <QStringList>
#include <QStringListModel>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QIntValidator>
#include <QThread>
#include <QTimer>
@ -165,23 +166,22 @@
#include "qt_helpers.hpp"
#include "MetaDataRegistry.hpp"
#include "SettingsGroup.hpp"
#include "FrequencyLineEdit.hpp"
#include "CandidateKeyFilter.hpp"
#include "ForeignKeyDelegate.hpp"
#include "widgets/FrequencyLineEdit.hpp"
#include "item_delegates/CandidateKeyFilter.hpp"
#include "item_delegates/ForeignKeyDelegate.hpp"
#include "TransceiverFactory.hpp"
#include "Transceiver.hpp"
#include "Bands.hpp"
#include "IARURegions.hpp"
#include "Modes.hpp"
#include "FrequencyList.hpp"
#include "StationList.hpp"
#include "models/Bands.hpp"
#include "models/IARURegions.hpp"
#include "models/Modes.hpp"
#include "models/FrequencyList.hpp"
#include "models/StationList.hpp"
#include "NetworkServerLookup.hpp"
#include "MessageBox.hpp"
#include "MaidenheadLocatorValidator.hpp"
#include "CallsignValidator.hpp"
#include "widgets/MessageBox.hpp"
#include "validators/MaidenheadLocatorValidator.hpp"
#include "validators/CallsignValidator.hpp"
#include "LotWUsers.hpp"
#include "ExchangeValidator.hpp"
#include "DecodeHighlightingModel.hpp"
#include "models/DecodeHighlightingModel.hpp"
#include "ui_Configuration.h"
#include "moc_Configuration.cpp"
@ -195,7 +195,42 @@ namespace
int const combo_box_item_disabled (0);
// QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
QRegularExpression message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
QRegularExpression RTTY_roundup_exchange_re {
R"(
(
AL|AK|AZ|AR|CA|CO|CT|DE|FL|GA # states
|HI|ID|IL|IN|IA|KS|KY|LA|ME|MD
|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ
|NM|NY|NC|ND|OH|OK|OR|PA|RI|SC
|SD|TN|TX|UT|VT|VA|WA|WV|WI|WY
|NB|NS|QC|ON|MB|SK|AB|BC|NWT|NF # VE provinces
|LB|NU|YT|PEI|DC
|DX # anyone else
)
)", QRegularExpression::CaseInsensitiveOption | QRegularExpression::ExtendedPatternSyntaxOption};
QRegularExpression field_day_exchange_re {
R"(
(
[1-9] # # transmitters (1 to 32 inc.)
|[0-2]\d
|3[0-2]
)
[A-F]\ # class and space
(
AB|AK|AL|AR|AZ|BC|CO|CT|DE|EB # ARRL/RAC section
|EMA|ENY|EPA|EWA|GA|GTA|IA|ID
|IL|IN|KS|KY|LA|LAX|MAR|MB|MDC
|ME|MI|MN|MO|MS|MT|NC|ND|NE|NFL
|NH|NL|NLI|NM|NNJ|NNY|NT|NTX|NV
|OH|OK|ONE|ONN|ONS|OR|ORG|PAC
|PR|QC|RI|SB|SC|SCV|SD|SDG|SF
|SFL|SJV|SK|SNJ|STX|SV|TN|UT|VA
|VI|VT|WCF|WI|WMA|WNY|WPA|WTX
|WV|WWA|WY
|DX # anyone else
)
)", QRegularExpression::CaseInsensitiveOption | QRegularExpression::ExtendedPatternSyntaxOption};
// Magic numbers for file validation
constexpr quint32 qrg_magic {0xadbccbdb};
@ -341,7 +376,7 @@ public:
{
auto editor = new QLineEdit {parent};
editor->setFrame (false);
editor->setValidator (new QRegExpValidator {message_alphabet, editor});
editor->setValidator (new QRegularExpressionValidator {message_alphabet, editor});
return editor;
}
};
@ -414,7 +449,6 @@ private:
void delete_stations ();
void insert_station ();
void chk77();
Q_SLOT void on_font_push_button_clicked ();
Q_SLOT void on_decoded_text_font_push_button_clicked ();
@ -447,15 +481,8 @@ private:
Q_SLOT void handle_transceiver_failure (QString const& reason);
Q_SLOT void on_reset_highlighting_to_defaults_push_button_clicked (bool);
Q_SLOT void on_LotW_CSV_fetch_push_button_clicked (bool);
Q_SLOT void on_cbFox_clicked (bool);
Q_SLOT void on_cbHound_clicked (bool);
Q_SLOT void on_cbx2ToneSpacing_clicked(bool);
Q_SLOT void on_cbx4ToneSpacing_clicked(bool);
Q_SLOT void on_rbNone_toggled(bool);
Q_SLOT void on_rbFieldDay_toggled();
Q_SLOT void on_rbRTTYroundup_toggled();
Q_SLOT void on_FieldDay_Exchange_textChanged();
Q_SLOT void on_RTTY_Exchange_textChanged();
Q_SLOT void on_prompt_to_log_check_box_clicked(bool);
Q_SLOT void on_cbAutoLog_clicked(bool);
@ -527,6 +554,7 @@ private:
DecodeHighlightingModel decode_highlighing_model_;
DecodeHighlightingModel next_decode_highlighing_model_;
bool highlight_by_mode_;
int LotW_days_since_upload_;
TransceiverFactory::ParameterPack rig_params_;
@ -577,15 +605,8 @@ private:
bool decode_at_52s_;
bool single_decode_;
bool twoPass_;
bool bFox_;
bool bHound_;
bool bGenerate77_;
bool bDecode77_;
bool bNoSpecial_;
bool bFieldDay_;
bool bRTTYroundup_;
bool bNA_VHF_Contest_;
bool bEU_VHF_Contest_;
bool bSpecialOp_;
int SelectedActivity_;
bool x2ToneSpacing_;
bool x4ToneSpacing_;
bool use_dynamic_grid_;
@ -677,15 +698,6 @@ bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features
bool Configuration::decode_at_52s () const {return m_->decode_at_52s_;}
bool Configuration::single_decode () const {return m_->single_decode_;}
bool Configuration::twoPass() const {return m_->twoPass_;}
bool Configuration::bFox() const {return m_->bFox_;}
bool Configuration::bHound() const {return m_->bHound_;}
bool Configuration::bGenerate77() const {return m_->bGenerate77_;}
bool Configuration::bDecode77() const {return m_->bDecode77_;}
bool Configuration::bNoSpecial() const {return m_->bNoSpecial_;}
bool Configuration::bFieldDay() const {return m_->bFieldDay_;}
bool Configuration::bRTTYroundup() const {return m_->bRTTYroundup_;}
bool Configuration::bNA_VHF_Contest() const {return m_->bNA_VHF_Contest_;}
bool Configuration::bEU_VHF_Contest() const {return m_->bEU_VHF_Contest_;}
bool Configuration::x2ToneSpacing() const {return m_->x2ToneSpacing_;}
bool Configuration::x4ToneSpacing() const {return m_->x4ToneSpacing_;}
bool Configuration::split_mode () const {return m_->split_mode ();}
@ -714,6 +726,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)
{
@ -826,24 +839,30 @@ QString Configuration::my_grid() const
return the_grid;
}
QString Configuration::FieldDayExchange() const
QString Configuration::Field_Day_Exchange() const
{
return m_->FD_exchange_;
}
void Configuration::setEU_VHF_Contest()
{
m_->bEU_VHF_Contest_ = true;
m_->ui_->rbEU_VHF_Contest->setChecked(m_->bEU_VHF_Contest_);
m_->ui_->cbGenerate77->setChecked(true);
{
m_->bSpecialOp_=true;
m_->ui_->gbSpecialOpActivity->setChecked(m_->bSpecialOp_);
m_->ui_->rbEU_VHF_Contest->setChecked(true);
m_->SelectedActivity_ = static_cast<int> (SpecialOperatingActivity::EU_VHF);
m_->write_settings();
}
QString Configuration::RTTYExchange() const
QString Configuration::RTTY_Exchange() const
{
return m_->RTTY_exchange_;
}
auto Configuration::special_op_id () const -> SpecialOperatingActivity
{
return m_->bSpecialOp_ ? static_cast<SpecialOperatingActivity> (m_->SelectedActivity_) : SpecialOperatingActivity::NONE;
}
void Configuration::set_location (QString const& grid_descriptor)
{
// change the dynamic grid
@ -910,6 +929,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}
@ -925,17 +945,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
, default_audio_output_device_selected_ {false}
{
ui_->setupUi (this);
// ui_->groupBox_6->setVisible(false); //### Temporary ??? ###
{
// Find a suitable data file location
if (!writeable_data_dir_.mkpath ("."))
{
MessageBox::critical_message (this, tr ("Failed to create data directory"),
tr ("path: \"%1\"").arg (writeable_data_dir_.absolutePath ()));
throw std::runtime_error {"Failed to create data directory"};
}
// Make sure the default save directory exists
QString save_dir {"save"};
default_save_directory_ = writeable_data_dir_;
@ -993,9 +1004,9 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
// validation
ui_->callsign_line_edit->setValidator (new CallsignValidator {this});
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this});
ui_->add_macro_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->FieldDay_Exchange->setValidator(new ExchangeValidator{this});
ui_->RTTY_Exchange->setValidator(new ExchangeValidator{this});
ui_->add_macro_line_edit->setValidator (new QRegularExpressionValidator {message_alphabet, this});
ui_->Field_Day_Exchange->setValidator(new QRegularExpressionValidator {field_day_exchange_re});
ui_->RTTY_Exchange->setValidator(new QRegularExpressionValidator {RTTY_roundup_exchange_re});
ui_->udp_server_port_spin_box->setMinimum (1);
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
@ -1035,6 +1046,13 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
ui_->split_mode_button_group->setId (ui_->split_rig_radio_button, TransceiverFactory::split_mode_rig);
ui_->split_mode_button_group->setId (ui_->split_emulate_radio_button, TransceiverFactory::split_mode_emulate);
ui_->special_op_activity_button_group->setId (ui_->rbNA_VHF_Contest, static_cast<int> (SpecialOperatingActivity::NA_VHF));
ui_->special_op_activity_button_group->setId (ui_->rbEU_VHF_Contest, static_cast<int> (SpecialOperatingActivity::EU_VHF));
ui_->special_op_activity_button_group->setId (ui_->rbField_Day, static_cast<int> (SpecialOperatingActivity::FIELD_DAY));
ui_->special_op_activity_button_group->setId (ui_->rbRTTY_Roundup, static_cast<int> (SpecialOperatingActivity::RTTY));
ui_->special_op_activity_button_group->setId (ui_->rbFox, static_cast<int> (SpecialOperatingActivity::FOX));
ui_->special_op_activity_button_group->setId (ui_->rbHound, static_cast<int> (SpecialOperatingActivity::HOUND));
//
// setup PTT port combo box drop down content
//
@ -1206,15 +1224,8 @@ void Configuration::impl::initialize_models ()
ui_->decode_at_52s_check_box->setChecked(decode_at_52s_);
ui_->single_decode_check_box->setChecked(single_decode_);
ui_->cbTwoPass->setChecked(twoPass_);
ui_->cbFox->setChecked(bFox_);
ui_->cbHound->setChecked(bHound_);
ui_->cbGenerate77->setChecked(bGenerate77_);
ui_->cbDecode77->setChecked(bDecode77_);
ui_->rbNone->setChecked(bNoSpecial_);
ui_->rbFieldDay->setChecked(bFieldDay_);
ui_->rbRTTYroundup->setChecked(bRTTYroundup_);
ui_->rbNA_VHF_Contest->setChecked(bNA_VHF_Contest_);
ui_->rbEU_VHF_Contest->setChecked(bEU_VHF_Contest_);
ui_->gbSpecialOpActivity->setChecked(bSpecialOp_);
ui_->special_op_activity_button_group->button (SelectedActivity_)->setChecked (true);
ui_->cbx2ToneSpacing->setChecked(x2ToneSpacing_);
ui_->cbx4ToneSpacing->setChecked(x4ToneSpacing_);
ui_->type_2_msg_gen_combo_box->setCurrentIndex (type_2_msg_gen_);
@ -1256,7 +1267,6 @@ void Configuration::impl::initialize_models ()
ui_->udpWindowRestore->setChecked(udpWindowRestore_);
ui_->calibration_intercept_spin_box->setValue (calibration_.intercept);
ui_->calibration_slope_ppm_spin_box->setValue (calibration_.slope_ppm);
chk77();
if (rig_params_.ptt_port.isEmpty ())
{
@ -1277,6 +1287,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 ();
@ -1298,9 +1309,9 @@ void Configuration::impl::read_settings ()
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
my_grid_ = settings_->value ("MyGrid", QString {}).toString ();
FD_exchange_ = settings_->value ("FieldDayExchange",QString {}).toString ();
RTTY_exchange_ = settings_->value ("RTTYExchange",QString {}).toString ();
ui_->FieldDay_Exchange->setText(FD_exchange_);
FD_exchange_ = settings_->value ("Field_Day_Exchange",QString {}).toString ();
RTTY_exchange_ = settings_->value ("RTTY_Exchange",QString {}).toString ();
ui_->Field_Day_Exchange->setText(FD_exchange_);
ui_->RTTY_Exchange->setText(RTTY_exchange_);
if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ())
&& next_font_ != font_)
@ -1422,6 +1433,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_);
@ -1459,15 +1471,8 @@ void Configuration::impl::read_settings ()
decode_at_52s_ = settings_->value("Decode52",false).toBool ();
single_decode_ = settings_->value("SingleDecode",false).toBool ();
twoPass_ = settings_->value("TwoPass",true).toBool ();
bFox_ = settings_->value("Fox",false).toBool ();
bHound_ = settings_->value("Hound",false).toBool ();
bGenerate77_ = settings_->value("Generate77",false).toBool ();
bDecode77_ = settings_->value("Decode77",false).toBool ();
bNoSpecial_ = settings_->value("NoSpecial",false).toBool ();
bFieldDay_ = settings_->value("FieldDay",false).toBool ();
bRTTYroundup_ = settings_->value("RTTYroundup",false).toBool ();
bNA_VHF_Contest_ = settings_->value("NA_VHF_Contest",false).toBool ();
bEU_VHF_Contest_ = settings_->value("EU_VHF_Contest",false).toBool ();
bSpecialOp_ = settings_->value("SpecialOpActivity",false).toBool ();
SelectedActivity_ = settings_->value("SelectedActivity",1).toInt ();
x2ToneSpacing_ = settings_->value("x2ToneSpacing",false).toBool ();
x4ToneSpacing_ = settings_->value("x4ToneSpacing",false).toBool ();
rig_params_.poll_interval = settings_->value ("Polling", 0).toInt ();
@ -1493,8 +1498,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("MyCall", my_callsign_);
settings_->setValue ("MyGrid", my_grid_);
settings_->setValue ("FieldDayExchange", FD_exchange_);
settings_->setValue ("RTTYExchange", RTTY_exchange_);
settings_->setValue ("Field_Day_Exchange", FD_exchange_);
settings_->setValue ("RTTY_Exchange", RTTY_exchange_);
settings_->setValue ("Font", font_.toString ());
settings_->setValue ("DecodedTextFont", decoded_text_font_.toString ());
settings_->setValue ("IDint", id_interval_);
@ -1537,6 +1542,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_);
@ -1571,15 +1577,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("Decode52", decode_at_52s_);
settings_->setValue ("SingleDecode", single_decode_);
settings_->setValue ("TwoPass", twoPass_);
settings_->setValue ("Fox", bFox_);
settings_->setValue ("Hound", bHound_);
settings_->setValue ("Generate77", bGenerate77_);
settings_->setValue ("Decode77", bDecode77_);
settings_->setValue ("NoSpecial", bNoSpecial_);
settings_->setValue ("FieldDay", bFieldDay_);
settings_->setValue ("RTTYroundup", bRTTYroundup_);
settings_->setValue ("NA_VHF_Contest", bNA_VHF_Contest_);
settings_->setValue ("EU_VHF_Contest", bEU_VHF_Contest_);
settings_->setValue ("SelectedActivity", SelectedActivity_);
settings_->setValue ("SpecialOpActivity", bSpecialOp_);
settings_->setValue ("x2ToneSpacing", x2ToneSpacing_);
settings_->setValue ("x4ToneSpacing", x4ToneSpacing_);
settings_->setValue ("OpCall", opCall_);
@ -1758,6 +1757,42 @@ bool Configuration::impl::validate ()
return false;
}
if (ui_->rbField_Day-> isChecked () &&
!ui_->Field_Day_Exchange->hasAcceptableInput ())
{
for (auto * parent = ui_->Field_Day_Exchange->parentWidget (); parent; parent = parent->parentWidget ())
{
auto index = ui_->configuration_tabs->indexOf (parent);
if (index != -1)
{
ui_->configuration_tabs->setCurrentIndex (index);
break;
}
}
ui_->Field_Day_Exchange->setFocus ();
MessageBox::critical_message (this, tr ("Invalid Contest Exchange")
, tr ("You must input a valid ARRL Field Day exchange"));
return false;
}
if (ui_->rbRTTY_Roundup-> isChecked () &&
!ui_->RTTY_Exchange->hasAcceptableInput ())
{
for (auto * parent = ui_->RTTY_Exchange->parentWidget (); parent; parent = parent->parentWidget ())
{
auto index = ui_->configuration_tabs->indexOf (parent);
if (index != -1)
{
ui_->configuration_tabs->setCurrentIndex (index);
break;
}
}
ui_->RTTY_Exchange->setFocus ();
MessageBox::critical_message (this, tr ("Invalid Contest Exchange")
, tr ("You must input a valid ARRL RTTY Roundup exchange"));
return false;
}
return true;
}
@ -1946,8 +1981,8 @@ void Configuration::impl::accept ()
my_callsign_ = ui_->callsign_line_edit->text ();
my_grid_ = ui_->grid_line_edit->text ();
FD_exchange_= ui_->FieldDay_Exchange->text ();
RTTY_exchange_= ui_->RTTY_Exchange->text ();
FD_exchange_= ui_->Field_Day_Exchange->text ().toUpper ();
RTTY_exchange_= ui_->RTTY_Exchange->text ().toUpper ();
spot_to_psk_reporter_ = ui_->psk_reporter_check_box->isChecked ();
id_interval_ = ui_->CW_id_interval_spin_box->value ();
ntrials_ = ui_->sbNtrials->value ();
@ -1980,16 +2015,8 @@ void Configuration::impl::accept ()
decode_at_52s_ = ui_->decode_at_52s_check_box->isChecked ();
single_decode_ = ui_->single_decode_check_box->isChecked ();
twoPass_ = ui_->cbTwoPass->isChecked ();
bFox_ = ui_->cbFox->isChecked ();
bHound_ = ui_->cbHound->isChecked ();
if(bFox_ or bHound_) ui_->rbNone->setChecked(true); //###
bGenerate77_ = ui_->cbGenerate77->isChecked();
bDecode77_ = ui_->cbDecode77->isChecked();
bNoSpecial_ = ui_->rbNone->isChecked ();
bFieldDay_ = ui_->rbFieldDay->isChecked ();
bRTTYroundup_ = ui_->rbRTTYroundup->isChecked ();
bNA_VHF_Contest_ = ui_->rbNA_VHF_Contest->isChecked ();
bEU_VHF_Contest_ = ui_->rbEU_VHF_Contest->isChecked ();
bSpecialOp_ = ui_->gbSpecialOpActivity->isChecked ();
SelectedActivity_ = ui_->special_op_activity_button_group->checkedId();
x2ToneSpacing_ = ui_->cbx2ToneSpacing->isChecked ();
x4ToneSpacing_ = ui_->cbx4ToneSpacing->isChecked ();
calibration_.intercept = ui_->calibration_intercept_spin_box->value ();
@ -2043,6 +2070,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_);
@ -2214,20 +2242,6 @@ void Configuration::impl::on_add_macro_line_edit_editingFinished ()
ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ());
}
void Configuration::impl::on_FieldDay_Exchange_textChanged()
{
bool b=ui_->FieldDay_Exchange->hasAcceptableInput() or !ui_->rbFieldDay->isChecked();
if(b) ui_->FieldDay_Exchange->setStyleSheet("color: black");
if(!b) ui_->FieldDay_Exchange->setStyleSheet("color: red");
}
void Configuration::impl::on_RTTY_Exchange_textChanged()
{
bool b=ui_->RTTY_Exchange->hasAcceptableInput() or !ui_->rbRTTYroundup->isChecked();
if(b) ui_->RTTY_Exchange->setStyleSheet("color: black");
if(!b) ui_->RTTY_Exchange->setStyleSheet("color: red");
}
void Configuration::impl::on_delete_macro_push_button_clicked (bool /* checked */)
{
auto selection_model = ui_->macros_list_view->selectionModel ();
@ -2468,49 +2482,6 @@ void Configuration::impl::on_cbAutoLog_clicked(bool checked)
if(checked) ui_->prompt_to_log_check_box->setChecked(false);
}
void Configuration::impl::on_cbFox_clicked (bool checked)
{
if(checked) {
ui_->cbHound->setChecked (false);
ui_->rbNone->setChecked(true);
}
chk77();
}
void Configuration::impl::on_cbHound_clicked (bool checked)
{
if(checked) {
ui_->cbFox->setChecked (false);
ui_->rbNone->setChecked(true);
}
chk77();
}
void Configuration::impl::chk77()
{
bool b77OK = !ui_->cbFox->isChecked() and !ui_->cbHound->isChecked();
ui_->groupBox_9->setEnabled(b77OK);
if(!b77OK) {
ui_->cbGenerate77->setChecked(true);
ui_->cbDecode77->setChecked(true);
}
}
void Configuration::impl::on_rbNone_toggled(bool b)
{
if(!b) ui_->cbGenerate77->setChecked(true);
}
void Configuration::impl::on_rbFieldDay_toggled()
{
on_FieldDay_Exchange_textChanged();
}
void Configuration::impl::on_rbRTTYroundup_toggled()
{
on_RTTY_Exchange_textChanged();
}
void Configuration::impl::on_cbx2ToneSpacing_clicked(bool b)
{
if(b) ui_->cbx4ToneSpacing->setChecked(false);

View File

@ -5,7 +5,7 @@
#include <QFont>
#include "Radio.hpp"
#include "IARURegions.hpp"
#include "models/IARURegions.hpp"
#include "AudioDevice.hpp"
#include "Transceiver.hpp"
@ -98,8 +98,8 @@ public:
QString my_callsign () const;
QString my_grid () const;
QString FieldDayExchange() const;
QString RTTYExchange() const;
QString Field_Day_Exchange() const;
QString RTTY_Exchange() const;
void setEU_VHF_Contest();
QFont text_font () const;
QFont decoded_text_font () const;
@ -134,13 +134,6 @@ public:
bool twoPass() const;
bool bFox() const;
bool bHound() const;
bool bGenerate77() const;
bool bDecode77() const;
bool bNoSpecial() const;
bool bFieldDay() const;
bool bRTTYroundup() const;
bool bNA_VHF_Contest() const;
bool bEU_VHF_Contest() const;
bool x2ToneSpacing() const;
bool x4ToneSpacing() const;
bool MyDx() const;
@ -176,6 +169,10 @@ public:
bool pwrBandTuneMemory () const;
LotWUsers const& lotw_users () const;
DecodeHighlightingModel const& decode_highlighting () const;
bool highlight_by_mode () const;
enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, FOX, HOUND};
SpecialOperatingActivity special_op_id () const;
struct CalibrationParams
{

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>534</width>
<height>546</height>
<width>542</width>
<height>542</height>
</rect>
</property>
<property name="windowTitle">
@ -2197,10 +2197,7 @@ Right click for insert and delete options.</string>
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable using the check boxes and right-click an item to change the foreground color, background color, or reset the item to default values.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable using the check boxes and right-click an item to change the foreground color, background color, or reset the item to default values. Drag and drop the items to change their priority, higher in the list is higher in priority.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
@ -2235,6 +2232,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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check to indicate new DXCC entities, grid squares, and callsigns per mode.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Highlight by Mode</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -2313,19 +2324,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 +2337,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">
@ -2414,59 +2425,238 @@ Right click for insert and delete options.</string>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_8">
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="gbSpecialOpActivity">
<property name="title">
<string>FT8 message types</string>
<string>Special operating activity: Generation of FT8 and MSK144 messages</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<widget class="QCheckBox" name="cbGenerate77">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;By default, early candidate releases of WSJT-X 2.0 generate 75-bit messages if the message content allows it.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Always generate 77-bit messages</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbDecode77">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check this box to ignore FT8 transmissions using the older 75-bit protocol.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Decode only 77-bit messages</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>FT8 DXpedition mode</string>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QCheckBox" name="cbFox">
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,2,1,0,0">
<item row="0" column="1" rowspan="3">
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1">
<item>
<widget class="QRadioButton" name="rbField_Day">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>ARRL Field Day</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout_16">
<item row="0" column="0">
<widget class="QLabel" name="labFD">
<property name="text">
<string>Exch:</string>
</property>
<property name="buddy">
<cstring>Field_Day_Exchange</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="Field_Day_Exchange">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>6A SNJ</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="2" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
<item>
<widget class="QRadioButton" name="rbRTTY_Roundup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>ARRL RTTY Roundup</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout_17">
<item row="0" column="0">
<widget class="QLabel" name="labRTTY">
<property name="text">
<string>Exch:</string>
</property>
<property name="buddy">
<cstring>RTTY_Exchange</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="RTTY_Exchange">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>NJ</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="rbFox">
<property name="toolTip">
<string>Fox is the DXpedition station</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;FT8 DXpedition mode: Fox (DXpedition) operator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string> Fox</string>
<string>Fox</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbHound">
<item row="2" column="0">
<widget class="QRadioButton" name="rbEU_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Everybody else is a Hound</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;European VHF+ contests requiring a signal report, serial number, and 6-character locator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>EU VHF Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="rbNA_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>NA VHF Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="0" column="4" rowspan="3">
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QRadioButton" name="rbHound">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;FT8 DXpedition mode: Hound operator calling the DX.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Hound</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
</layout>
@ -2606,7 +2796,7 @@ Right click for insert and delete options.</string>
</layout>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -2619,206 +2809,6 @@ Right click for insert and delete options.</string>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_9">
<property name="title">
<string>Special operating activity: Generation of FT8 and MSK144 messages</string>
</property>
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,2,1,0">
<item row="0" column="0">
<widget class="QRadioButton" name="rbNone">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For normal operating&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>None</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="rbEU_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;European VHF+ contests requiring a signal report, serial number, and 6-character locator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>EU VHF Contest</string>
</property>
</widget>
</item>
<item row="2" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
<item>
<widget class="QRadioButton" name="rbRTTYroundup">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>ARRL RTTY Roundup</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout_17">
<item row="0" column="0">
<widget class="QLabel" name="labRTTY">
<property name="text">
<string>Exch:</string>
</property>
<property name="buddy">
<cstring>RTTY_Exchange</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="RTTY_Exchange">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>NJ</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1">
<item>
<widget class="QRadioButton" name="rbFieldDay">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>ARRL Field Day</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout_16">
<item row="0" column="0">
<widget class="QLabel" name="labFD">
<property name="text">
<string>Exch:</string>
</property>
<property name="buddy">
<cstring>FieldDay_Exchange</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="FieldDay_Exchange">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &amp;quot;DX&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>6A SNJ</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="rbNA_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>NA VHF Contest</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="3">
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3" rowspan="3">
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
@ -2842,7 +2832,7 @@ Right click for insert and delete options.</string>
<customwidget>
<class>DecodeHighlightingListView</class>
<extends>QListView</extends>
<header>DecodeHighlightingListView.hpp</header>
<header>widgets/DecodeHighlightingListView.hpp</header>
</customwidget>
</customwidgets>
<tabstops>
@ -2934,6 +2924,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>
@ -2945,16 +2936,12 @@ Right click for insert and delete options.</string>
<tabstop>sbTxDelay</tabstop>
<tabstop>cbx2ToneSpacing</tabstop>
<tabstop>cbx4ToneSpacing</tabstop>
<tabstop>cbFox</tabstop>
<tabstop>cbHound</tabstop>
<tabstop>cbGenerate77</tabstop>
<tabstop>cbDecode77</tabstop>
<tabstop>rbNone</tabstop>
<tabstop>rbFox</tabstop>
<tabstop>rbNA_VHF_Contest</tabstop>
<tabstop>rbEU_VHF_Contest</tabstop>
<tabstop>rbFieldDay</tabstop>
<tabstop>FieldDay_Exchange</tabstop>
<tabstop>rbRTTYroundup</tabstop>
<tabstop>rbField_Day</tabstop>
<tabstop>Field_Day_Exchange</tabstop>
<tabstop>rbRTTY_Roundup</tabstop>
<tabstop>RTTY_Exchange</tabstop>
</tabstops>
<resources/>
@ -3025,12 +3012,13 @@ Right click for insert and delete options.</string>
</connection>
</connections>
<buttongroups>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
</buttongroups>
</ui>

View File

@ -1,77 +0,0 @@
#include "DecodeHighlightingListView.hpp"
#include <QAction>
#include <QColorDialog>
#include "DecodeHighlightingModel.hpp"
#include "MessageBox.hpp"
#include "pimpl_impl.hpp"
class DecodeHighlightingListView::impl final
{
public:
impl ()
: fg_colour_action_ {tr ("&Foreground color ..."), nullptr}
, bg_colour_action_ {tr ("&Background color ..."), nullptr}
, defaults_action_ {tr ("&Reset this item to defaults"), nullptr}
{
}
DecodeHighlightingListView * self_;
QAction fg_colour_action_;
QAction bg_colour_action_;
QAction defaults_action_;
};
DecodeHighlightingListView::DecodeHighlightingListView (QWidget * parent)
: QListView {parent}
{
addAction (&m_->fg_colour_action_);
addAction (&m_->bg_colour_action_);
addAction (&m_->defaults_action_);
connect (&m_->fg_colour_action_, &QAction::triggered, [this] (bool /*checked*/) {
auto const& index = currentIndex ();
auto colour = QColorDialog::getColor (model ()->data (index, Qt::ForegroundRole).value<QBrush> ().color ()
, this
, tr ("Choose %1 Foreground Color")
.arg (model ()->data (index).toString ()));
if (colour.isValid ())
{
model ()->setData (index, colour, Qt::ForegroundRole);
}
});
connect (&m_->bg_colour_action_, &QAction::triggered, [this] (bool /*checked*/) {
auto const& index = currentIndex ();
auto colour = QColorDialog::getColor (model ()->data (index, Qt::BackgroundRole).value<QBrush> ().color ()
, this
, tr ("Choose %1 Background Color")
.arg (model ()->data (index).toString ()));
if (colour.isValid ())
{
model ()->setData (index, colour, Qt::BackgroundRole);
}
});
connect (&m_->defaults_action_, &QAction::triggered, [this] (bool /*checked*/) {
auto const& index = currentIndex ();
model ()->setData (index, model ()->data (index, DecodeHighlightingModel::EnabledDefaultRole).toBool () ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
model ()->setData (index, model ()->data (index, DecodeHighlightingModel::ForegroundDefaultRole), Qt::ForegroundRole);
model ()->setData (index, model ()->data (index, DecodeHighlightingModel::BackgroundDefaultRole), Qt::BackgroundRole);
});
}
DecodeHighlightingListView::~DecodeHighlightingListView ()
{
}
QSize DecodeHighlightingListView::sizeHint () const
{
auto item_height = sizeHintForRow (0);
if (item_height >= 0)
{
// set the height hint to exactly the space required for all the
// items
return {width (), (model ()->rowCount () * (item_height + 2 * spacing ())) + 2 * frameWidth ()};
}
return QListView::sizeHint ();
}

View File

@ -1,319 +0,0 @@
#include "DecodeHighlightingModel.hpp"
#include <QString>
#include <QVariant>
#include <QList>
#include <QBrush>
#include <QFont>
#include <QMap>
#include <QVector>
#include <QDataStream>
#include <QMetaType>
#include <QDebug>
#include "pimpl_impl.hpp"
#include "moc_DecodeHighlightingModel.cpp"
class DecodeHighlightingModel::impl final
{
public:
explicit impl ()
: data_ {defaults_}
{
}
HighlightItems static const defaults_;
HighlightItems data_;
QFont font_;
};
QList<DecodeHighlightingModel::HighlightInfo> const DecodeHighlightingModel::impl::defaults_ = {
{Highlight::CQ, true, {}, {{0x66, 0xff, 0x66}}}
, {Highlight::MyCall, true, {}, {{0xff, 0x66, 0x66}}}
, {Highlight::Tx, true, {}, {{Qt::yellow}}}
, {Highlight::DXCC, true, {}, {{0xff, 0x00, 0xff}}}
, {Highlight::DXCCBand, true, {}, {{0xff, 0xaa, 0xff}}}
, {Highlight::Grid, false, {}, {{0xff, 0x80, 0x00}}}
, {Highlight::GridBand, false, {}, {{0xff, 0xcc, 0x99}}}
, {Highlight::Call, false, {}, {{0x00, 0xff, 0xff}}}
, {Highlight::CallBand, false, {}, {{0x99, 0xff, 0xff}}}
, {Highlight::LotW, false, {{0x99, 0x00, 0x00}}, {}}
};
bool operator == (DecodeHighlightingModel::HighlightInfo const& lhs, DecodeHighlightingModel::HighlightInfo const& rhs)
{
return lhs.type_ == rhs.type_
&& lhs.enabled_ == rhs.enabled_
&& lhs.foreground_ == rhs.foreground_
&& lhs.background_ == rhs.background_;
}
QDataStream& operator << (QDataStream& os, DecodeHighlightingModel::HighlightInfo const& item)
{
return os << item.type_
<< item.enabled_
<< item.foreground_
<< item.background_;
}
QDataStream& operator >> (QDataStream& is, DecodeHighlightingModel::HighlightInfo& item)
{
return is >> item.type_
>> item.enabled_
>> item.foreground_
>> item.background_;
}
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug debug, DecodeHighlightingModel::HighlightInfo const& item)
{
QDebugStateSaver save {debug};
debug.nospace () << "HighlightInfo("
<< item.type_ << ", "
<< item.enabled_ << ", "
<< item.foreground_ << ", "
<< item.background_ << ')';
return debug;
}
#endif
ENUM_QDATASTREAM_OPS_IMPL (DecodeHighlightingModel, Highlight);
ENUM_CONVERSION_OPS_IMPL (DecodeHighlightingModel, Highlight);
DecodeHighlightingModel::DecodeHighlightingModel (QObject * parent)
: QAbstractListModel {parent}
{
}
DecodeHighlightingModel::~DecodeHighlightingModel ()
{
}
QString DecodeHighlightingModel::highlight_name (Highlight h)
{
switch (h)
{
case Highlight::CQ: return "CQ in message";
case Highlight::MyCall: return "My Call in message";
case Highlight::Tx: return "Transmitted message";
case Highlight::DXCC: return "New DXCC";
case Highlight::DXCCBand: return "New DXCC on Band";
case Highlight::Grid: return "New Grid";
case Highlight::GridBand: return "New Grid on Band";
case Highlight::Call: return "New Call";
case Highlight::CallBand: return "New Call on Band";
case Highlight::LotW: return "LotW User";
}
return "Unknown";
}
auto DecodeHighlightingModel::default_items () -> HighlightItems const&
{
return impl::defaults_;
}
auto DecodeHighlightingModel::items () const -> HighlightItems const&
{
return m_->data_;
}
void DecodeHighlightingModel::items (HighlightItems const& items)
{
m_->data_ = items;
QVector<int> roles;
roles << Qt::CheckStateRole << Qt::ForegroundRole << Qt::BackgroundRole;
Q_EMIT dataChanged (index (0, 0), index (rowCount () - 1, 0), roles);
}
void DecodeHighlightingModel::set_font (QFont const& font)
{
m_->font_ = font;
}
int DecodeHighlightingModel::rowCount (const QModelIndex& parent) const
{
return parent.isValid () ? 0 : m_->data_.size ();
}
QVariant DecodeHighlightingModel::data (const QModelIndex& index, int role) const
{
QVariant result;
if (index.isValid () && index.row () < rowCount ())
{
auto const& item = m_->data_[index.row ()];
switch (role)
{
case Qt::CheckStateRole:
result = item.enabled_ ? Qt::Checked : Qt::Unchecked;
break;
case Qt::DisplayRole:
result = highlight_name (item.type_);
break;
case Qt::ForegroundRole:
if (Qt::NoBrush != item.foreground_.style ())
{
result = item.foreground_;
}
break;
case Qt::BackgroundRole:
if (Qt::NoBrush != item.background_.style ())
{
result = item.background_;
}
break;
case Qt::FontRole:
result = m_->font_;
break;
case TypeRole:
result = static_cast<int> (item.type_);
break;
case EnabledDefaultRole:
for (auto const& default_item : impl::defaults_)
{
if (default_item.type_ == item.type_)
{
result = default_item.enabled_ ? Qt::Checked : Qt::Unchecked;
}
}
break;
case ForegroundDefaultRole:
for (auto const& default_item : impl::defaults_)
{
if (default_item.type_ == item.type_)
{
result = default_item.foreground_;
}
}
break;
case BackgroundDefaultRole:
for (auto const& default_item : impl::defaults_)
{
if (default_item.type_ == item.type_)
{
result = default_item.background_;
}
}
break;
}
}
return result;
}
// Override QAbstractItemModel::itemData() as it is used by the
// default mime encode routine used in drag'n'drop operations and we
// want to transport the type role, this is because the display role
// is derived from the type role.
QMap<int, QVariant> DecodeHighlightingModel::itemData (QModelIndex const& index) const
{
auto roles = QAbstractListModel::itemData (index);
QVariant variantData = data (index, TypeRole);
if (variantData.isValid ())
{
roles.insert (TypeRole, variantData);
}
return roles;
}
QVariant DecodeHighlightingModel::headerData (int /*section*/, Qt::Orientation orientation, int role) const
{
QVariant header;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
header = tr ("Highlight Type");
}
return header;
}
Qt::ItemFlags DecodeHighlightingModel::flags (QModelIndex const& index) const
{
auto flags = QAbstractListModel::flags (index) | Qt::ItemIsDragEnabled;
if (index.isValid ())
{
flags |= Qt::ItemIsUserCheckable;
}
else
{
flags |= Qt::ItemIsDropEnabled;
}
return flags;
}
bool DecodeHighlightingModel::setData (QModelIndex const& index, QVariant const& value, int role)
{
bool ok {false};
if (index.isValid () && index.row () < rowCount ())
{
auto& item = m_->data_[index.row ()];
QVector<int> roles;
roles << role;
switch (role)
{
case Qt::DisplayRole:
case Qt::FontRole:
ok = true;
break;
case Qt::CheckStateRole:
if (item.enabled_ != (Qt::Checked == value))
{
item.enabled_ = Qt::Checked == value;
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
case Qt::ForegroundRole:
if (item.foreground_ != value.value<QBrush> ())
{
item.foreground_ = value.value<QBrush> ();
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
case Qt::BackgroundRole:
if (item.background_ != value.value<QBrush> ())
{
item.background_ = value.value<QBrush> ();
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
case TypeRole:
if (item.type_ != static_cast<Highlight> (value.toInt ()))
{
item.type_ = static_cast<Highlight> (value.toInt ());
roles << Qt::DisplayRole;
Q_EMIT dataChanged (index, index, roles);
}
ok = true;
break;
}
}
return ok;
}
Qt::DropActions DecodeHighlightingModel::supportedDropActions () const
{
return Qt::MoveAction;
}
bool DecodeHighlightingModel::insertRows (int row, int count, QModelIndex const& parent)
{
beginInsertRows (parent, row, row + count - 1);
for (int index = 0; index < count; ++index)
{
m_->data_.insert (row, HighlightInfo {Highlight::CQ, false, {}, {}});
}
endInsertRows ();
return true;
}
bool DecodeHighlightingModel::removeRows (int row, int count, QModelIndex const& parent)
{
beginRemoveRows (parent, row, row + count - 1);
for (int index = 0; index < count; ++index)
{
m_->data_.removeAt (row);
}
endRemoveRows ();
return true;
}

View File

@ -1,77 +0,0 @@
#ifndef DECODE_HIGHLIGHTING_MODEL_HPP_
#define DECODE_HIGHLIGHTING_MODEL_HPP_
#include <QAbstractListModel>
#include <QBrush>
#include <QList>
#include "qt_helpers.hpp"
#include "pimpl_h.hpp"
class QObject;
class QFont;
class QDataStream;
class QDebug;
class DecodeHighlightingModel final
: public QAbstractListModel
{
Q_OBJECT
public:
enum class Highlight : char {CQ, MyCall, Tx, DXCC, DXCCBand, Grid, GridBand, Call, CallBand, LotW};
Q_ENUM (Highlight)
static QString highlight_name (Highlight h);
struct HighlightInfo final
{
Highlight type_;
bool enabled_;
QBrush foreground_;
QBrush background_;
};
using HighlightItems = QList<HighlightInfo>;
explicit DecodeHighlightingModel (QObject * parent = 0);
~DecodeHighlightingModel();
// access to raw items nd default items
static HighlightItems const& default_items ();
HighlightItems const& items () const;
void items (HighlightItems const&);
void set_font (QFont const&);
enum DefaultRoles {TypeRole = Qt::UserRole, EnabledDefaultRole, ForegroundDefaultRole, BackgroundDefaultRole};
private:
// implement the QAbstractListModel interface
int rowCount (QModelIndex const& parent = QModelIndex()) const override;
QVariant data (QModelIndex const&, int role) const override;
QVariant headerData (int section, Qt::Orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags (QModelIndex const&) const override;
bool setData (QModelIndex const& index, QVariant const& value, int role) override;
Qt::DropActions supportedDropActions () const override;
bool insertRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
bool removeRows (int row, int count, QModelIndex const& parent = QModelIndex {}) override;
QMap<int, QVariant> itemData (QModelIndex const&) const override;
class impl;
pimpl<impl> m_;
};
bool operator == (DecodeHighlightingModel::HighlightInfo const&, DecodeHighlightingModel::HighlightInfo const&);
QDataStream& operator << (QDataStream&, DecodeHighlightingModel::HighlightInfo const&);
QDataStream& operator >> (QDataStream&, DecodeHighlightingModel::HighlightInfo&);
#if !defined (QT_NO_DEBUG_STREAM)
QDebug operator << (QDebug, DecodeHighlightingModel::HighlightInfo const&);
#endif
ENUM_QDATASTREAM_OPS_DECL (DecodeHighlightingModel, Highlight);
ENUM_CONVERSION_OPS_DECL (DecodeHighlightingModel, Highlight);
Q_DECLARE_METATYPE (DecodeHighlightingModel::HighlightInfo);
Q_DECLARE_METATYPE (DecodeHighlightingModel::HighlightItems);
#endif

View File

@ -1,65 +0,0 @@
#include <QDebug>
#include "ExchangeValidator.hpp"
ExchangeValidator::ExchangeValidator (QObject * parent)
: QValidator {parent}
{
}
auto ExchangeValidator::validate (QString& input, int& length) const -> State
{
bool ok=false;
QStringList w=input.split(" ");
int nwords=w.size();
length=input.size();
input = input.toUpper ();
if(nwords==1 and length<=3) {
//ARRL RTTY Roundup
// ntype=4;
// ok=exch_valid_(&ntype, const_cast<char *>(input.toLatin1().constData()),length);
QStringList states;
states << "AL" << "AK" << "AZ" << "AR" << "CA" << "CO"
<< "CT" << "DE" << "FL" << "GA" << "HI" << "ID"
<< "IL" << "IN" << "IA" << "KS" << "KY" << "LA"
<< "ME" << "MD" << "MA" << "MI" << "MN" << "MS"
<< "MO" << "MT" << "NE" << "NV" << "NH" << "NJ"
<< "NM" << "NY" << "NC" << "ND" << "OH" << "OK"
<< "OR" << "PA" << "RI" << "SC" << "SD" << "TN"
<< "TX" << "UT" << "VT" << "VA" << "WA" << "WV"
<< "WI" << "WY" << "NB" << "NS" << "QC" << "ON"
<< "MB" << "SK" << "AB" << "BC" << "NWT" << "NF"
<< "LB" << "NU" << "YT" << "PEI" << "DC" << "DX";
if(states.contains(input)) ok=true;
}
if(nwords==2 and w.at(1).size()<=3) {
//ARRL Field Day
int n=w.at(0).size();
if(n>3) goto done;
int ntx=w.at(0).left(n-1).toInt();
if(ntx<1 or ntx>32) goto done;
QString c1=w.at(0).right(1);
if(c1<"A" or c1>"F") goto done;
QStringList sections;
sections << "AB" << "AK" << "AL" << "AR" << "AZ" << "BC"
<< "CO" << "CT" << "DE" << "EB" << "EMA" << "ENY"
<< "EPA" << "EWA" << "GA" << "GTA" << "IA" << "ID"
<< "IL" << "IN" << "KS" << "KY" << "LA" << "LAX"
<< "MAR" << "MB" << "MDC" << "ME" << "MI" << "MN"
<< "MO" << "MS" << "MT" << "NC" << "ND" << "NE"
<< "NFL" << "NH" << "NL" << "NLI" << "NM" << "NNJ"
<< "NNY" << "NT" << "NTX" << "NV" << "OH" << "OK"
<< "ONE" << "ONN" << "ONS" << "OR" << "ORG" << "PAC"
<< "PR" << "QC" << "RI" << "SB" << "SC" << "SCV"
<< "SD" << "SDG" << "SF" << "SFL" << "SJV" << "SK"
<< "SNJ" << "STX" << "SV" << "TN" << "UT" << "VA"
<< "VI" << "VT" << "WCF" << "WI" << "WMA" << "WNY"
<< "WPA" << "WTX" << "WV" << "WWA" << "WY" << "DX";
if(sections.contains(w.at(1))) ok=true;
}
done:
if(ok) return Acceptable;
return Intermediate;
}

View File

@ -1,19 +0,0 @@
#ifndef EXCHANGE_VALIDATOR_HPP__
#define EXCHANGE_VALIDATOR_HPP__
#include <QValidator>
// ExchangeValidator - QValidator for Field Day and RTTY Roundup exchanges
class ExchangeValidator final
: public QValidator
{
public:
ExchangeValidator (QObject * parent = nullptr);
// QValidator implementation
State validate (QString& input, int& length) const override;
};
#endif

View File

@ -1,126 +0,0 @@
#include "ExportCabrillo.h"
#include "SettingsGroup.hpp"
#include "MessageBox.hpp"
#include <QApplication>
#include <QDebug>
#include <QFileDialog>
#include "ui_ExportCabrillo.h"
#include "moc_ExportCabrillo.cpp"
ExportCabrillo::ExportCabrillo(QSettings *settings, QWidget *parent) :
QDialog(parent),
settings_ {settings},
ui(new Ui::ExportCabrillo)
{
ui->setupUi(this);
read_settings();
setWindowTitle(QApplication::applicationName() + " - Export Cabrillo");
}
ExportCabrillo::~ExportCabrillo()
{
if(isVisible()) write_settings();
delete ui;
}
void ExportCabrillo::closeEvent (QCloseEvent * e)
{
write_settings();
QWidget::closeEvent(e);
}
void ExportCabrillo::read_settings ()
{
SettingsGroup group {settings_, "ExportCabrillo"};
restoreGeometry (settings_->value("window/geometry").toByteArray());
ui->lineEdit_1->setText(settings_->value("Location").toString());
ui->lineEdit_2->setText(settings_->value("Contest").toString());
ui->lineEdit_3->setText(settings_->value("Callsign").toString());
ui->lineEdit_4->setText(settings_->value("Category-Operator").toString());
ui->lineEdit_5->setText(settings_->value("Category-Transmitter").toString());
ui->lineEdit_6->setText(settings_->value("Category-Power").toString());
ui->lineEdit_7->setText(settings_->value("Category-Assisted").toString());
ui->lineEdit_8->setText(settings_->value("Category-Band").toString());
ui->lineEdit_9->setText(settings_->value("Claimed-Score").toString());
ui->lineEdit_10->setText(settings_->value("Operators").toString());
ui->lineEdit_11->setText(settings_->value("Club").toString());
ui->lineEdit_12->setText(settings_->value("Name").toString());
ui->lineEdit_13->setText(settings_->value("Address1").toString());
ui->lineEdit_14->setText(settings_->value("Address2").toString());
}
void ExportCabrillo::write_settings ()
{
SettingsGroup group {settings_, "ExportCabrillo"};
settings_->setValue ("window/geometry", saveGeometry ());
settings_->setValue("Location",ui->lineEdit_1->text());
settings_->setValue("Contest",ui->lineEdit_2->text());
settings_->setValue("Callsign",ui->lineEdit_3->text());
settings_->setValue("Category-Operator",ui->lineEdit_4->text());
settings_->setValue("Category-Transmitter",ui->lineEdit_5->text());
settings_->setValue("Category-Power",ui->lineEdit_6->text());
settings_->setValue("Category-Assisted",ui->lineEdit_7->text());
settings_->setValue("Category-Band",ui->lineEdit_8->text());
settings_->setValue("Claimed-Score",ui->lineEdit_9->text());
settings_->setValue("Operators",ui->lineEdit_10->text());
settings_->setValue("Club",ui->lineEdit_11->text());
settings_->setValue("Name",ui->lineEdit_12->text());
settings_->setValue("Address1",ui->lineEdit_13->text());
settings_->setValue("Address2",ui->lineEdit_14->text());
}
void ExportCabrillo::setFile(QString t)
{
m_CabLog=t;
}
void ExportCabrillo::on_pbSaveAs_clicked()
{
QString fname;
QFileDialog saveAs(this);
saveAs.setFileMode(QFileDialog::AnyFile);
fname=saveAs.getSaveFileName(this, "Save File", "","Cabrillo Log (*.log)");
QFile f {fname};
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&f);
out << "START-OF-LOG:3.0" << endl
<< "LOCATION: " << ui->lineEdit_1->text() << endl
<< "CONTEST: " << ui->lineEdit_2->text() << endl
<< "CALLSIGN: " << ui->lineEdit_3->text() << endl
<< "CATEGORY-OPERATOR: " << ui->lineEdit_4->text() << endl
<< "CATEGORY-TRANSMITTER: " << ui->lineEdit_5->text() << endl
<< "CATEGORY-POWER: " << ui->lineEdit_6->text() << endl
<< "CATEGORY-ASSISTED: " << ui->lineEdit_7->text() << endl
<< "CATEGORY-BAND: " << ui->lineEdit_8->text() << endl
<< "CLAIMED-SCORE: " << ui->lineEdit_9->text() << endl
<< "OPERATORS: " << ui->lineEdit_10->text() << endl
<< "CLUB: " << ui->lineEdit_11->text() << endl
<< "NAME: " << ui->lineEdit_12->text() << endl
<< "ADDRESS: " << ui->lineEdit_13->text() << endl
<< "ADDRESS: " << ui->lineEdit_14->text() << endl;
QFile f2(m_CabLog);
if(f2.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream s(&f2);
QString t=s.readAll();
out << t << "END-OF-LOG:" << endl;
f2.close();
}
f.close();
} else {
auto const& message = tr ("Cannot open \"%1\" for writing: %2")
.arg (f.fileName ()).arg (f.errorString ());
MessageBox::warning_message (this, tr ("Export Cabrillo File Error"), message);
}
write_settings();
}
void ExportCabrillo::accept()
{
write_settings();
QDialog::accept();
}

View File

@ -1,37 +0,0 @@
#ifndef EXPORTCABRILLO_H
#define EXPORTCABRILLO_H
#include <QDialog>
#include <QSettings>
namespace Ui {
class ExportCabrillo;
}
class ExportCabrillo : public QDialog
{
Q_OBJECT
public:
explicit ExportCabrillo(QSettings *settings, QWidget *parent = 0);
void setFile(QString t);
~ExportCabrillo();
public slots:
void accept();
protected:
void closeEvent (QCloseEvent *) override;
private slots:
void on_pbSaveAs_clicked();
private:
QSettings * settings_;
QString m_CabLog;
void read_settings();
void write_settings();
Ui::ExportCabrillo *ui;
};
#endif // EXPORTCABRILLO_H

View File

@ -1,304 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportCabrillo</class>
<widget class="QDialog" name="ExportCabrillo">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>330</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Location:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_1">
<property name="text">
<string>SNJ</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Contest:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEdit_2">
<property name="text">
<string>ARRL-RTTY</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Callsign:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_3">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Category-Operator: </string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_4">
<property name="text">
<string>SINGLE-OP</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Category-Transmitter:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_5">
<property name="text">
<string>ONE</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Category-Power:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEdit_6">
<property name="text">
<string>LOW</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Category-Assisted:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="lineEdit_7">
<property name="text">
<string>NON-ASSISTED</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Category-Band:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="lineEdit_8">
<property name="text">
<string>ALL</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Claimed-Score:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="lineEdit_9">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Operators:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLineEdit" name="lineEdit_10">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Club:</string>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLineEdit" name="lineEdit_11">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLineEdit" name="lineEdit_12">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLineEdit" name="lineEdit_13">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLineEdit" name="lineEdit_14">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pbSaveAs">
<property name="text">
<string>Save As</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ExportCabrillo</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ExportCabrillo</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,41 +0,0 @@
#include "ForeignKeyDelegate.hpp"
#include <QComboBox>
#include "CandidateKeyFilter.hpp"
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel * referenced_model
, int referenced_key_column
, QObject * parent
, int referenced_key_role)
: QStyledItemDelegate {parent}
, candidate_key_filter_ {new CandidateKeyFilter {referenced_model, referenced_key_column, nullptr, referenced_key_role}}
{
}
ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent
, int referenced_key_role
, int referencing_key_role)
: QStyledItemDelegate {parent}
, candidate_key_filter_ {new CandidateKeyFilter {referenced_model, referencing_model, referenced_key_column, referencing_key_column, nullptr, referenced_key_role, referencing_key_role}}
{
}
ForeignKeyDelegate::~ForeignKeyDelegate ()
{
}
QWidget * ForeignKeyDelegate::createEditor (QWidget * parent
, QStyleOptionViewItem const& /* option */
, QModelIndex const& index) const
{
auto editor = new QComboBox {parent};
editor->setFrame (false);
candidate_key_filter_->set_active_key (index);
editor->setModel (candidate_key_filter_.data ());
return editor;
}

View File

@ -1,42 +0,0 @@
#ifndef FOREIGN_KEY_DELEGATE_HPP_
#define FOREIGN_KEY_DELEGATE_HPP_
#include <QStyledItemDelegate>
#include <QScopedPointer>
class CandidateKeyFilter;
//
// Class ForeignKeyDelegate
//
// Item delegate for editing a foreign key item in a one or many
// to one relationship. A QComboBox is used as an item delegate
// for the edit role.
//
class ForeignKeyDelegate final
: public QStyledItemDelegate
{
public:
// many to many relationship
explicit ForeignKeyDelegate (QAbstractItemModel * referenced_model
, int referenced_key_column
, QObject * parent = nullptr
, int referenced_key_role = Qt::EditRole);
// one to many (referenced to referencing) relationship
explicit ForeignKeyDelegate (QAbstractItemModel * referenced_model
, QAbstractItemModel const * referencing_model
, int referenced_key_column
, int referencing_key_column
, QObject * parent = nullptr
, int referenced_key_role = Qt::EditRole
, int referencing_key_role = Qt::EditRole);
~ForeignKeyDelegate ();
QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override;
private:
QScopedPointer<CandidateKeyFilter> candidate_key_filter_;
};
#endif

View File

@ -1,45 +0,0 @@
#ifndef FREQUENCY_LINE_EDIT_HPP_
#define FREQUENCY_LINE_EDIT_HPP_
#include <QLineEdit>
#include "Radio.hpp"
class QWidget;
//
// MHz frequency line edits with validation
//
class FrequencyLineEdit final
: public QLineEdit
{
Q_OBJECT;
Q_PROPERTY (Frequency frequency READ frequency WRITE frequency USER true);
public:
using Frequency = Radio::Frequency;
explicit FrequencyLineEdit (QWidget * parent = nullptr);
// Property frequency implementation
Frequency frequency () const;
void frequency (Frequency);
};
class FrequencyDeltaLineEdit final
: public QLineEdit
{
Q_OBJECT;
Q_PROPERTY (FrequencyDelta frequency_delta READ frequency_delta WRITE frequency_delta USER true);
public:
using FrequencyDelta = Radio::FrequencyDelta;
explicit FrequencyDeltaLineEdit (QWidget * parent = nullptr);
// Property frequency_delta implementation
FrequencyDelta frequency_delta () const;
void frequency_delta (FrequencyDelta);
};
#endif

View File

@ -1,29 +0,0 @@
#include "HelpTextWindow.hpp"
#include <QApplication>
#include <QString>
#include <QPalette>
#include <QFile>
#include <QTextStream>
#include "qt_helpers.hpp"
#include <MessageBox.hpp>
HelpTextWindow::HelpTextWindow (QString const& title, QString const& file_name, QFont const& font, QWidget * parent)
: QLabel {parent, Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint}
{
QFile source {file_name};
if (!source.open (QIODevice::ReadOnly | QIODevice::Text))
{
MessageBox::warning_message (this, tr ("Help file error")
, tr ("Cannot open \"%1\" for reading").arg (source.fileName ())
, tr ("Error: %1").arg (source.errorString ()));
return;
}
setText (QTextStream {&source}.readAll ());
setWindowTitle(QApplication::applicationName () + " - " + title);
setMargin (10);
setBackgroundRole (QPalette::Base);
setAutoFillBackground (true);
setStyleSheet (font_as_stylesheet (font));
}

View File

@ -1,96 +0,0 @@
#include "IARURegions.hpp"
#include <algorithm>
#include <QString>
#include <QVariant>
#include <QModelIndex>
#include <QMetaType>
#include "moc_IARURegions.cpp"
namespace
{
// human readable strings for each Region enumeration value
char const * const region_names[] =
{
"All",
"Region 1",
"Region 2",
"Region 3",
};
std::size_t constexpr region_names_size = sizeof (region_names) / sizeof (region_names[0]);
}
IARURegions::IARURegions (QObject * parent)
: QAbstractListModel {parent}
{
static_assert (region_names_size == SENTINAL,
"region_names array must match Region enumeration");
}
char const * IARURegions::name (Region r)
{
return region_names[static_cast<int> (r)];
}
auto IARURegions::value (QString const& s) -> Region
{
auto end = region_names + region_names_size;
auto p = std::find_if (region_names, end
, [&s] (char const * const name) {
return name == s;
});
return p != end ? static_cast<Region> (p - region_names) : ALL;
}
QVariant IARURegions::data (QModelIndex const& index, int role) const
{
QVariant item;
if (index.isValid ())
{
auto const& row = index.row ();
switch (role)
{
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("IARU Region");
break;
case Qt::EditRole:
item = static_cast<Region> (row);
break;
case Qt::DisplayRole:
case Qt::AccessibleTextRole:
item = region_names[row];
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
}
return item;
}
QVariant IARURegions::headerData (int section, Qt::Orientation orientation, int role) const
{
QVariant result;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
result = tr ("IARU Region");
}
else
{
result = QAbstractListModel::headerData (section, orientation, role);
}
return result;
}
ENUM_QDATASTREAM_OPS_IMPL (IARURegions, Region);
ENUM_CONVERSION_OPS_IMPL (IARURegions, Region);

View File

@ -1,99 +0,0 @@
#include "LiveFrequencyValidator.hpp"
#include <QLocale>
#include <QString>
#include <QComboBox>
#include <QLineEdit>
#include "Bands.hpp"
#include "FrequencyList.hpp"
#include "moc_LiveFrequencyValidator.cpp"
LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box
, Bands const * bands
, FrequencyList_v2 const * frequencies
, Frequency const * nominal_frequency
, QWidget * parent)
: QRegExpValidator {
QRegExp { // frequency in MHz or band
bands->data (QModelIndex {}).toString () // out of band string
+ QString {R"(|((\d{0,6}(\)"} // or up to 6 digits
+ QLocale {}.decimalPoint () // (followed by decimal separator
+ R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,6}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive))
+ QLocale {}.decimalPoint () // or a decimal separator
+ R"(\d{0,6})?)|(\d{0,3}(\)" // followed by up to 6
// digits or a decimal number
+ QLocale {}.decimalPoint () // or a decimal separator
+ R"(\d{0,6})?[Kk]))" // followed by a 'k' or 'K'
}
, parent
}
, bands_ {bands}
, frequencies_ {frequencies}
, nominal_frequency_ {nominal_frequency}
, combo_box_ {combo_box}
{
}
auto LiveFrequencyValidator::validate (QString& input, int& pos) const -> State
{
auto state = QRegExpValidator::validate (input, pos);
// by never being Acceptable we force fixup calls on ENTER or
// losing focus
return Acceptable == state ? Intermediate : state;
}
void LiveFrequencyValidator::fixup (QString& input) const
{
QRegExpValidator::fixup (input);
if (!bands_->oob ().startsWith (input))
{
if (input.contains ('m', Qt::CaseInsensitive))
{
input = input.toLower ();
QVector<QVariant> frequencies;
for (auto const& item : frequencies_->frequency_list ())
{
if (bands_->find (item.frequency_) == input)
{
frequencies << item.frequency_;
}
}
if (!frequencies.isEmpty ())
{
Q_EMIT valid (frequencies.first ().value<Frequency> ());
}
else
{
input = QString {};
}
}
else if (input.contains (QChar {'k'}, Qt::CaseInsensitive))
{
// kHz in current MHz input
auto f = Radio::frequency (input.remove (QChar {'k'}, Qt::CaseInsensitive), 3);
f += *nominal_frequency_ / 1000000u * 1000000u;
input = bands_->find (f);
Q_EMIT valid (f);
}
else
{
// frequency input
auto f = Radio::frequency (input, 6);
input = bands_->find (f);
Q_EMIT valid (f);
}
if (bands_->oob () == input)
{
combo_box_->lineEdit ()->setStyleSheet ("QLineEdit {color: yellow; background-color : red;}");
}
else
{
combo_box_->lineEdit ()->setStyleSheet ({});
}
combo_box_->setCurrentText (input);
}
}

View File

@ -48,6 +48,10 @@ public:
if (!QFileInfo::exists (csv_file_name) || forced_fetch)
{
current_url_.setUrl (url);
if (current_url_.isValid () && !QSslSocket::supportsSsl ())
{
current_url_.setScheme ("http");
}
redirect_count_ = 0;
download (current_url_);
}
@ -66,10 +70,6 @@ public:
network_manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
}
if (url.isValid () && !QSslSocket::supportsSsl ())
{
url.setScheme ("http");
}
QNetworkRequest request {url};
request.setRawHeader ("User-Agent", "WSJT LotW User Downloader");
request.setOriginatingObject (this);
@ -99,7 +99,14 @@ public:
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
{
if (++redirect_count_ < 10) // maintain sanity
if ("https" == redirect_url.scheme () && !QSslSocket::supportsSsl ())
{
Q_EMIT self_->LotW_users_error (tr ("Network Error - SSL/TLS support not installed, cannot fetch:\n\'%1\'")
.arg (redirect_url.toDisplayString ()));
url_valid_ = false; // reset
Q_EMIT self_->load_finished ();
}
else if (++redirect_count_ < 10) // maintain sanity
{
// follow redirect
download (reply_->url ().resolved (redirect_url));

View File

@ -378,13 +378,14 @@ void MessageClient::set_server_port (port_type server_port)
m_->server_port_ = server_port;
}
void MessageClient::send_raw_datagram (QByteArray const& message, QHostAddress const& dest_address
qint64 MessageClient::send_raw_datagram (QByteArray const& message, QHostAddress const& dest_address
, port_type dest_port)
{
if (dest_port && !dest_address.isNull ())
{
m_->writeDatagram (message, dest_address, dest_port);
return m_->writeDatagram (message, dest_address, dest_port);
}
return 0;
}
void MessageClient::add_blocked_destination (QHostAddress const& a)

View File

@ -70,10 +70,10 @@ public:
// of record marker
Q_SLOT void logged_ADIF (QByteArray const& ADIF_record);
// this slot may be used to send arbitrary UDP datagrams to and
// this may be used to send arbitrary UDP datagrams to and
// destination allowing the underlying socket to be used for general
// UDP messaging if desired
Q_SLOT void send_raw_datagram (QByteArray const&, QHostAddress const& dest_address, port_type dest_port);
qint64 send_raw_datagram (QByteArray const&, QHostAddress const& dest_address, port_type dest_port);
// disallowed message destination (does not block datagrams sent
// with send_raw_datagram() above)

View File

@ -5,16 +5,16 @@
#include <QStandardItemEditorCreator>
#include "Radio.hpp"
#include "FrequencyList.hpp"
#include "models/FrequencyList.hpp"
#include "AudioDevice.hpp"
#include "Configuration.hpp"
#include "StationList.hpp"
#include "models/StationList.hpp"
#include "Transceiver.hpp"
#include "TransceiverFactory.hpp"
#include "WFPalette.hpp"
#include "IARURegions.hpp"
#include "DecodeHighlightingModel.hpp"
#include "FrequencyLineEdit.hpp"
#include "models/IARURegions.hpp"
#include "models/DecodeHighlightingModel.hpp"
#include "widgets/FrequencyLineEdit.hpp"
QItemEditorFactory * item_editor_factory ()
{

View File

@ -3,7 +3,7 @@
#include <qmath.h>
#include <QDateTime>
#include <QDebug>
#include "mainwindow.h"
#include "widgets/mainwindow.h" // TODO: G4WJS - break this dependency
#include "soundout.h"
#include "commons.h"

View File

@ -30,7 +30,7 @@
#include "SettingsGroup.hpp"
#include "qt_helpers.hpp"
#include "SettingsGroup.hpp"
#include "MessageBox.hpp"
#include "widgets/MessageBox.hpp"
#include "pimpl_impl.hpp"

View File

@ -7,7 +7,7 @@
#include <QNetworkReply>
#include <QString>
#include "MessageBox.hpp"
#include "widgets/MessageBox.hpp"
class QNetworkRequest;
class QIODevice;

View File

@ -231,7 +231,7 @@
* DX grid utf8
* Tx frequency (Hz) quint64
* Mode utf8
* Report send utf8
* Report sent utf8
* Report received utf8
* Tx power utf8
* Comments utf8

View File

@ -12,11 +12,37 @@
Copyright 2001 - 2018 by Joe Taylor, K1JT.
Release: WSJT-X 2.0-rc4
November 12, 2018
-----------------------
Changes from WSJT-X Version 2.0.0-rc3 include the following:
- Fix the "cannot open file fort.81" bug
- Avoid too many redirect loops related to openSSL support
- Fix the auto-generated messages for nonstandard callsigns
- Remove all support for the legacy FT8 protocol
- Disallow selecting MSK144 with RTTY or Field Day messages active
- Correct and expand support for color highlighting decoded messages
- ESC key aborts a QSO, clears DX Call, and selects Tx6
- Disable "nextCall" procedure for RTTY contest; it still needs work
- Correct a flaw in handling MSK144 Sh messages
- Prevent Fox from inadvertently toggling Tx 1st/Even
- Re-organize the Fox/Hound/Contest selection boxes
- Improve the validators for contest exchange boxes
- Disable Tx after 5 minutes of no mouse movement
- Remove end-of-line AP info when using contest messages
- Fix forwarding of Sent and Rcvd exchanges to N1MM+ and ADIF log
- Don't auto-log a QSO with incomplete exchange info
- Fix two sequencing flaws after double-clicks on a decoded msg
- New facilities for Contest and Fox-mode logging
Release: WSJT-X 2.0-rc3
October 15, 2018
-----------------------
Changes from WSJT-X Version 2.0.0-rc1 include the following:
Changes from WSJT-X Version 2.0.0-rc2 include the following:
- Improved SNR calculation for FT8
- Test grid4 (not grid6) for matches in ADIF log

View File

@ -7,7 +7,7 @@
#include "pimpl_impl.hpp"
#include "SettingsGroup.hpp"
#include "SampleDownloader/Directory.hpp"
#include "MessageBox.hpp"
#include "widgets/MessageBox.hpp"
#include "moc_SampleDownloader.cpp"

View File

@ -21,7 +21,7 @@
#include "DirectoryNode.hpp"
#include "FileNode.hpp"
#include "revision_utils.hpp"
#include "MessageBox.hpp"
#include "widgets/MessageBox.hpp"
#include "moc_Directory.cpp"

View File

@ -6,7 +6,7 @@
#include <QFileInfo>
#include "Directory.hpp"
#include "MessageBox.hpp"
#include "widgets/MessageBox.hpp"
FileNode::FileNode (QTreeWidgetItem * parent
, QNetworkAccessManager * network_manager

View File

@ -1,48 +0,0 @@
#include "SplashScreen.hpp"
#include <QPixmap>
#include <QVBoxLayout>
#include <QCheckBox>
#include <QCoreApplication>
#include "revision_utils.hpp"
#include "pimpl_impl.hpp"
#include "moc_SplashScreen.cpp"
class SplashScreen::impl
{
public:
impl ()
: checkbox_ {"Do not show this again"}
{
main_layout_.addStretch ();
main_layout_.addWidget (&checkbox_, 0, Qt::AlignRight);
}
QVBoxLayout main_layout_;
QCheckBox checkbox_;
};
SplashScreen::SplashScreen ()
: QSplashScreen {QPixmap {":/splash.png"}, Qt::WindowStaysOnTopHint}
{
setLayout (&m_->main_layout_);
showMessage ("<h2>" + QString {"WSJT-X v" +
QCoreApplication::applicationVersion() + " " +
revision ()}.simplified () + "</h2>"
"V1.8 has many new features.<br /><br />"
"The release notes have more details.<br /><br />"
"Send issue reports to wsjtgroup@yahoogroups.com, and be sure to save .wav<br />"
"files where appropriate.<br /><br />"
"<b>Open the Help menu and select Release Notes for more details.</b><br />"
"<img src=\":/icon_128x128.png\" />"
"<img src=\":/gpl-v3-logo.svg\" height=\"80\" />", Qt::AlignCenter);
connect (&m_->checkbox_, &QCheckBox::stateChanged, [this] (int s) {
if (Qt::Checked == s) Q_EMIT disabled ();
});
}
SplashScreen::~SplashScreen ()
{
}

View File

@ -3,7 +3,7 @@
#include <QRegExp>
#include <QColor>
#include "MaidenheadLocatorValidator.hpp"
#include "validators/MaidenheadLocatorValidator.hpp"
namespace
{

View File

@ -2,5 +2,5 @@
set (WSJTX_VERSION_MAJOR 2)
set (WSJTX_VERSION_MINOR 0)
set (WSJTX_VERSION_PATCH 0)
set (WSJTX_RC 3) # release candidate number, comment out or zero for development versions
set (WSJTX_RC 4) # release candidate number, comment out or zero for development versions
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build

View File

@ -11,8 +11,8 @@
#include "SettingsGroup.hpp"
#include "Configuration.hpp"
#include "Bands.hpp"
#include "FrequencyList.hpp"
#include "models/Bands.hpp"
#include "models/FrequencyList.hpp"
#include "WsprTxScheduler.h"
#include "pimpl_impl.hpp"
#include "moc_WSPRBandHopping.cpp"

100
about.ui
View File

@ -1,100 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CAboutDlg</class>
<widget class="QDialog" name="CAboutDlg">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="windowTitle">
<string>About WSJT-X</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="labelTxt">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<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>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>okButton</sender>
<signal>clicked()</signal>
<receiver>CAboutDlg</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>321</x>
<y>120</y>
</hint>
<hint type="destinationlabel">
<x>186</x>
<y>71</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

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