summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/log
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/log')
-rw-r--r--src/boost/libs/log/README.md32
-rw-r--r--src/boost/libs/log/build/Jamfile.v2534
-rw-r--r--src/boost/libs/log/build/log-architecture.jam112
-rw-r--r--src/boost/libs/log/build/log-platform-config.jam59
-rw-r--r--src/boost/libs/log/config/atomic-int32/Jamfile.jam19
-rw-r--r--src/boost/libs/log/config/atomic-int32/atomic_int32.cpp17
-rw-r--r--src/boost/libs/log/config/message-compiler/Jamfile.jam22
-rw-r--r--src/boost/libs/log/config/native-syslog/Jamfile.jam19
-rw-r--r--src/boost/libs/log/config/native-syslog/native_syslog.cpp26
-rw-r--r--src/boost/libs/log/config/pthread-mutex-robust/Jamfile.jam19
-rw-r--r--src/boost/libs/log/config/pthread-mutex-robust/pthread_mutex_robust.cpp37
-rw-r--r--src/boost/libs/log/config/x86-ext/Jamfile.jam34
-rw-r--r--src/boost/libs/log/config/x86-ext/avx2.cpp20
-rw-r--r--src/boost/libs/log/config/x86-ext/ssse3.cpp19
-rw-r--r--src/boost/libs/log/config/xopen-source-600/Jamfile.jam16
-rw-r--r--src/boost/libs/log/config/xopen-source-600/xopen_source_600.cpp17
-rw-r--r--src/boost/libs/log/example/Jamfile.v223
-rw-r--r--src/boost/libs/log/example/advanced_usage/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/advanced_usage/main.cpp300
-rw-r--r--src/boost/libs/log/example/async_log/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/async_log/main.cpp129
-rw-r--r--src/boost/libs/log/example/basic_usage/Jamfile.v258
-rw-r--r--src/boost/libs/log/example/basic_usage/main.cpp129
-rw-r--r--src/boost/libs/log/example/bounded_async_log/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/bounded_async_log/main.cpp131
-rw-r--r--src/boost/libs/log/example/event_log/Jamfile.v2102
-rw-r--r--src/boost/libs/log/example/event_log/event_log_messages.mc58
-rw-r--r--src/boost/libs/log/example/event_log/main.cpp190
-rw-r--r--src/boost/libs/log/example/keywords/Jamfile.v258
-rw-r--r--src/boost/libs/log/example/keywords/main.cpp133
-rw-r--r--src/boost/libs/log/example/multiple_files/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/multiple_files/main.cpp105
-rw-r--r--src/boost/libs/log/example/multiple_threads/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/multiple_threads/main.cpp115
-rw-r--r--src/boost/libs/log/example/native_syslog/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/native_syslog/main.cpp109
-rw-r--r--src/boost/libs/log/example/rotating_file/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/rotating_file/main.cpp96
-rw-r--r--src/boost/libs/log/example/settings_file/Jamfile.v258
-rw-r--r--src/boost/libs/log/example/settings_file/main.cpp74
-rw-r--r--src/boost/libs/log/example/settings_file/settings.txt25
-rw-r--r--src/boost/libs/log/example/settings_file_custom_factories/Jamfile.v258
-rw-r--r--src/boost/libs/log/example/settings_file_custom_factories/main.cpp205
-rw-r--r--src/boost/libs/log/example/settings_file_custom_factories/settings.txt14
-rw-r--r--src/boost/libs/log/example/syslog/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/syslog/main.cpp100
-rw-r--r--src/boost/libs/log/example/trivial/Jamfile.v257
-rw-r--r--src/boost/libs/log/example/trivial/main.cpp49
-rw-r--r--src/boost/libs/log/example/wide_char/Jamfile.v262
-rw-r--r--src/boost/libs/log/example/wide_char/main.cpp121
-rw-r--r--src/boost/libs/log/index.html13
-rw-r--r--src/boost/libs/log/meta/libraries.json14
-rw-r--r--src/boost/libs/log/src/alignment_gap_between.hpp50
-rw-r--r--src/boost/libs/log/src/attribute_name.cpp228
-rw-r--r--src/boost/libs/log/src/attribute_set.cpp148
-rw-r--r--src/boost/libs/log/src/attribute_set_impl.hpp394
-rw-r--r--src/boost/libs/log/src/attribute_value_set.cpp570
-rw-r--r--src/boost/libs/log/src/bit_tools.hpp51
-rw-r--r--src/boost/libs/log/src/code_conversion.cpp299
-rw-r--r--src/boost/libs/log/src/core.cpp806
-rw-r--r--src/boost/libs/log/src/date_time_format_parser.cpp423
-rw-r--r--src/boost/libs/log/src/default_attribute_names.cpp122
-rw-r--r--src/boost/libs/log/src/default_sink.cpp229
-rw-r--r--src/boost/libs/log/src/default_sink.hpp75
-rw-r--r--src/boost/libs/log/src/dump.cpp275
-rw-r--r--src/boost/libs/log/src/dump_avx2.cpp349
-rw-r--r--src/boost/libs/log/src/dump_ssse3.cpp311
-rw-r--r--src/boost/libs/log/src/event.cpp277
-rw-r--r--src/boost/libs/log/src/exceptions.cpp646
-rw-r--r--src/boost/libs/log/src/format_parser.cpp154
-rw-r--r--src/boost/libs/log/src/global_logger_storage.cpp110
-rw-r--r--src/boost/libs/log/src/id_formatting.hpp61
-rw-r--r--src/boost/libs/log/src/murmur3.hpp84
-rw-r--r--src/boost/libs/log/src/named_scope.cpp314
-rw-r--r--src/boost/libs/log/src/named_scope_format_parser.cpp749
-rw-r--r--src/boost/libs/log/src/once_block.cpp471
-rw-r--r--src/boost/libs/log/src/permissions.cpp94
-rw-r--r--src/boost/libs/log/src/posix/ipc_reliable_message_queue.cpp881
-rw-r--r--src/boost/libs/log/src/posix/ipc_sync_wrappers.hpp267
-rw-r--r--src/boost/libs/log/src/posix/object_name.cpp170
-rw-r--r--src/boost/libs/log/src/process_id.cpp123
-rw-r--r--src/boost/libs/log/src/process_name.cpp187
-rw-r--r--src/boost/libs/log/src/record_ostream.cpp183
-rw-r--r--src/boost/libs/log/src/setup/default_filter_factory.cpp356
-rw-r--r--src/boost/libs/log/src/setup/default_filter_factory.hpp106
-rw-r--r--src/boost/libs/log/src/setup/default_formatter_factory.cpp289
-rw-r--r--src/boost/libs/log/src/setup/default_formatter_factory.hpp59
-rw-r--r--src/boost/libs/log/src/setup/filter_parser.cpp531
-rw-r--r--src/boost/libs/log/src/setup/formatter_parser.cpp485
-rw-r--r--src/boost/libs/log/src/setup/init_from_settings.cpp887
-rw-r--r--src/boost/libs/log/src/setup/init_from_stream.cpp47
-rw-r--r--src/boost/libs/log/src/setup/matches_relation_factory.cpp274
-rw-r--r--src/boost/libs/log/src/setup/parser_utils.cpp431
-rw-r--r--src/boost/libs/log/src/setup/parser_utils.hpp323
-rw-r--r--src/boost/libs/log/src/setup/settings_parser.cpp260
-rw-r--r--src/boost/libs/log/src/severity_level.cpp92
-rw-r--r--src/boost/libs/log/src/spirit_encoding.cpp48
-rw-r--r--src/boost/libs/log/src/spirit_encoding.hpp104
-rw-r--r--src/boost/libs/log/src/stateless_allocator.hpp95
-rw-r--r--src/boost/libs/log/src/syslog_backend.cpp620
-rw-r--r--src/boost/libs/log/src/text_file_backend.cpp1569
-rw-r--r--src/boost/libs/log/src/text_multifile_backend.cpp114
-rw-r--r--src/boost/libs/log/src/text_ostream_backend.cpp164
-rw-r--r--src/boost/libs/log/src/thread_id.cpp272
-rw-r--r--src/boost/libs/log/src/thread_specific.cpp292
-rw-r--r--src/boost/libs/log/src/threadsafe_queue.cpp160
-rw-r--r--src/boost/libs/log/src/timer.cpp159
-rw-r--r--src/boost/libs/log/src/timestamp.cpp279
-rw-r--r--src/boost/libs/log/src/trivial.cpp155
-rw-r--r--src/boost/libs/log/src/unique_ptr.hpp59
-rw-r--r--src/boost/libs/log/src/windows/auto_handle.hpp79
-rw-r--r--src/boost/libs/log/src/windows/debug_output_backend.cpp79
-rw-r--r--src/boost/libs/log/src/windows/event_log_backend.cpp636
-rw-r--r--src/boost/libs/log/src/windows/event_log_registry.hpp491
-rw-r--r--src/boost/libs/log/src/windows/ipc_reliable_message_queue.cpp818
-rw-r--r--src/boost/libs/log/src/windows/ipc_sync_wrappers.cpp544
-rw-r--r--src/boost/libs/log/src/windows/ipc_sync_wrappers.hpp544
-rw-r--r--src/boost/libs/log/src/windows/light_rw_mutex.cpp200
-rw-r--r--src/boost/libs/log/src/windows/mapped_shared_memory.cpp251
-rw-r--r--src/boost/libs/log/src/windows/mapped_shared_memory.hpp102
-rw-r--r--src/boost/libs/log/src/windows/object_name.cpp227
-rw-r--r--src/boost/libs/log/src/windows/simple_event_log.mc58
-rw-r--r--src/boost/libs/log/src/windows/utf_code_conversion.hpp42
-rw-r--r--src/boost/libs/log/test/Jamfile.v2123
-rw-r--r--src/boost/libs/log/test/common/attr_comparison.hpp60
-rw-r--r--src/boost/libs/log/test/common/char_definitions.hpp116
-rw-r--r--src/boost/libs/log/test/common/make_record.hpp32
-rw-r--r--src/boost/libs/log/test/common/test_sink.hpp92
-rw-r--r--src/boost/libs/log/test/compile/current_function_support.cpp37
-rw-r--r--src/boost/libs/log/test/compile/self_contained_header.cpp22
-rw-r--r--src/boost/libs/log/test/compile/src_logger_assignable.cpp39
-rw-r--r--src/boost/libs/log/test/compile/src_logger_get_attributes.cpp44
-rw-r--r--src/boost/libs/log/test/compile/util_unique_identifier.cpp34
-rw-r--r--src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp42
-rw-r--r--src/boost/libs/log/test/performance/Jamfile.v215
-rw-r--r--src/boost/libs/log/test/performance/dump.cpp76
-rw-r--r--src/boost/libs/log/test/performance/record_emission.cpp132
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_set.cpp280
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp51
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_value_impl.cpp153
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_value_set.cpp244
-rw-r--r--src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp60
-rw-r--r--src/boost/libs/log/test/run/attr_function.cpp138
-rw-r--r--src/boost/libs/log/test/run/attr_named_scope.cpp190
-rw-r--r--src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp101
-rw-r--r--src/boost/libs/log/test/run/attr_value_visitation.cpp238
-rw-r--r--src/boost/libs/log/test/run/core.cpp243
-rw-r--r--src/boost/libs/log/test/run/filt_attr.cpp403
-rw-r--r--src/boost/libs/log/test/run/filt_has_attr.cpp102
-rw-r--r--src/boost/libs/log/test/run/filt_matches_boost_regex.cpp107
-rw-r--r--src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp115
-rw-r--r--src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp114
-rw-r--r--src/boost/libs/log/test/run/filt_matches_std_regex.cpp120
-rw-r--r--src/boost/libs/log/test/run/filt_matches_xpressive.cpp107
-rw-r--r--src/boost/libs/log/test/run/form_attr.cpp123
-rw-r--r--src/boost/libs/log/test/run/form_auto_newline.cpp94
-rw-r--r--src/boost/libs/log/test/run/form_c_decor.cpp126
-rw-r--r--src/boost/libs/log/test/run/form_char_decor.cpp174
-rw-r--r--src/boost/libs/log/test/run/form_csv_decor.cpp84
-rw-r--r--src/boost/libs/log/test/run/form_date_time.cpp212
-rw-r--r--src/boost/libs/log/test/run/form_format.cpp83
-rw-r--r--src/boost/libs/log/test/run/form_if.cpp107
-rw-r--r--src/boost/libs/log/test/run/form_max_size_decor.cpp177
-rw-r--r--src/boost/libs/log/test/run/form_message.cpp84
-rw-r--r--src/boost/libs/log/test/run/form_named_scope.cpp537
-rw-r--r--src/boost/libs/log/test/run/form_to_log_manip.cpp98
-rw-r--r--src/boost/libs/log/test/run/form_xml_decor.cpp84
-rw-r--r--src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp67
-rw-r--r--src/boost/libs/log/test/run/src_record_ostream.cpp479
-rw-r--r--src/boost/libs/log/test/run/util_dynamic_type_disp.cpp138
-rw-r--r--src/boost/libs/log/test/run/util_exception_handler.cpp361
-rw-r--r--src/boost/libs/log/test/run/util_formatting_ostream.cpp503
-rw-r--r--src/boost/libs/log/test/run/util_ipc_object_name.cpp177
-rw-r--r--src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp474
-rw-r--r--src/boost/libs/log/test/run/util_manip_add_value.cpp139
-rw-r--r--src/boost/libs/log/test/run/util_manip_auto_newline.cpp83
-rw-r--r--src/boost/libs/log/test/run/util_manip_dump.cpp239
-rw-r--r--src/boost/libs/log/test/run/util_manip_to_log.cpp134
-rw-r--r--src/boost/libs/log/test/run/util_once_block.cpp293
-rw-r--r--src/boost/libs/log/test/run/util_static_type_disp.cpp147
-rw-r--r--src/boost/libs/log/test/run/util_stp_filter_parser.cpp808
-rw-r--r--src/boost/libs/log/test/run/util_stp_formatter_parser.cpp257
-rw-r--r--src/boost/libs/log/test/run/util_stp_settings_parser.cpp294
-rw-r--r--src/boost/libs/log/test/run/util_string_literal.cpp221
184 files changed, 35873 insertions, 0 deletions
diff --git a/src/boost/libs/log/README.md b/src/boost/libs/log/README.md
new file mode 100644
index 000000000..b8827baf6
--- /dev/null
+++ b/src/boost/libs/log/README.md
@@ -0,0 +1,32 @@
+# ![Boost.Log](doc/logo.png)
+
+Boost.Log, part of collection of the [Boost C++ Libraries](https://github.com/boostorg), provides tools for adding logging to libraries and applications.
+
+### Directories
+
+* **build** - Boost.Log build scripts
+* **config** - Boost.Log build configuration code and scripts
+* **doc** - QuickBook documentation sources
+* **example** - Boost.Log examples
+* **include** - Interface headers of Boost.Log
+* **src** - Compilable source code of Boost.Log
+* **test** - Boost.Log unit tests
+
+### More information
+
+* [Documentation](https://www.boost.org/libs/log)
+* [Ask questions](https://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-log)
+* [Report bugs](https://github.com/boostorg/log/issues/new). Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
+* Submit your patches as [pull requests](https://github.com/boostorg/log/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+* Discussions about the library are held on the [Boost developers mailing list](https://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](https://www.boost.org/community/policy.html) before posting and add the `[log]` tag at the beginning of the subject line.
+
+### Build status
+
+Branch | Travis CI | AppVeyor | Test Matrix | Dependencies |
+:-------------: | --------- | -------- | ----------- | ------------ |
+[`master`](https://github.com/boostorg/log/tree/master) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=master)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html)
+[`develop`](https://github.com/boostorg/log/tree/develop) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=develop)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html)
+
+### License
+
+Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
diff --git a/src/boost/libs/log/build/Jamfile.v2 b/src/boost/libs/log/build/Jamfile.v2
new file mode 100644
index 000000000..a172767ab
--- /dev/null
+++ b/src/boost/libs/log/build/Jamfile.v2
@@ -0,0 +1,534 @@
+#
+# Copyright Andrey Semashev 2007 - 2016.
+# 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)
+#
+
+import common ;
+import modules ;
+import os ;
+import path ;
+import project ;
+import feature ;
+import configure ;
+import log-architecture ;
+import log-platform-config ;
+using mc ;
+
+local here = [ modules.binding $(__name__) ] ;
+
+project.push-current [ project.current ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config/message-compiler ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config/x86-ext ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config/pthread-mutex-robust ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config/native-syslog ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config/atomic-int32 ] ;
+project.pop-current ;
+
+# Windows libs
+lib psapi ;
+lib advapi32 ;
+lib secur32 ;
+lib ws2_32 ;
+lib mswsock ;
+
+# UNIX libs
+lib rt ;
+lib socket ;
+lib nsl ;
+lib ipv6 ;
+
+rule has-config-flag ( flag : properties * )
+{
+ if ( "<define>$(flag)" in $(properties) || "<define>$(flag)=1" in $(properties) )
+ {
+ return 1 ;
+ }
+ else
+ {
+ return ;
+ }
+}
+
+rule check-instruction-set ( properties * )
+{
+ local result ;
+ local instruction_set = [ feature.get-values "log-instruction-set" : [ log-architecture.deduce-instruction-set $(properties) ] ] ;
+
+ if $(instruction_set) = i386 || $(instruction_set) = i486
+ {
+ if ! $(.annouced-failure)
+ {
+ ECHO Boost.Log is not supported on the specified target CPU and will not be built. At least i586 class CPU is required. ;
+ .annouced-failure = 1 ;
+ }
+ result = <build>no ;
+ }
+
+ return $(result) ;
+}
+
+rule select-regex-backend ( properties * )
+{
+ local result = ;
+
+ # Use Boost.Regex backend by default. It produces smaller executables and also has the best performance for small string matching.
+ if ! (
+ [ has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] ||
+ [ has-config-flag BOOST_LOG_WITHOUT_DEFAULT_FACTORIES : $(properties) ] ||
+ [ has-config-flag BOOST_LOG_USE_STD_REGEX : $(properties) ] ||
+ [ has-config-flag BOOST_LOG_USE_BOOST_XPRESSIVE : $(properties) ] )
+ {
+ result = <library>/boost/regex//boost_regex ;
+ }
+
+ return $(result) ;
+}
+
+rule check-pthread-mutex-robust ( properties * )
+{
+ local result = ;
+
+ local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : pthread-supports-robust-mutexes ] ;
+ if $(has_pthread_mutex_robust)
+ {
+ result = <define>BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST ;
+ }
+
+ return $(result) ;
+}
+
+rule check-atomic-int32 ( properties * )
+{
+ local result = ;
+
+ local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : native-atomic-int32-supported ] ;
+ if ! $(has_atomic_int32)
+ {
+ result = <define>BOOST_LOG_WITHOUT_IPC ;
+ }
+
+ return $(result) ;
+}
+
+rule check-native-syslog ( properties * )
+{
+ local result = ;
+
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ]
+ {
+ local has_native_syslog = [ configure.builds /boost/log/native-syslog//native_syslog : $(properties) : native-syslog-supported ] ;
+ if $(has_native_syslog)
+ {
+ result = <define>BOOST_LOG_USE_NATIVE_SYSLOG ;
+ }
+ }
+
+ return $(result) ;
+}
+
+rule check-message-compiler ( properties * )
+{
+ local result ;
+
+ if <target-os>windows in $(properties)
+ {
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ]
+ {
+ local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ;
+ if ! $(has_mc)
+ {
+ result = <define>BOOST_LOG_WITHOUT_EVENT_LOG ;
+ }
+ }
+ else
+ {
+ # This branch is needed to fix building with MinGW
+ result = <define>BOOST_LOG_WITHOUT_EVENT_LOG ;
+ }
+ }
+ else
+ {
+ result = <define>BOOST_LOG_WITHOUT_EVENT_LOG ;
+ }
+
+ return $(result) ;
+}
+
+project boost/log
+ : source-location ../src
+ : requirements
+ <conditional>@check-instruction-set
+ <conditional>@check-atomic-int32
+ <conditional>@select-regex-backend
+ <conditional>@check-pthread-mutex-robust
+ <conditional>@check-native-syslog
+ <conditional>@check-message-compiler
+ <conditional>@log-platform-config.set-platform-defines
+
+ <include>../src
+
+ <define>__STDC_CONSTANT_MACROS # Use system-defined macros for integer constants, if possible
+ <define>BOOST_SPIRIT_USE_PHOENIX_V3=1
+ <define>BOOST_THREAD_DONT_USE_CHRONO=1 # Don't introduce false dependency on Boost.Chrono
+
+ # Disable warnings about using 'insecure' standard C functions
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>clang:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+ <toolset>gcc,<target-os>windows:<linkflags>-Wl,--enable-auto-import
+ <toolset>gcc,<target-os>cygwin:<linkflags>-Wl,--enable-auto-import
+
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/atomic//boost_atomic
+ <threading>multi:<library>/boost/thread//boost_thread
+
+ <target-os>windows:<library>ws2_32
+ <target-os>windows:<library>mswsock
+ <target-os>windows:<library>advapi32
+
+ <target-os>cygwin:<library>ws2_32
+ <target-os>cygwin:<library>mswsock
+ <target-os>cygwin:<library>advapi32
+ # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76
+ <target-os>cygwin:<define>BOOST_LOG_WITHOUT_IPC
+
+ <target-os>linux:<library>rt
+
+ <target-os>solaris:<library>socket
+ <target-os>solaris:<library>nsl
+
+ <target-os>hpux:<library>ipv6
+
+ <target-os>freebsd:<library>rt
+ <target-os>qnxnto:<library>socket
+ <toolset>pgi:<library>rt
+ : usage-requirements
+ <toolset>clang:<cxxflags>-Wno-bind-to-temporary-copy
+ <toolset>clang:<cxxflags>-Wno-unused-function
+ ;
+
+local BOOST_LOG_COMMON_SRC =
+ attribute_name.cpp
+ attribute_set.cpp
+ attribute_value_set.cpp
+ code_conversion.cpp
+ core.cpp
+ record_ostream.cpp
+ severity_level.cpp
+ global_logger_storage.cpp
+ named_scope.cpp
+ process_name.cpp
+ process_id.cpp
+ thread_id.cpp
+ timer.cpp
+ exceptions.cpp
+ default_attribute_names.cpp
+ default_sink.cpp
+ text_ostream_backend.cpp
+ text_file_backend.cpp
+ text_multifile_backend.cpp
+ thread_specific.cpp
+ once_block.cpp
+ timestamp.cpp
+ threadsafe_queue.cpp
+ event.cpp
+ trivial.cpp
+ spirit_encoding.cpp
+ format_parser.cpp
+ date_time_format_parser.cpp
+ named_scope_format_parser.cpp
+ permissions.cpp
+ dump.cpp
+ ;
+
+BOOST_LOG_COMMON_SSSE3_SRC =
+ dump_ssse3
+ ;
+
+BOOST_LOG_COMMON_AVX2_SRC =
+ dump_avx2
+ ;
+
+rule ssse3-targets-cond ( properties * )
+{
+ local result = <build>no ;
+
+ if <log-architecture>x86 in [ log-architecture.deduce-architecture $(properties) ]
+ {
+ local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : compiler-supports-ssse3 ] ;
+ if $(has_ssse3)
+ {
+ result = ;
+ if <toolset>gcc in $(properties) || <toolset>clang in $(properties)
+ {
+ result = <cxxflags>"-msse -msse2 -msse3 -mssse3" ;
+ }
+ else if <toolset>intel in $(properties)
+ {
+ if <toolset-intel:platform>win in $(properties)
+ {
+ result = <cxxflags>"/QxSSSE3" ;
+ }
+ else
+ {
+ result = <cxxflags>"-xSSSE3" ;
+ }
+ }
+ else if <toolset>msvc in $(properties)
+ {
+ # MSVC doesn't really care about these switches, all SSE intrinsics are always available, but still...
+ # Also 64 bit MSVC doesn't have the /arch:SSE2 switch as it is the default.
+ if <log-address-model>32 in [ log-architecture.deduce-address-model $(properties) ]
+ {
+ result = <cxxflags>"/arch:SSE2" ;
+ }
+ }
+ }
+ }
+
+# if ! <build>no in $(result)
+# {
+# ECHO Boost.Log: Using SSSE3 optimized implementation ;
+# }
+# ECHO $(result) ;
+
+ return $(result) ;
+}
+
+for local src in $(BOOST_LOG_COMMON_SSSE3_SRC)
+{
+ obj $(src)
+ : ## sources ##
+ $(src).cpp
+ : ## requirements ##
+ <conditional>@ssse3-targets-cond
+ <link>shared:<define>BOOST_LOG_DLL
+ <define>BOOST_LOG_BUILDING_THE_LIB=1
+ : ## default-build ##
+ : ## usage-requirements ##
+ <define>BOOST_LOG_USE_SSSE3
+ ;
+
+ explicit $(src) ;
+}
+
+rule avx2-targets-cond ( properties * )
+{
+ local result = <build>no ;
+
+ if <log-architecture>x86 in [ log-architecture.deduce-architecture $(properties) ]
+ {
+ local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : compiler-supports-avx2 ] ;
+ if $(has_avx2)
+ {
+ result = ;
+ if <toolset>gcc in $(properties)
+ {
+ result = <cxxflags>"-mavx -mavx2 -fabi-version=0" ;
+ }
+ else if <toolset>clang in $(properties)
+ {
+ result = <cxxflags>"-mavx -mavx2" ;
+ }
+ else if <toolset>intel in $(properties)
+ {
+ if <toolset-intel:platform>win in $(properties)
+ {
+ result = <cxxflags>"/arch:CORE-AVX2" ;
+ }
+ else
+ {
+ result = <cxxflags>"-xCORE-AVX2 -fabi-version=0" ;
+ }
+ }
+ else if <toolset>msvc in $(properties)
+ {
+ result = <cxxflags>"/arch:AVX" ;
+ }
+ }
+ }
+
+# if ! <build>no in $(result)
+# {
+# ECHO Boost.Log: Using AVX2 optimized implementation ;
+# }
+# ECHO $(result) ;
+
+ return $(result) ;
+}
+
+for local src in $(BOOST_LOG_COMMON_AVX2_SRC)
+{
+ obj $(src)
+ : ## sources ##
+ $(src).cpp
+ : ## requirements ##
+ <conditional>@avx2-targets-cond
+ <link>shared:<define>BOOST_LOG_DLL
+ <define>BOOST_LOG_BUILDING_THE_LIB=1
+ : ## default-build ##
+ : ## usage-requirements ##
+ <define>BOOST_LOG_USE_AVX2
+ ;
+
+ explicit $(src) ;
+}
+
+rule select-arch-specific-sources ( properties * )
+{
+ local result ;
+
+ if <log-architecture>x86 in [ log-architecture.deduce-architecture $(properties) ]
+ {
+ local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : compiler-supports-ssse3 ] ;
+ if $(has_ssse3)
+ {
+ result += <define>BOOST_LOG_USE_SSSE3 ;
+ result += <source>$(BOOST_LOG_COMMON_SSSE3_SRC) ;
+ }
+
+ local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : compiler-supports-avx2 ] ;
+ if $(has_avx2)
+ {
+ result += <define>BOOST_LOG_USE_AVX2 ;
+ result += <source>$(BOOST_LOG_COMMON_AVX2_SRC) ;
+ }
+ }
+
+# ECHO Arch sources: $(result) ;
+
+ return $(result) ;
+}
+
+rule select-platform-specific-sources ( properties * )
+{
+ local result ;
+
+ if <target-os>windows in $(properties)
+ {
+ result += <source>windows/light_rw_mutex.cpp ;
+
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ]
+ {
+ result += <source>windows/object_name.cpp ;
+ result += <source>windows/mapped_shared_memory.cpp ;
+ result += <source>windows/ipc_sync_wrappers.cpp ;
+ result += <source>windows/ipc_reliable_message_queue.cpp ;
+ result += <library>secur32 ;
+ }
+
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_DEBUG_OUTPUT : $(properties) ]
+ {
+ result += <source>windows/debug_output_backend.cpp ;
+ }
+
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ]
+ {
+ result += <source>windows/simple_event_log.mc ;
+ result += <source>windows/event_log_backend.cpp ;
+ result += <library>psapi ;
+
+ DEPENDS windows/event_log_backend.cpp : windows/simple_event_log.mc ;
+ }
+ }
+ else
+ {
+ result += <define>BOOST_LOG_WITHOUT_EVENT_LOG ;
+ result += <define>BOOST_LOG_WITHOUT_DEBUG_OUTPUT ;
+
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ]
+ {
+ result += <source>posix/object_name.cpp ;
+ result += <source>posix/ipc_reliable_message_queue.cpp ;
+ }
+ }
+
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ]
+ {
+ result += <source>syslog_backend.cpp ;
+ }
+
+# ECHO Platform sources: $(result) ;
+
+ return $(result) ;
+}
+
+lib boost_log
+ : ## sources ##
+ $(BOOST_LOG_COMMON_SRC)
+ : ## requirements ##
+ <conditional>@select-arch-specific-sources
+ <conditional>@select-platform-specific-sources
+ <link>shared:<define>BOOST_LOG_DLL
+ <define>BOOST_LOG_BUILDING_THE_LIB=1
+ : ## default-build ##
+ : ## usage-requirements ##
+ <link>shared:<define>BOOST_LOG_DYN_LINK=1
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ ;
+
+
+local BOOST_LOG_SETUP_COMMON_SRC =
+ parser_utils.cpp
+ init_from_stream.cpp
+ init_from_settings.cpp
+ settings_parser.cpp
+ filter_parser.cpp
+ formatter_parser.cpp
+ default_filter_factory.cpp
+ matches_relation_factory.cpp
+ default_formatter_factory.cpp
+ ;
+
+lib boost_log_setup
+ : ## sources ##
+ setup/$(BOOST_LOG_SETUP_COMMON_SRC)
+ : ## requirements ##
+ <link>shared:<define>BOOST_LOG_DYN_LINK=1
+ <link>shared:<define>BOOST_LOG_SETUP_DLL
+ <define>BOOST_LOG_SETUP_BUILDING_THE_LIB=1
+ <library>boost_log
+ : ## default-build ##
+ : ## usage-requirements ##
+ <link>shared:<define>BOOST_LOG_SETUP_DYN_LINK=1
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ ;
+
+boost-install boost_log boost_log_setup ;
diff --git a/src/boost/libs/log/build/log-architecture.jam b/src/boost/libs/log/build/log-architecture.jam
new file mode 100644
index 000000000..785dda0f5
--- /dev/null
+++ b/src/boost/libs/log/build/log-architecture.jam
@@ -0,0 +1,112 @@
+# log-architecture.jam
+#
+# Copyright 2012 Steven Watanabe
+# Copyright 2013 Andrey Semashev
+#
+# 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)
+
+import configure ;
+import project ;
+import path ;
+import property ;
+import feature ;
+
+local here = [ modules.binding $(__name__) ] ;
+
+feature.feature log-architecture : : free ;
+feature.feature log-address-model : : free ;
+feature.feature log-instruction-set : : free ;
+
+project.push-current [ project.current ] ;
+project.load [ path.join [ path.make $(here:D) ] ../../config/checks/architecture ] ;
+project.pop-current ;
+
+rule deduce-address-model ( properties * )
+{
+ local address_model = [ feature.get-values "address-model" : $(properties) ] ;
+ if $(address_model)
+ {
+ return <log-address-model>$(address_model) ;
+ }
+ else
+ {
+ if [ configure.builds /boost/architecture//32 : $(properties) : 32-bit ]
+ {
+ return <log-address-model>32 ;
+ }
+ else if [ configure.builds /boost/architecture//64 : $(properties) : 64-bit ]
+ {
+ return <log-address-model>64 ;
+ }
+ }
+}
+
+rule address-model ( )
+{
+ return <conditional>@log-architecture.deduce-address-model ;
+}
+
+rule deduce-architecture ( properties * )
+{
+ local architecture = [ feature.get-values "architecture" : $(properties) ] ;
+ if $(architecture)
+ {
+ return <log-architecture>$(architecture) ;
+ }
+ else
+ {
+ if [ configure.builds /boost/architecture//x86 : $(properties) : x86 ]
+ {
+ return <log-architecture>x86 ;
+ }
+ else if [ configure.builds /boost/architecture//arm : $(properties) : arm ]
+ {
+ return <log-architecture>arm ;
+ }
+ else if [ configure.builds /boost/architecture//mips1 : $(properties) : mips1 ]
+ {
+ return <log-architecture>mips1 ;
+ }
+ else if [ configure.builds /boost/architecture//power : $(properties) : power ]
+ {
+ return <log-architecture>power ;
+ }
+ else if [ configure.builds /boost/architecture//sparc : $(properties) : sparc ]
+ {
+ return <log-architecture>sparc ;
+ }
+ }
+}
+
+rule architecture ( )
+{
+ return <conditional>@log-architecture.deduce-architecture ;
+}
+
+rule deduce-instruction-set ( properties * )
+{
+ local result ;
+ local instruction_set = [ feature.get-values "instruction-set" : $(properties) ] ;
+
+ if $(instruction_set)
+ {
+ result = <log-instruction-set>$(instruction_set) ;
+ }
+ else
+ {
+ if <log-architecture>x86 in $(properties) && <log-address-model>32 in $(properties)
+ {
+ # We build for Pentium Pro and later CPUs by default. This is used as the target in many Linux distributions, and Windows and OS X also seem to not support older CPUs.
+ result = <log-instruction-set>i686 ;
+ }
+ }
+
+ return $(result) ;
+}
+
+rule instruction-set ( )
+{
+ return <conditional>@log-architecture.deduce-instruction-set ;
+}
diff --git a/src/boost/libs/log/build/log-platform-config.jam b/src/boost/libs/log/build/log-platform-config.jam
new file mode 100644
index 000000000..cee01cc10
--- /dev/null
+++ b/src/boost/libs/log/build/log-platform-config.jam
@@ -0,0 +1,59 @@
+# log-platform-config.jam
+#
+# Copyright 2017 Andrey Semashev
+#
+# 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)
+
+import configure ;
+import project ;
+import path ;
+import property ;
+import feature ;
+
+local here = [ modules.binding $(__name__) ] ;
+
+project.push-current [ project.current ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config/xopen-source-600 ] ;
+project.pop-current ;
+
+rule set-platform-defines ( properties * )
+{
+ local result = ;
+
+ if ( <target-os>windows in $(properties) ) || ( <target-os>cygwin in $(properties) )
+ {
+ result += <define>NOMINMAX ;
+ result += <define>WIN32_LEAN_AND_MEAN ;
+ result += <define>SECURITY_WIN32 ;
+ result += <define>BOOST_USE_WINDOWS_H ;
+
+ if <target-os>cygwin in $(properties)
+ {
+ result += <define>__USE_W32_SOCKETS ;
+ result += <define>_XOPEN_SOURCE=600 ;
+ }
+ }
+ else if <target-os>solaris in $(properties)
+ {
+ # Solaris headers are broken and cannot be included in C++03 when _XOPEN_SOURCE=600. At the same time, they cannot be included with _XOPEN_SOURCE=500 in C++11 and later.
+ # This is because the system headers check the C language version and error out if the version does not match. We have to test if we can request _XOPEN_SOURCE=600.
+ if [ configure.builds /boost/log/xopen-source-600//xopen_source_600 : $(properties) : xopen-source-600-supported ]
+ {
+ result += <define>_XOPEN_SOURCE=600 ;
+ }
+ else
+ {
+ result += <define>_XOPEN_SOURCE=500 ;
+ }
+
+ result += <define>__EXTENSIONS__ ;
+ }
+ else if ( <target-os>linux in $(properties) ) || ( <target-os>hpux in $(properties) )
+ {
+ result += <define>_XOPEN_SOURCE=600 ;
+ }
+
+ return $(result) ;
+}
diff --git a/src/boost/libs/log/config/atomic-int32/Jamfile.jam b/src/boost/libs/log/config/atomic-int32/Jamfile.jam
new file mode 100644
index 000000000..5b08d8d78
--- /dev/null
+++ b/src/boost/libs/log/config/atomic-int32/Jamfile.jam
@@ -0,0 +1,19 @@
+#
+# Copyright Andrey Semashev 2016.
+# 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)
+#
+
+import project ;
+import log-platform-config ;
+
+project /boost/log/atomic-int32
+ : source-location .
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <pch>off
+ ;
+
+obj atomic_int32 : atomic_int32.cpp ;
diff --git a/src/boost/libs/log/config/atomic-int32/atomic_int32.cpp b/src/boost/libs/log/config/atomic-int32/atomic_int32.cpp
new file mode 100644
index 000000000..f39bcc8f5
--- /dev/null
+++ b/src/boost/libs/log/config/atomic-int32/atomic_int32.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+
+#include <boost/atomic.hpp>
+
+#if !defined(BOOST_ATOMIC_INT32_LOCK_FREE) || (BOOST_ATOMIC_INT32_LOCK_FREE+0) != 2
+#error Boost.Log: Native 32-bit atomic operations are required but not supported by Boost.Atomic on the target platform
+#endif
+
+int main(int, char*[])
+{
+ return 0;
+}
diff --git a/src/boost/libs/log/config/message-compiler/Jamfile.jam b/src/boost/libs/log/config/message-compiler/Jamfile.jam
new file mode 100644
index 000000000..37d98d107
--- /dev/null
+++ b/src/boost/libs/log/config/message-compiler/Jamfile.jam
@@ -0,0 +1,22 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import project ;
+import log-platform-config ;
+using mc ;
+
+project /boost/log/message-compiler
+ : source-location ../../src
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+ <pch>off
+ ;
+
+obj simple_event_log : windows/simple_event_log.mc ;
+
+# This test target verifies that Message Compiler (mc) is available and supported by the current toolset
+alias test-availability : simple_event_log ;
diff --git a/src/boost/libs/log/config/native-syslog/Jamfile.jam b/src/boost/libs/log/config/native-syslog/Jamfile.jam
new file mode 100644
index 000000000..fa5dfcd0a
--- /dev/null
+++ b/src/boost/libs/log/config/native-syslog/Jamfile.jam
@@ -0,0 +1,19 @@
+#
+# Copyright Andrey Semashev 2016.
+# 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)
+#
+
+import project ;
+import log-platform-config ;
+
+project /boost/log/native-syslog
+ : source-location .
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <pch>off
+ ;
+
+obj native_syslog : native_syslog.cpp ;
diff --git a/src/boost/libs/log/config/native-syslog/native_syslog.cpp b/src/boost/libs/log/config/native-syslog/native_syslog.cpp
new file mode 100644
index 000000000..25605a682
--- /dev/null
+++ b/src/boost/libs/log/config/native-syslog/native_syslog.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+
+#include <syslog.h>
+
+int main(int, char*[])
+{
+ ::openlog("test", LOG_NDELAY, LOG_USER);
+
+ ::syslog(LOG_USER | LOG_DEBUG, "debug message");
+ ::syslog(LOG_USER | LOG_INFO, "info message");
+ ::syslog(LOG_USER | LOG_NOTICE, "notice message");
+ ::syslog(LOG_USER | LOG_WARNING, "warning message");
+ ::syslog(LOG_USER | LOG_ERR, "error message");
+ ::syslog(LOG_USER | LOG_CRIT, "critical message");
+ ::syslog(LOG_USER | LOG_ALERT, "alert message");
+ ::syslog(LOG_USER | LOG_EMERG, "emergency message");
+
+ ::closelog();
+
+ return 0;
+}
diff --git a/src/boost/libs/log/config/pthread-mutex-robust/Jamfile.jam b/src/boost/libs/log/config/pthread-mutex-robust/Jamfile.jam
new file mode 100644
index 000000000..6082e66e1
--- /dev/null
+++ b/src/boost/libs/log/config/pthread-mutex-robust/Jamfile.jam
@@ -0,0 +1,19 @@
+#
+# Copyright Andrey Semashev 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)
+#
+
+import project ;
+import log-platform-config ;
+
+project /boost/log/pthread-mutex-robust
+ : source-location .
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <pch>off
+ ;
+
+obj pthread_mutex_robust : pthread_mutex_robust.cpp ;
diff --git a/src/boost/libs/log/config/pthread-mutex-robust/pthread_mutex_robust.cpp b/src/boost/libs/log/config/pthread-mutex-robust/pthread_mutex_robust.cpp
new file mode 100644
index 000000000..36415aca0
--- /dev/null
+++ b/src/boost/libs/log/config/pthread-mutex-robust/pthread_mutex_robust.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright Andrey Semashev 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)
+ */
+
+#include <errno.h>
+#include <pthread.h>
+
+int main(int, char*[])
+{
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+ pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+ pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
+
+ pthread_mutex_t m;
+ pthread_mutex_init(&m, &attr);
+ pthread_mutexattr_destroy(&attr);
+
+ int err = pthread_mutex_lock(&m);
+ if (err == EOWNERDEAD)
+ {
+ err = pthread_mutex_consistent(&m);
+ }
+
+ if (err != ENOTRECOVERABLE)
+ {
+ pthread_mutex_unlock(&m);
+ }
+
+ pthread_mutex_destroy(&m);
+
+ return 0;
+}
diff --git a/src/boost/libs/log/config/x86-ext/Jamfile.jam b/src/boost/libs/log/config/x86-ext/Jamfile.jam
new file mode 100644
index 000000000..0e9695aae
--- /dev/null
+++ b/src/boost/libs/log/config/x86-ext/Jamfile.jam
@@ -0,0 +1,34 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import project ;
+
+project /boost/log/x86-extensions
+ : source-location .
+ : requirements
+ <pch>off
+ ;
+
+obj ssse3 : ssse3.cpp
+ :
+ <toolset>gcc:<cxxflags>"-msse -msse2 -msse3 -mssse3"
+ <toolset>clang:<cxxflags>"-msse -msse2 -msse3 -mssse3"
+ <toolset>intel-linux:<cxxflags>"-xSSSE3"
+ <toolset>intel-darwin:<cxxflags>"-xSSSE3"
+ <toolset>intel-win:<cxxflags>"/QxSSSE3"
+ ;
+
+obj avx2 : avx2.cpp
+ :
+ <toolset>gcc:<cxxflags>"-mavx -mavx2 -fabi-version=0"
+ <toolset>clang:<cxxflags>"-mavx -mavx2"
+ <toolset>intel-linux:<cxxflags>"-xCORE-AVX2 -fabi-version=0"
+ <toolset>intel-darwin:<cxxflags>"-xCORE-AVX2 -fabi-version=0"
+ <toolset>intel-win:<cxxflags>"/arch:CORE-AVX2"
+ <toolset>msvc:<cxxflags>"/arch:AVX"
+ ;
+
diff --git a/src/boost/libs/log/config/x86-ext/avx2.cpp b/src/boost/libs/log/config/x86-ext/avx2.cpp
new file mode 100644
index 000000000..3ee051f17
--- /dev/null
+++ b/src/boost/libs/log/config/x86-ext/avx2.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+
+#include <immintrin.h>
+
+void pretend_used(__m256i*);
+
+int main(int, char*[])
+{
+ __m256i mm = _mm256_setzero_si256();
+ pretend_used(&mm);
+ mm = _mm256_shuffle_epi8(_mm256_alignr_epi8(mm, mm, 10), mm);
+ pretend_used(&mm);
+ _mm256_zeroupper();
+ return 0;
+}
diff --git a/src/boost/libs/log/config/x86-ext/ssse3.cpp b/src/boost/libs/log/config/x86-ext/ssse3.cpp
new file mode 100644
index 000000000..4bcfe2bc7
--- /dev/null
+++ b/src/boost/libs/log/config/x86-ext/ssse3.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+
+#include <tmmintrin.h>
+
+void pretend_used(__m128i*);
+
+int main(int, char*[])
+{
+ __m128i mm = _mm_setzero_si128();
+ pretend_used(&mm);
+ mm = _mm_shuffle_epi8(_mm_alignr_epi8(mm, mm, 10), mm);
+ pretend_used(&mm);
+ return 0;
+}
diff --git a/src/boost/libs/log/config/xopen-source-600/Jamfile.jam b/src/boost/libs/log/config/xopen-source-600/Jamfile.jam
new file mode 100644
index 000000000..0d744dcfd
--- /dev/null
+++ b/src/boost/libs/log/config/xopen-source-600/Jamfile.jam
@@ -0,0 +1,16 @@
+#
+# Copyright Andrey Semashev 2017.
+# 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)
+#
+
+import project ;
+
+project /boost/log/xopen-source-600
+ : source-location .
+ : requirements
+ <pch>off
+ ;
+
+obj xopen_source_600 : xopen_source_600.cpp ;
diff --git a/src/boost/libs/log/config/xopen-source-600/xopen_source_600.cpp b/src/boost/libs/log/config/xopen-source-600/xopen_source_600.cpp
new file mode 100644
index 000000000..1b26467c9
--- /dev/null
+++ b/src/boost/libs/log/config/xopen-source-600/xopen_source_600.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright Andrey Semashev 2017.
+ * 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)
+ */
+
+// Test if we can include system headers with -D_XOPEN_SOURCE=600
+#undef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+
+#include <unistd.h>
+
+int main(int, char*[])
+{
+ return 0;
+}
diff --git a/src/boost/libs/log/example/Jamfile.v2 b/src/boost/libs/log/example/Jamfile.v2
new file mode 100644
index 000000000..07ad6ccf5
--- /dev/null
+++ b/src/boost/libs/log/example/Jamfile.v2
@@ -0,0 +1,23 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+build-project ./advanced_usage ;
+build-project ./async_log ;
+build-project ./bounded_async_log ;
+build-project ./basic_usage ;
+build-project ./event_log ;
+build-project ./multiple_files ;
+build-project ./multiple_threads ;
+build-project ./rotating_file ;
+build-project ./settings_file ;
+build-project ./settings_file_custom_factories ;
+build-project ./syslog ;
+build-project ./native_syslog ;
+build-project ./wide_char ;
+build-project ./keywords ;
+build-project ./trivial ;
+build-project ./doc ;
diff --git a/src/boost/libs/log/example/advanced_usage/Jamfile.v2 b/src/boost/libs/log/example/advanced_usage/Jamfile.v2
new file mode 100644
index 000000000..542bd18b6
--- /dev/null
+++ b/src/boost/libs/log/example/advanced_usage/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe advanced_usage
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/advanced_usage/main.cpp b/src/boost/libs/log/example/advanced_usage/main.cpp
new file mode 100644
index 000000000..dcfd1ee87
--- /dev/null
+++ b/src/boost/libs/log/example/advanced_usage/main.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 11.11.2007
+ *
+ * \brief An example of in-depth library usage. See the library tutorial for expanded
+ * comments on this code. It may also be worthwhile reading the Wiki requirements page:
+ * http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost.Logging
+ */
+
+// #define BOOST_LOG_USE_CHAR
+// #define BOOST_ALL_DYN_LINK 1
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <cassert>
+#include <iostream>
+#include <fstream>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/core/null_deleter.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/utility/manipulators/add_value.hpp>
+#include <boost/log/attributes/scoped_attribute.hpp>
+#include <boost/log/support/date_time.hpp>
+
+namespace logging = boost::log;
+namespace expr = boost::log::expressions;
+namespace sinks = boost::log::sinks;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+// Here we define our application severity levels.
+enum severity_level
+{
+ normal,
+ notification,
+ warning,
+ error,
+ critical
+};
+
+// The formatting logic for the severity level
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
+{
+ static const char* const str[] =
+ {
+ "normal",
+ "notification",
+ "warning",
+ "error",
+ "critical"
+ };
+ if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
+ strm << str[lvl];
+ else
+ strm << static_cast< int >(lvl);
+ return strm;
+}
+
+int foo(src::logger& lg)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG(lg) << "foo is being called";
+ return 10;
+}
+
+int main(int argc, char* argv[])
+{
+ // This is a in-depth tutorial/example of Boost.Log usage
+
+ // The first thing we have to do to get using the library is
+ // to set up the logging sinks - i.e. where the logs will be written to.
+ // Each sink is composed from frontend and backend. Frontend deals with
+ // general sink behavior, like filtering (see below) and threading model.
+ // Backend implements formatting and, actually, storing log records.
+ // Not every frontend/backend combinations are compatible (mostly because of
+ // threading models incompatibilities), but if they are not, the code will
+ // simply not compile.
+
+ // For now we only create a text output sink:
+ typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
+ shared_ptr< text_sink > pSink(new text_sink);
+
+ // Here synchronous_sink is a sink frontend that performs thread synchronization
+ // before passing log records to the backend (the text_ostream_backend class).
+ // The backend formats each record and outputs it to one or several streams.
+ // This approach makes implementing backends a lot simpler, because you don't
+ // need to worry about multithreading.
+
+ {
+ // The good thing about sink frontends is that they are provided out-of-box and
+ // take away thread-safety burden from the sink backend implementors. Even if you
+ // have to call a custom backend method, the frontend gives you a convenient way
+ // to do it in a thread safe manner. All you need is to acquire a locking pointer
+ // to the backend.
+ text_sink::locked_backend_ptr pBackend = pSink->locked_backend();
+
+ // Now, as long as pBackend lives, you may work with the backend without
+ // interference of other threads that might be trying to log.
+
+ // Next we add streams to which logging records should be output
+ shared_ptr< std::ostream > pStream(&std::clog, boost::null_deleter());
+ pBackend->add_stream(pStream);
+
+ // We can add more than one stream to the sink backend
+ shared_ptr< std::ofstream > pStream2(new std::ofstream("sample.log"));
+ assert(pStream2->is_open());
+ pBackend->add_stream(pStream2);
+ }
+
+ // Ok, we're ready to add the sink to the logging library
+ logging::core::get()->add_sink(pSink);
+
+ // Now our logs will be written both to the console and to the file.
+ // Let's do a quick test and output something. We have to create a logger for this.
+ src::logger lg;
+
+ // And output...
+ BOOST_LOG(lg) << "Hello, World!";
+
+ // Nice, huh? That's pretty much equivalent to writing the string to both the file
+ // and the console. Now let's define the different way of formatting log records.
+ // Each logging record may have a number of attributes in addition to the
+ // message body itself. By setting up formatter we define which of them
+ // will be written to log and in what way they will look there.
+ pSink->set_formatter(expr::stream
+ << expr::attr< unsigned int >("RecordID") // First an attribute "RecordID" is written to the log
+ << " [" << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%d.%m.%Y %H:%M:%S.%f")
+ << "] [" << expr::attr< severity_level >("Severity")
+ << "] [" << expr::attr< boost::posix_time::time_duration >("Uptime")
+ << "] [" // then this delimiter separates it from the rest of the line
+ << expr::if_(expr::has_attr("Tag"))
+ [
+ expr::stream << expr::attr< std::string >("Tag") // then goes another attribute named "Tag"
+ // Note here we explicitly stated that its type
+ // should be std::string. We could omit it just
+ // like we did it with the "RecordID", but in this case
+ // library would have to detect the actual attribute value
+ // type in run time which has the following consequences:
+ // - On the one hand, the attribute would have been output
+ // even if it has another type (not std::string).
+ // - On the other, this detection does not come for free
+ // and will result in performance decrease.
+ //
+ // In general it's better you to specify explicitly which
+ // type should an attribute have wherever it is possible.
+ // You may specify an MPL sequence of types if the attribute
+ // may have more than one type. And you will have to specify
+ // it anyway if the library is not familiar with it (see
+ // boost/log/utility/type_dispatch/standard_types.hpp for the list
+ // of the supported out-of-the-box types).
+ << "] [" // yet another delimiter
+ ]
+ << expr::format_named_scope("Scope", keywords::format = "%n", keywords::iteration = expr::reverse) << "] "
+ << expr::smessage); // here goes the log record text
+
+/*
+ // There is an alternative way of specifying formatters
+ pSink->set_formatter(
+ expr::format("%1% @ %2% [%3%] >%4%< Scope: %5%: %6%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%d.%m.%Y %H:%M:%S.%f")
+ % expr::attr< boost::posix_time::time_duration >("Uptime")
+ % expr::attr< std::string >("Tag")
+ % expr::format_named_scope("Scope", keywords::format = "%n", keywords::iteration = expr::reverse, keywords::depth = 2)
+ % expr::smessage);
+*/
+
+ // Now the sink will output in the following format:
+ // 1 [Current time] [Tag value] Hello World!
+ // The output will be the same for all streams we add to the sink. If you want something different,
+ // you may create another sink for that purpose.
+
+ // Now we're going to set up the attributes.
+ // Remember that "RecordID" attribute in the formatter? There is a counter
+ // attribute in the library that increments or decrements the value each time
+ // it is output. Let's create it with a starting value 1.
+ attrs::counter< unsigned int > RecordID(1);
+
+ // Since we intend to count all logging records ever made by the application,
+ // this attribute should clearly be global.
+ logging::core::get()->add_global_attribute("RecordID", RecordID);
+
+ // And similarly add a time stamp
+ attrs::local_clock TimeStamp;
+ logging::core::get()->add_global_attribute("TimeStamp", TimeStamp);
+
+ // And an up time stopwatch
+ BOOST_LOG_SCOPED_THREAD_ATTR("Uptime", attrs::timer());
+
+ // Attributes may have two other scopes: thread scope and source scope. Attributes of thread
+ // scope are output with each record made by the thread (regardless of the logger object), and
+ // attributes of the source scope are output with each record made by the logger. On output
+ // all attributes of global, thread and source scopes are merged into a one record and passed to
+ // the sinks as one view. There is no difference between attributes of different scopes from the
+ // sinks' perspective.
+
+ // Let's also track the execution scope from which the records are made
+ attrs::named_scope Scope;
+ logging::core::get()->add_thread_attribute("Scope", Scope);
+
+ // We can mark the current execution scope now - it's the 'main' function
+ BOOST_LOG_FUNCTION();
+
+ // Let's try out the counter attribute and formatting
+ BOOST_LOG(lg) << "Some log line with a counter";
+ BOOST_LOG(lg) << "Another log line with the counter";
+
+ // Ok, remember the "Tag" attribute we added in the formatter? It is absent in these
+ // two lines above, so it is empty in the output. Let's try to tag some log records with it.
+ {
+ BOOST_LOG_NAMED_SCOPE("Tagging scope");
+
+ // Here we add a temporary attribute to the logger lg.
+ // Every log record being written in the current scope with logger lg
+ // will have a string attribute "Tag" with value "Tagged line" attached.
+ BOOST_LOG_SCOPED_LOGGER_TAG(lg, "Tag", "Tagged line");
+
+ // The above line is roughly equivalent to the following:
+ // attrs::constant< std::string > TagAttr("Tagged line");
+ // logging::scoped_attribute _ =
+ // logging::add_scoped_logger_attribute(lg, "Tag", TagAttr);
+
+ // Now these lines will be highlighted with the tag
+ BOOST_LOG(lg) << "Some tagged log line";
+ BOOST_LOG(lg) << "Another tagged log line";
+ }
+
+ // And this line is not highlighted anymore
+ BOOST_LOG(lg) << "Now the tag is removed";
+ BOOST_LOG(lg) << logging::add_value("Tag", "Tagged line") << "Some lines can also be selectively tagged";
+
+ // Now let's try to apply filtering to the output. Filtering is based on
+ // attributes being output with the record. One of the common filtering use cases
+ // is filtering based on the record severity level. We've already defined severity levels.
+ // Now we can set the filter. A filter is essentially a functor that returns
+ // boolean value that tells whether to write the record or not.
+ pSink->set_filter(
+ expr::attr< severity_level >("Severity").or_default(normal) >= warning // Write all records with "warning" severity or higher
+ || expr::begins_with(expr::attr< std::string >("Tag").or_default(std::string()), "IMPORTANT")); // ...or specifically tagged
+
+ // The "attr" placeholder here acts pretty much like the "attr" placeholder in formatters, except
+ // that it requires the attribute type (or types in MPL-sequence) to be specified.
+ // In case of a single std::string or std::wstring type of attribute the "attr" placeholder
+ // provides a number of extended predicates which include "begins_with", "ends_with", "contains"
+ // and "matches" (the last one performs RegEx matching).
+ // There are other placeholders to be used for filter composition in the "boost/log/filters"
+ // directory. Additionally, you are not restricted to them and may provide your own filtering
+ // functors.
+
+ // It must be noted that filters may be applied on per-sink basis and/or globally.
+ // Above we set a filter for this particular sink. Had we another sink, the filter would
+ // not influence it. To set a global filter one should call the set_filter method of the
+ // logging system like that:
+ // logging::core::get()->set_filter(...);
+
+ // Now, to set logging severity we could perfectly use our previously created logger "lg".
+ // But no make it more convenient and efficient there is a special extended logger class.
+ // Its implementation may serve as an example of extending basic library functionality.
+ // You may add your specific capabilities to the logger by deriving your class from it.
+ src::severity_logger< severity_level > slg;
+
+ // These two lines test filtering based on severity
+ BOOST_LOG_SEV(slg, normal) << "A normal severity message, will not pass to the output";
+ BOOST_LOG_SEV(slg, error) << "An error severity message, will pass to the output";
+
+ {
+ // Next we try if the second condition of the filter works
+ // We mark following lines with a tag
+ BOOST_LOG_SCOPED_THREAD_TAG("Tag", "IMPORTANT MESSAGES");
+
+ // We may omit the severity and use the shorter BOOST_LOG macro. The logger "slg"
+ // has the default severity that may be specified on its construction. We didn't
+ // do it, so it is 0 by default. Therefore this record will have "normal" severity.
+ // The only reason this record will be output is the "Tag" attribute we added above.
+ BOOST_LOG(slg) << "Some really urgent line";
+ }
+
+ pSink->reset_filter();
+
+ // And moreover, it is possible to nest logging records. For example, this will
+ // be processed in the order of evaluation:
+ BOOST_LOG(lg) << "The result of foo is " << foo(lg);
+
+ return 0;
+}
diff --git a/src/boost/libs/log/example/async_log/Jamfile.v2 b/src/boost/libs/log/example/async_log/Jamfile.v2
new file mode 100644
index 000000000..bb2438d43
--- /dev/null
+++ b/src/boost/libs/log/example/async_log/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe async_log
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/async_log/main.cpp b/src/boost/libs/log/example/async_log/main.cpp
new file mode 100644
index 000000000..7f7a19509
--- /dev/null
+++ b/src/boost/libs/log/example/async_log/main.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 30.08.2009
+ *
+ * \brief An example of asynchronous logging in multiple threads.
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <functional>
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/utility/record_ordering.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+enum
+{
+ LOG_RECORDS_TO_WRITE = 10000,
+ THREAD_COUNT = 2
+};
+
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt)
+
+//! This function is executed in multiple threads
+void thread_fun(boost::barrier& bar)
+{
+ // Wait until all threads are created
+ bar.wait();
+
+ // Here we go. First, identify the thread.
+ BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
+
+ // Now, do some logging
+ for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
+ {
+ BOOST_LOG(test_lg::get()) << "Log record " << i;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Open a rotating text file
+ shared_ptr< std::ostream > strm(new std::ofstream("test.log"));
+ if (!strm->good())
+ throw std::runtime_error("Failed to open a text log file");
+
+ // Create a text file sink
+ typedef sinks::text_ostream_backend backend_t;
+ typedef sinks::asynchronous_sink<
+ backend_t,
+ sinks::unbounded_ordering_queue<
+ logging::attribute_value_ordering< unsigned int, std::less< unsigned int > >
+ >
+ > sink_t;
+ shared_ptr< sink_t > sink(new sink_t(
+ boost::make_shared< backend_t >(),
+ // We'll apply record ordering to ensure that records from different threads go sequentially in the file
+ keywords::order = logging::make_attr_ordering< unsigned int >("RecordID", std::less< unsigned int >())));
+
+ sink->locked_backend()->add_stream(strm);
+
+ sink->set_formatter
+ (
+ expr::format("%1%: [%2%] [%3%] - %4%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::attr< boost::posix_time::ptime >("TimeStamp")
+ % expr::attr< boost::thread::id >("ThreadID")
+ % expr::smessage
+ );
+
+ // Add it to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+
+ // Create logging threads
+ boost::barrier bar(THREAD_COUNT);
+ boost::thread_group threads;
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ threads.create_thread(boost::bind(&thread_fun, boost::ref(bar)));
+
+ // Wait until all action ends
+ threads.join_all();
+
+ // Flush all buffered records
+ sink->stop();
+ sink->flush();
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/basic_usage/Jamfile.v2 b/src/boost/libs/log/example/basic_usage/Jamfile.v2
new file mode 100644
index 000000000..56a9d5eb5
--- /dev/null
+++ b/src/boost/libs/log/example/basic_usage/Jamfile.v2
@@ -0,0 +1,58 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ ;
+
+exe basic_usage
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/basic_usage/main.cpp b/src/boost/libs/log/example/basic_usage/main.cpp
new file mode 100644
index 000000000..3dc8a5af0
--- /dev/null
+++ b/src/boost/libs/log/example/basic_usage/main.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 11.11.2007
+ *
+ * \brief An example of basic library usage. See the library tutorial for expanded
+ * comments on this code. It may also be worthwhile reading the Wiki requirements page:
+ * http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost.Logging
+ */
+
+// #define BOOST_LOG_USE_CHAR
+// #define BOOST_ALL_DYN_LINK 1
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <iostream>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+
+#include <boost/log/utility/setup/file.hpp>
+#include <boost/log/utility/setup/console.hpp>
+#include <boost/log/utility/setup/common_attributes.hpp>
+
+#include <boost/log/attributes/timer.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+
+#include <boost/log/sources/logger.hpp>
+
+#include <boost/log/support/date_time.hpp>
+
+namespace logging = boost::log;
+namespace sinks = boost::log::sinks;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+// Here we define our application severity levels.
+enum severity_level
+{
+ normal,
+ notification,
+ warning,
+ error,
+ critical
+};
+
+// The formatting logic for the severity level
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (
+ std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
+{
+ static const char* const str[] =
+ {
+ "normal",
+ "notification",
+ "warning",
+ "error",
+ "critical"
+ };
+ if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
+ strm << str[lvl];
+ else
+ strm << static_cast< int >(lvl);
+ return strm;
+}
+
+int main(int argc, char* argv[])
+{
+ // This is a simple tutorial/example of Boost.Log usage
+
+ // The first thing we have to do to get using the library is
+ // to set up the logging sinks - i.e. where the logs will be written to.
+ logging::add_console_log(std::clog, keywords::format = "%TimeStamp%: %Message%");
+
+ // One can also use lambda expressions to setup filters and formatters
+ logging::add_file_log
+ (
+ "sample.log",
+ keywords::filter = expr::attr< severity_level >("Severity") >= warning,
+ keywords::format = expr::stream
+ << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d, %H:%M:%S.%f")
+ << " [" << expr::format_date_time< attrs::timer::value_type >("Uptime", "%O:%M:%S")
+ << "] [" << expr::format_named_scope("Scope", keywords::format = "%n (%f:%l)")
+ << "] <" << expr::attr< severity_level >("Severity")
+ << "> " << expr::message
+/*
+ keywords::format = expr::format("%1% [%2%] [%3%] <%4%> %5%")
+ % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d, %H:%M:%S.%f")
+ % expr::format_date_time< attrs::timer::value_type >("Uptime", "%O:%M:%S")
+ % expr::format_named_scope("Scope", keywords::format = "%n (%f:%l)")
+ % expr::attr< severity_level >("Severity")
+ % expr::message
+*/
+ );
+
+ // Also let's add some commonly used attributes, like timestamp and record counter.
+ logging::add_common_attributes();
+ logging::core::get()->add_thread_attribute("Scope", attrs::named_scope());
+
+ BOOST_LOG_FUNCTION();
+
+ // Now our logs will be written both to the console and to the file.
+ // Let's do a quick test and output something. We have to create a logger for this.
+ src::logger lg;
+
+ // And output...
+ BOOST_LOG(lg) << "Hello, World!";
+
+ // Now, let's try logging with severity
+ src::severity_logger< severity_level > slg;
+
+ // Let's pretend we also want to profile our code, so add a special timer attribute.
+ slg.add_attribute("Uptime", attrs::timer());
+
+ BOOST_LOG_SEV(slg, normal) << "A normal severity message, will not pass to the file";
+ BOOST_LOG_SEV(slg, warning) << "A warning severity message, will pass to the file";
+ BOOST_LOG_SEV(slg, error) << "An error severity message, will pass to the file";
+
+ return 0;
+}
diff --git a/src/boost/libs/log/example/bounded_async_log/Jamfile.v2 b/src/boost/libs/log/example/bounded_async_log/Jamfile.v2
new file mode 100644
index 000000000..36e47a29a
--- /dev/null
+++ b/src/boost/libs/log/example/bounded_async_log/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe bounded_async_log
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/bounded_async_log/main.cpp b/src/boost/libs/log/example/bounded_async_log/main.cpp
new file mode 100644
index 000000000..14dee2f5e
--- /dev/null
+++ b/src/boost/libs/log/example/bounded_async_log/main.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 30.08.2009
+ *
+ * \brief An example of asynchronous logging with bounded log record queue in multiple threads.
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <functional>
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/utility/record_ordering.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+enum
+{
+ LOG_RECORDS_TO_WRITE = 10000,
+ THREAD_COUNT = 2
+};
+
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt)
+
+//! This function is executed in multiple threads
+void thread_fun(boost::barrier& bar)
+{
+ // Wait until all threads are created
+ bar.wait();
+
+ // Here we go. First, identify the thread.
+ BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
+
+ // Now, do some logging
+ for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
+ {
+ BOOST_LOG(test_lg::get()) << "Log record " << i;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Open a rotating text file
+ shared_ptr< std::ostream > strm(new std::ofstream("test.log"));
+ if (!strm->good())
+ throw std::runtime_error("Failed to open a text log file");
+
+ // Create a text file sink
+ typedef sinks::text_ostream_backend backend_t;
+ typedef sinks::asynchronous_sink<
+ backend_t,
+ sinks::bounded_ordering_queue<
+ logging::attribute_value_ordering< unsigned int, std::less< unsigned int > >,
+ 128, // queue no more than 128 log records
+ sinks::block_on_overflow // wait until records are processed
+ >
+ > sink_t;
+ shared_ptr< sink_t > sink(new sink_t(
+ boost::make_shared< backend_t >(),
+ // We'll apply record ordering to ensure that records from different threads go sequentially in the file
+ keywords::order = logging::make_attr_ordering("RecordID", std::less< unsigned int >())));
+
+ sink->locked_backend()->add_stream(strm);
+
+ sink->set_formatter
+ (
+ expr::format("%1%: [%2%] [%3%] - %4%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::attr< boost::posix_time::ptime >("TimeStamp")
+ % expr::attr< boost::thread::id >("ThreadID")
+ % expr::smessage
+ );
+
+ // Add it to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+
+ // Create logging threads
+ boost::barrier bar(THREAD_COUNT);
+ boost::thread_group threads;
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ threads.create_thread(boost::bind(&thread_fun, boost::ref(bar)));
+
+ // Wait until all action ends
+ threads.join_all();
+
+ // Flush all buffered records
+ sink->stop();
+ sink->flush();
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/event_log/Jamfile.v2 b/src/boost/libs/log/example/event_log/Jamfile.v2
new file mode 100644
index 000000000..bcc17f46b
--- /dev/null
+++ b/src/boost/libs/log/example/event_log/Jamfile.v2
@@ -0,0 +1,102 @@
+#
+# Copyright Andrey Semashev 2007 - 2016.
+# 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)
+#
+
+import os ;
+import configure ;
+import ../../build/log-platform-config ;
+
+rule has-config-flag ( flag : properties * )
+{
+ if ( "<define>$(flag)" in $(properties) || "<define>$(flag)=1" in $(properties) )
+ {
+ return 1 ;
+ }
+ else
+ {
+ return ;
+ }
+}
+
+rule check-message-compiler ( properties * )
+{
+ local result ;
+
+ if <target-os>windows in $(properties)
+ {
+ if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ]
+ {
+ local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ;
+ if ! $(has_mc)
+ {
+ result += <build>no ;
+ }
+ }
+ }
+ else
+ {
+ result += <build>no ;
+ }
+
+ return $(result) ;
+}
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+ <conditional>@check-message-compiler
+
+ <link>shared
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+lib event_log_messages
+ : event_log_messages.mc
+ : <linkflags>-noentry
+# <name>event_log_messages
+ ;
+
+exe event_log
+ : main.cpp
+ : <implicit-dependency>event_log_messages
+ ;
diff --git a/src/boost/libs/log/example/event_log/event_log_messages.mc b/src/boost/libs/log/example/event_log/event_log_messages.mc
new file mode 100644
index 000000000..d3e107903
--- /dev/null
+++ b/src/boost/libs/log/example/event_log/event_log_messages.mc
@@ -0,0 +1,58 @@
+; /* --------------------------------------------------------
+; HEADER SECTION
+; */
+SeverityNames=(Debug=0x0:MY_SEVERITY_DEBUG
+ Info=0x1:MY_SEVERITY_INFO
+ Warning=0x2:MY_SEVERITY_WARNING
+ Error=0x3:MY_SEVERITY_ERROR
+ )
+
+; /* --------------------------------------------------------
+; MESSAGE DEFINITION SECTION
+; */
+
+MessageIdTypedef=WORD
+
+MessageId=0x1
+SymbolicName=MY_CATEGORY_1
+Language=English
+Category 1
+.
+
+MessageId=0x2
+SymbolicName=MY_CATEGORY_2
+Language=English
+Category 2
+.
+
+MessageId=0x3
+SymbolicName=MY_CATEGORY_3
+Language=English
+Category 3
+.
+
+MessageIdTypedef=DWORD
+
+MessageId=0x100
+Severity=Warning
+Facility=Application
+SymbolicName=LOW_DISK_SPACE_MSG
+Language=English
+The drive %1 has low free disk space. At least %2 Mb of free space is recommended.
+.
+
+MessageId=0x101
+Severity=Error
+Facility=Application
+SymbolicName=DEVICE_INACCESSIBLE_MSG
+Language=English
+The drive %1 is not accessible.
+.
+
+MessageId=0x102
+Severity=Info
+Facility=Application
+SymbolicName=SUCCEEDED_MSG
+Language=English
+Operation finished successfully in %1 seconds.
+.
diff --git a/src/boost/libs/log/example/event_log/main.cpp b/src/boost/libs/log/example/event_log/main.cpp
new file mode 100644
index 000000000..ca02a188e
--- /dev/null
+++ b/src/boost/libs/log/example/event_log/main.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 16.11.2008
+ *
+ * \brief An example of logging into Windows event log.
+ *
+ * The example shows the basic usage of the Windows NT event log backend.
+ * The code defines custom severity levels, initializes the sink and a couple of
+ * attributes to test with, and writes several records at different levels.
+ * As a result the written records should appear in the Application log, and
+ * should be displayed correctly with the Windows event log viewer.
+ */
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/event_log_backend.hpp>
+
+#if !defined(WIN32_LEAN_AND_MEAN)
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#include "event_log_messages.h"
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+//[ example_sinks_event_log_severity
+// Define application-specific severity levels
+enum severity_level
+{
+ normal,
+ warning,
+ error
+};
+//]
+
+void init_logging()
+{
+ //[ example_sinks_event_log_create_backend
+ // Create an event log sink
+ boost::shared_ptr< sinks::event_log_backend > backend(
+ new sinks::event_log_backend((
+ keywords::message_file = "%SystemDir%\\event_log_messages.dll",
+ keywords::log_name = "My Application",
+ keywords::log_source = "My Source"
+ ))
+ );
+ //]
+
+ //[ example_sinks_event_log_event_composer
+ // Create an event composer. It is initialized with the event identifier mapping.
+ sinks::event_log::event_composer composer(
+ sinks::event_log::direct_event_id_mapping< int >("EventID"));
+
+ // For each event described in the message file, set up the insertion string formatters
+ composer[LOW_DISK_SPACE_MSG]
+ // the first placeholder in the message
+ // will be replaced with contents of the "Drive" attribute
+ % expr::attr< std::string >("Drive")
+ // the second placeholder in the message
+ // will be replaced with contents of the "Size" attribute
+ % expr::attr< boost::uintmax_t >("Size");
+
+ composer[DEVICE_INACCESSIBLE_MSG]
+ % expr::attr< std::string >("Drive");
+
+ composer[SUCCEEDED_MSG]
+ % expr::attr< unsigned int >("Duration");
+
+ // Then put the composer to the backend
+ backend->set_event_composer(composer);
+ //]
+
+ //[ example_sinks_event_log_mappings
+ // We'll have to map our custom levels to the event log event types
+ sinks::event_log::custom_event_type_mapping< severity_level > type_mapping("Severity");
+ type_mapping[normal] = sinks::event_log::make_event_type(MY_SEVERITY_INFO);
+ type_mapping[warning] = sinks::event_log::make_event_type(MY_SEVERITY_WARNING);
+ type_mapping[error] = sinks::event_log::make_event_type(MY_SEVERITY_ERROR);
+
+ backend->set_event_type_mapper(type_mapping);
+
+ // Same for event categories.
+ // Usually event categories can be restored by the event identifier.
+ sinks::event_log::custom_event_category_mapping< int > cat_mapping("EventID");
+ cat_mapping[LOW_DISK_SPACE_MSG] = sinks::event_log::make_event_category(MY_CATEGORY_1);
+ cat_mapping[DEVICE_INACCESSIBLE_MSG] = sinks::event_log::make_event_category(MY_CATEGORY_2);
+ cat_mapping[SUCCEEDED_MSG] = sinks::event_log::make_event_category(MY_CATEGORY_3);
+
+ backend->set_event_category_mapper(cat_mapping);
+ //]
+
+ //[ example_sinks_event_log_register_sink
+ // Create the frontend for the sink
+ boost::shared_ptr< sinks::synchronous_sink< sinks::event_log_backend > > sink(
+ new sinks::synchronous_sink< sinks::event_log_backend >(backend));
+
+ // Set up filter to pass only records that have the necessary attribute
+ sink->set_filter(expr::has_attr< int >("EventID"));
+
+ logging::core::get()->add_sink(sink);
+ //]
+}
+
+//[ example_sinks_event_log_facilities
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(event_logger, src::severity_logger_mt< severity_level >)
+
+// The function raises an event of the disk space depletion
+void announce_low_disk_space(std::string const& drive, boost::uintmax_t size)
+{
+ BOOST_LOG_SCOPED_THREAD_TAG("EventID", (int)LOW_DISK_SPACE_MSG);
+ BOOST_LOG_SCOPED_THREAD_TAG("Drive", drive);
+ BOOST_LOG_SCOPED_THREAD_TAG("Size", size);
+ // Since this record may get accepted by other sinks,
+ // this message is not completely useless
+ BOOST_LOG_SEV(event_logger::get(), warning) << "Low disk " << drive
+ << " space, " << size << " Mb is recommended";
+}
+
+// The function raises an event of inaccessible disk drive
+void announce_device_inaccessible(std::string const& drive)
+{
+ BOOST_LOG_SCOPED_THREAD_TAG("EventID", (int)DEVICE_INACCESSIBLE_MSG);
+ BOOST_LOG_SCOPED_THREAD_TAG("Drive", drive);
+ BOOST_LOG_SEV(event_logger::get(), error) << "Cannot access drive " << drive;
+}
+
+// The structure is an activity guard that will emit an event upon the activity completion
+struct activity_guard
+{
+ activity_guard()
+ {
+ // Add a stop watch attribute to measure the activity duration
+ m_it = event_logger::get().add_attribute("Duration", attrs::timer()).first;
+ }
+ ~activity_guard()
+ {
+ BOOST_LOG_SCOPED_THREAD_TAG("EventID", (int)SUCCEEDED_MSG);
+ BOOST_LOG_SEV(event_logger::get(), normal) << "Activity ended";
+ event_logger::get().remove_attribute(m_it);
+ }
+
+private:
+ logging::attribute_set::iterator m_it;
+};
+//]
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Initialize the library
+ init_logging();
+
+ // Make some events
+ {
+ activity_guard activity;
+
+ announce_low_disk_space("C:", 2 * 1024 * 1024);
+ announce_device_inaccessible("D:");
+ }
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/keywords/Jamfile.v2 b/src/boost/libs/log/example/keywords/Jamfile.v2
new file mode 100644
index 000000000..54db6e112
--- /dev/null
+++ b/src/boost/libs/log/example/keywords/Jamfile.v2
@@ -0,0 +1,58 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ ;
+
+exe keywords
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/keywords/main.cpp b/src/boost/libs/log/example/keywords/main.cpp
new file mode 100644
index 000000000..5271f95ad
--- /dev/null
+++ b/src/boost/libs/log/example/keywords/main.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 01.12.2012
+ *
+ * \brief An example of using attribute keywords.
+ */
+
+// #define BOOST_LOG_USE_CHAR
+// #define BOOST_ALL_DYN_LINK 1
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <iostream>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+
+#include <boost/log/utility/setup/file.hpp>
+#include <boost/log/utility/setup/console.hpp>
+#include <boost/log/utility/setup/common_attributes.hpp>
+
+#include <boost/log/attributes/timer.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+
+#include <boost/log/sources/logger.hpp>
+
+#include <boost/log/support/date_time.hpp>
+
+namespace logging = boost::log;
+namespace sinks = boost::log::sinks;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+// Here we define our application severity levels.
+enum severity_level
+{
+ normal,
+ notification,
+ warning,
+ error,
+ critical
+};
+
+// The formatting logic for the severity level
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (
+ std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
+{
+ static const char* const str[] =
+ {
+ "normal",
+ "notification",
+ "warning",
+ "error",
+ "critical"
+ };
+ if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
+ strm << str[lvl];
+ else
+ strm << static_cast< int >(lvl);
+ return strm;
+}
+
+// Declare attribute keywords
+BOOST_LOG_ATTRIBUTE_KEYWORD(_severity, "Severity", severity_level)
+BOOST_LOG_ATTRIBUTE_KEYWORD(_timestamp, "TimeStamp", boost::posix_time::ptime)
+BOOST_LOG_ATTRIBUTE_KEYWORD(_uptime, "Uptime", attrs::timer::value_type)
+BOOST_LOG_ATTRIBUTE_KEYWORD(_scope, "Scope", attrs::named_scope::value_type)
+
+int main(int argc, char* argv[])
+{
+ // This is a simple tutorial/example of Boost.Log usage
+
+ // The first thing we have to do to get using the library is
+ // to set up the logging sinks - i.e. where the logs will be written to.
+ logging::add_console_log(std::clog, keywords::format = "%TimeStamp%: %_%");
+
+ // One can also use lambda expressions to setup filters and formatters
+ logging::add_file_log
+ (
+ "sample.log",
+ keywords::filter = _severity >= warning,
+ keywords::format = expr::stream
+ << expr::format_date_time(_timestamp, "%Y-%m-%d, %H:%M:%S.%f")
+ << " [" << expr::format_date_time(_uptime, "%O:%M:%S")
+ << "] [" << expr::format_named_scope(_scope, keywords::format = "%n (%f:%l)")
+ << "] <" << _severity
+ << "> " << expr::message
+/*
+ keywords::format = expr::format("%1% [%2%] [%3%] <%4%> %5%")
+ % expr::format_date_time(_timestamp, "%Y-%m-%d, %H:%M:%S.%f")
+ % expr::format_date_time(_uptime, "%O:%M:%S")
+ % expr::format_named_scope(_scope, keywords::format = "%n (%f:%l)")
+ % _severity
+ % expr::message
+*/
+ );
+
+ // Also let's add some commonly used attributes, like timestamp and record counter.
+ logging::add_common_attributes();
+ logging::core::get()->add_thread_attribute("Scope", attrs::named_scope());
+
+ BOOST_LOG_FUNCTION();
+
+ // Now our logs will be written both to the console and to the file.
+ // Let's do a quick test and output something. We have to create a logger for this.
+ src::logger lg;
+
+ // And output...
+ BOOST_LOG(lg) << "Hello, World!";
+
+ // Now, let's try logging with severity
+ src::severity_logger< severity_level > slg;
+
+ // Let's pretend we also want to profile our code, so add a special timer attribute.
+ slg.add_attribute("Uptime", attrs::timer());
+
+ BOOST_LOG_SEV(slg, normal) << "A normal severity message, will not pass to the file";
+ BOOST_LOG_SEV(slg, warning) << "A warning severity message, will pass to the file";
+ BOOST_LOG_SEV(slg, error) << "An error severity message, will pass to the file";
+
+ return 0;
+}
diff --git a/src/boost/libs/log/example/multiple_files/Jamfile.v2 b/src/boost/libs/log/example/multiple_files/Jamfile.v2
new file mode 100644
index 000000000..81e3e5dda
--- /dev/null
+++ b/src/boost/libs/log/example/multiple_files/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe multiple_files
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/multiple_files/main.cpp b/src/boost/libs/log/example/multiple_files/main.cpp
new file mode 100644
index 000000000..0a1ce47d5
--- /dev/null
+++ b/src/boost/libs/log/example/multiple_files/main.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 26.04.2008
+ *
+ * \brief This example shows how to perform logging to several files simultaneously,
+ * with files being created on an attribute value basis - thread identifier in this case.
+ * In the example the application creates a number of threads and registers thread
+ * identifiers as attributes. Every thread performs logging, and the sink separates
+ * log records from different threads into different files.
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/text_multifile_backend.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+enum
+{
+ THREAD_COUNT = 5,
+ LOG_RECORDS_TO_WRITE = 10
+};
+
+// Global logger declaration
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger_mt)
+
+// This function is executed in a separate thread
+void thread_foo()
+{
+ BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
+ for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
+ {
+ BOOST_LOG(my_logger::get()) << "Log record " << i;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Create a text file sink
+ typedef sinks::synchronous_sink< sinks::text_multifile_backend > file_sink;
+ shared_ptr< file_sink > sink(new file_sink);
+
+ // Set up how the file names will be generated
+ sink->locked_backend()->set_file_name_composer(sinks::file::as_file_name_composer(
+ expr::stream << "logs/" << expr::attr< boost::thread::id >("ThreadID") << ".log"));
+
+ // Set the log record formatter
+ sink->set_formatter
+ (
+ expr::format("%1%: [%2%] - %3%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::attr< boost::posix_time::ptime >("TimeStamp")
+ % expr::smessage
+ );
+
+ // Add it to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+
+ // Create threads and make some logs
+ boost::thread_group threads;
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ threads.create_thread(&thread_foo);
+
+ threads.join_all();
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/multiple_threads/Jamfile.v2 b/src/boost/libs/log/example/multiple_threads/Jamfile.v2
new file mode 100644
index 000000000..269a0cb79
--- /dev/null
+++ b/src/boost/libs/log/example/multiple_threads/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe multiple_threads
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/multiple_threads/main.cpp b/src/boost/libs/log/example/multiple_threads/main.cpp
new file mode 100644
index 000000000..2b005237f
--- /dev/null
+++ b/src/boost/libs/log/example/multiple_threads/main.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 10.06.2008
+ *
+ * \brief An example of logging in multiple threads.
+ * See the library tutorial for expanded comments on this code.
+ * It may also be worthwhile reading the Wiki requirements page:
+ * http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost.Logging
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/sources/logger.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+enum
+{
+ LOG_RECORDS_TO_WRITE = 10000,
+ THREAD_COUNT = 2
+};
+
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt)
+
+//! This function is executed in multiple threads
+void thread_fun(boost::barrier& bar)
+{
+ // Wait until all threads are created
+ bar.wait();
+
+ // Now, do some logging
+ for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
+ {
+ BOOST_LOG(test_lg::get()) << "Log record " << i;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Open a rotating text file
+ shared_ptr< std::ostream > strm(new std::ofstream("test.log"));
+ if (!strm->good())
+ throw std::runtime_error("Failed to open a text log file");
+
+ // Create a text file sink
+ shared_ptr< sinks::synchronous_sink< sinks::text_ostream_backend > > sink(
+ new sinks::synchronous_sink< sinks::text_ostream_backend >);
+
+ sink->locked_backend()->add_stream(strm);
+
+ sink->set_formatter
+ (
+ expr::format("%1%: [%2%] [%3%] - %4%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::attr< boost::posix_time::ptime >("TimeStamp")
+ % expr::attr< attrs::current_thread_id::value_type >("ThreadID")
+ % expr::smessage
+ );
+
+ // Add it to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+ logging::core::get()->add_global_attribute("ThreadID", attrs::current_thread_id());
+
+ // Create logging threads
+ boost::barrier bar(THREAD_COUNT);
+ boost::thread_group threads;
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ threads.create_thread(boost::bind(&thread_fun, boost::ref(bar)));
+
+ // Wait until all action ends
+ threads.join_all();
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/native_syslog/Jamfile.v2 b/src/boost/libs/log/example/native_syslog/Jamfile.v2
new file mode 100644
index 000000000..51ee1c2e1
--- /dev/null
+++ b/src/boost/libs/log/example/native_syslog/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe native_syslog
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/native_syslog/main.cpp b/src/boost/libs/log/example/native_syslog/main.cpp
new file mode 100644
index 000000000..d9814d527
--- /dev/null
+++ b/src/boost/libs/log/example/native_syslog/main.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 07.03.2009
+ *
+ * \brief An example of logging to a syslog server (syslogd, for example).
+ *
+ * The example shows how to initialize logging to a local syslog server.
+ * The code creates a sink that will use native syslog API to emit messages.
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <boost/config.hpp>
+#if !defined(BOOST_WINDOWS)
+#define BOOST_LOG_USE_NATIVE_SYSLOG
+#endif
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <boost/smart_ptr/shared_ptr.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/syslog_backend.hpp>
+
+#if defined(BOOST_LOG_USE_NATIVE_SYSLOG)
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+//! Define application-specific severity levels
+enum severity_levels
+{
+ normal,
+ warning,
+ error
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Create a syslog sink
+ shared_ptr< sinks::synchronous_sink< sinks::syslog_backend > > sink(
+ new sinks::synchronous_sink< sinks::syslog_backend >(
+ keywords::use_impl = sinks::syslog::native,
+ keywords::facility = sinks::syslog::local7));
+
+ sink->set_formatter
+ (
+ expr::format("native_syslog: %1%: %2%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::smessage
+ );
+
+ // We'll have to map our custom levels to the syslog levels
+ sinks::syslog::custom_severity_mapping< severity_levels > mapping("Severity");
+ mapping[normal] = sinks::syslog::info;
+ mapping[warning] = sinks::syslog::warning;
+ mapping[error] = sinks::syslog::critical;
+
+ sink->locked_backend()->set_severity_mapper(mapping);
+
+ // Add the sink to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+
+ // Do some logging
+ src::severity_logger< severity_levels > lg(keywords::severity = normal);
+ BOOST_LOG_SEV(lg, normal) << "A syslog record with normal level";
+ BOOST_LOG_SEV(lg, warning) << "A syslog record with warning level";
+ BOOST_LOG_SEV(lg, error) << "A syslog record with error level";
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
+
+#else // defined(BOOST_LOG_USE_NATIVE_SYSLOG)
+
+int main (int, char*[])
+{
+ std::cout << "Native syslog API is not supported on this platform" << std::endl;
+ return 0;
+}
+
+#endif // defined(BOOST_LOG_USE_NATIVE_SYSLOG)
diff --git a/src/boost/libs/log/example/rotating_file/Jamfile.v2 b/src/boost/libs/log/example/rotating_file/Jamfile.v2
new file mode 100644
index 000000000..f91c942eb
--- /dev/null
+++ b/src/boost/libs/log/example/rotating_file/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe rotating_file
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/rotating_file/main.cpp b/src/boost/libs/log/example/rotating_file/main.cpp
new file mode 100644
index 000000000..bb221f6eb
--- /dev/null
+++ b/src/boost/libs/log/example/rotating_file/main.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 26.04.2008
+ *
+ * \brief An example of logging into a rotating text file.
+ * See the library tutorial for expanded comments on this code.
+ * It may also be worthwhile reading the Wiki requirements page:
+ * http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost.Logging
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/text_file_backend.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+enum { LOG_RECORDS_TO_WRITE = 10000 };
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Create a text file sink
+ typedef sinks::synchronous_sink< sinks::text_file_backend > file_sink;
+ shared_ptr< file_sink > sink(new file_sink(
+ keywords::file_name = "file.log", // file name pattern
+ keywords::target_file_name = "%Y%m%d_%H%M%S_%5N.log", // file name pattern
+ keywords::rotation_size = 16384 // rotation size, in characters
+ ));
+
+ // Set up where the rotated files will be stored
+ sink->locked_backend()->set_file_collector(sinks::file::make_collector(
+ keywords::target = "logs", // where to store rotated files
+ keywords::max_size = 16 * 1024 * 1024, // maximum total size of the stored files, in bytes
+ keywords::min_free_space = 100 * 1024 * 1024, // minimum free space on the drive, in bytes
+ keywords::max_files = 512 // maximum number of stored files
+ ));
+
+ // Upon restart, scan the target directory for files matching the file_name pattern
+ sink->locked_backend()->scan_for_files();
+
+ sink->set_formatter
+ (
+ expr::format("%1%: [%2%] - %3%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::attr< boost::posix_time::ptime >("TimeStamp")
+ % expr::smessage
+ );
+
+ // Add it to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+
+ // Do some logging
+ src::logger lg;
+ for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i)
+ {
+ BOOST_LOG(lg) << "Some log record";
+ }
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/settings_file/Jamfile.v2 b/src/boost/libs/log/example/settings_file/Jamfile.v2
new file mode 100644
index 000000000..8459f7d76
--- /dev/null
+++ b/src/boost/libs/log/example/settings_file/Jamfile.v2
@@ -0,0 +1,58 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ ;
+
+exe settings_file
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/settings_file/main.cpp b/src/boost/libs/log/example/settings_file/main.cpp
new file mode 100644
index 000000000..eb4a13f92
--- /dev/null
+++ b/src/boost/libs/log/example/settings_file/main.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 26.04.2008
+ *
+ * \brief An example of initializing the library from a settings file.
+ * See the library tutorial for expanded comments on this code.
+ * It may also be worthwhile reading the Wiki requirements page:
+ * http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost.Logging
+ */
+
+// #define BOOST_ALL_DYN_LINK 1
+
+#include <exception>
+#include <iostream>
+#include <fstream>
+
+#include <boost/log/trivial.hpp>
+#include <boost/log/common.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/utility/setup/from_stream.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+
+void try_logging()
+{
+ BOOST_LOG_TRIVIAL(trace) << "This is a trace severity record";
+ BOOST_LOG_TRIVIAL(debug) << "This is a debug severity record";
+ BOOST_LOG_TRIVIAL(info) << "This is an info severity record";
+ BOOST_LOG_TRIVIAL(warning) << "This is a warning severity record";
+ BOOST_LOG_TRIVIAL(error) << "This is an error severity record";
+ BOOST_LOG_TRIVIAL(fatal) << "This is a fatal severity record";
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Open the file
+ std::ifstream settings("settings.txt");
+ if (!settings.is_open())
+ {
+ std::cout << "Could not open settings.txt file" << std::endl;
+ return 1;
+ }
+
+ // Read the settings and initialize logging library
+ logging::init_from_stream(settings);
+
+ // Add some attributes
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+
+ // Try logging
+ try_logging();
+
+ // Now enable tagging and try again
+ BOOST_LOG_SCOPED_THREAD_TAG("Tag", "TAGGED");
+ try_logging();
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/settings_file/settings.txt b/src/boost/libs/log/example/settings_file/settings.txt
new file mode 100644
index 000000000..c9fdb9db3
--- /dev/null
+++ b/src/boost/libs/log/example/settings_file/settings.txt
@@ -0,0 +1,25 @@
+#
+# Copyright Andrey Semashev 2007 - 2014.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+#
+
+[Core]
+
+Filter="%Severity% >= debug"
+
+
+[Sinks.1]
+
+Destination=Console
+Format="%TimeStamp% [%Severity%] *** %Message%"
+Filter="%Tag% | %Severity% > info"
+
+
+[Sinks.2]
+
+Destination=TextFile
+FileName=test.log
+AutoFlush=true
+Format="[%TimeStamp%] [%Severity%] [%Tag%] %Message%"
diff --git a/src/boost/libs/log/example/settings_file_custom_factories/Jamfile.v2 b/src/boost/libs/log/example/settings_file_custom_factories/Jamfile.v2
new file mode 100644
index 000000000..8032af9b6
--- /dev/null
+++ b/src/boost/libs/log/example/settings_file_custom_factories/Jamfile.v2
@@ -0,0 +1,58 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ ;
+
+exe settings_file_custom_factories
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/settings_file_custom_factories/main.cpp b/src/boost/libs/log/example/settings_file_custom_factories/main.cpp
new file mode 100644
index 000000000..a82d813eb
--- /dev/null
+++ b/src/boost/libs/log/example/settings_file_custom_factories/main.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 12.05.2010
+ *
+ * \brief An example of initializing the library from a settings file,
+ * with custom filter and formatter factories for attributes.
+ */
+
+// #define BOOST_ALL_DYN_LINK 1
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/common.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/setup/from_stream.hpp>
+#include <boost/log/utility/setup/common_attributes.hpp>
+#include <boost/log/utility/setup/filter_parser.hpp>
+#include <boost/log/utility/setup/formatter_parser.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+
+//! Enum for our custom severity levels
+enum severity_level
+{
+ normal,
+ notification,
+ warning,
+ error,
+ critical
+};
+
+//! Formatting operator for severity levels
+inline std::ostream& operator<< (std::ostream& strm, severity_level level)
+{
+ switch (level)
+ {
+ case normal:
+ strm << "normal";
+ break;
+ case notification:
+ strm << "notification";
+ break;
+ case warning:
+ strm << "warning";
+ break;
+ case error:
+ strm << "error";
+ break;
+ case critical:
+ strm << "critical";
+ break;
+ default:
+ strm << static_cast< int >(level);
+ break;
+ }
+
+ return strm;
+}
+
+//! Parsing operator for severity levels
+inline std::istream& operator>> (std::istream& strm, severity_level& level)
+{
+ if (strm.good())
+ {
+ std::string str;
+ strm >> str;
+ if (str == "normal")
+ level = normal;
+ else if (str == "notification")
+ level = notification;
+ else if (str == "warning")
+ level = warning;
+ else if (str == "error")
+ level = error;
+ else if (str == "critical")
+ level = critical;
+ else
+ strm.setstate(std::ios_base::failbit);
+ }
+
+ return strm;
+}
+
+//! Our custom formatter for the scope list
+struct scope_list_formatter
+{
+ typedef void result_type;
+ typedef attrs::named_scope::value_type scope_stack;
+
+ explicit scope_list_formatter(logging::attribute_name const& name) :
+ name_(name)
+ {
+ }
+ void operator()(logging::record_view const& rec, logging::formatting_ostream& strm) const
+ {
+ // We need to acquire the attribute value from the log record
+ logging::visit< scope_stack >
+ (
+ name_,
+ rec.attribute_values(),
+ boost::bind(&scope_list_formatter::format, boost::placeholders::_1, boost::ref(strm))
+ );
+ }
+
+private:
+ //! This is where our custom formatting takes place
+ static void format(scope_stack const& scopes, logging::formatting_ostream& strm)
+ {
+ scope_stack::const_iterator it = scopes.begin(), end = scopes.end();
+ for (; it != end; ++it)
+ {
+ strm << "\t" << it->scope_name << " [" << it->file_name << ":" << it->line << "]\n";
+ }
+ }
+
+private:
+ logging::attribute_name name_;
+};
+
+class my_scopes_formatter_factory :
+ public logging::formatter_factory< char >
+{
+public:
+ /*!
+ * This function creates a formatter for the MyScopes attribute.
+ * It effectively associates the attribute with the scope_list_formatter class
+ */
+ formatter_type create_formatter(
+ logging::attribute_name const& attr_name, args_map const& args)
+ {
+ return formatter_type(scope_list_formatter(attr_name));
+ }
+};
+
+//! The function initializes the logging library
+void init_logging()
+{
+ // First thing - register the custom formatter for MyScopes
+ logging::register_formatter_factory("MyScopes", boost::make_shared< my_scopes_formatter_factory >());
+
+ // Also register filter and formatter factories for our custom severity level enum. Since our operator<< and operator>> implement
+ // all required behavior, simple factories provided by Boost.Log will do.
+ logging::register_simple_filter_factory< severity_level >("Severity");
+ logging::register_simple_formatter_factory< severity_level, char >("Severity");
+
+ // Then load the settings from the file
+ std::ifstream settings("settings.txt");
+ if (!settings.is_open())
+ throw std::runtime_error("Could not open settings.txt file");
+ logging::init_from_stream(settings);
+
+ // Add some attributes. Note that severity level will be provided by the logger, so we don't need to add it here.
+ logging::add_common_attributes();
+
+ logging::core::get()->add_global_attribute("MyScopes", attrs::named_scope());
+}
+
+//! Global logger, which we will use to write log messages
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::severity_logger< severity_level >)
+
+//! The function tests logging
+void try_logging()
+{
+ BOOST_LOG_FUNCTION();
+
+ src::severity_logger< severity_level >& lg = test_lg::get();
+
+ BOOST_LOG_SEV(lg, critical) << "This is a critical severity record";
+
+ BOOST_LOG_NAMED_SCOPE("random name");
+ BOOST_LOG_SEV(lg, error) << "This is a error severity record";
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ init_logging();
+ try_logging();
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/boost/libs/log/example/settings_file_custom_factories/settings.txt b/src/boost/libs/log/example/settings_file_custom_factories/settings.txt
new file mode 100644
index 000000000..98d8d7fd6
--- /dev/null
+++ b/src/boost/libs/log/example/settings_file_custom_factories/settings.txt
@@ -0,0 +1,14 @@
+#
+# Copyright Andrey Semashev 2007 - 2014.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+#
+
+[Sinks.TextFileSettings]
+Destination=TextFile
+FileName=test.log
+AutoFlush=true
+Filter="%Severity% > normal"
+Format="[%TimeStamp%] [%Severity%]\n%MyScopes%\n\t:: %Message%"
+Asynchronous=false
diff --git a/src/boost/libs/log/example/syslog/Jamfile.v2 b/src/boost/libs/log/example/syslog/Jamfile.v2
new file mode 100644
index 000000000..a4d1a9710
--- /dev/null
+++ b/src/boost/libs/log/example/syslog/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/thread//boost_thread
+ <threading>multi
+ ;
+
+exe syslog
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/syslog/main.cpp b/src/boost/libs/log/example/syslog/main.cpp
new file mode 100644
index 000000000..18db09195
--- /dev/null
+++ b/src/boost/libs/log/example/syslog/main.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 07.03.2009
+ *
+ * \brief An example of logging to a syslog server (syslogd, for example).
+ *
+ * The example shows how to initialize logging to a remote syslog server.
+ * The code creates a sink that will send syslog messages to local port 514.
+ */
+
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <boost/config.hpp>
+#if !defined(BOOST_WINDOWS)
+#define BOOST_LOG_USE_NATIVE_SYSLOG
+#endif
+
+#include <stdexcept>
+#include <string>
+#include <iostream>
+#include <boost/smart_ptr/shared_ptr.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/syslog_backend.hpp>
+
+namespace logging = boost::log;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace sinks = boost::log::sinks;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+using boost::shared_ptr;
+
+//! Define application-specific severity levels
+enum severity_levels
+{
+ normal,
+ warning,
+ error
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ // Create a syslog sink
+ shared_ptr< sinks::synchronous_sink< sinks::syslog_backend > > sink(
+ new sinks::synchronous_sink< sinks::syslog_backend >());
+
+ sink->set_formatter
+ (
+ expr::format("syslog.exe: %1%: %2%")
+ % expr::attr< unsigned int >("RecordID")
+ % expr::smessage
+ );
+
+ // We'll have to map our custom levels to the syslog levels
+ sinks::syslog::custom_severity_mapping< severity_levels > mapping("Severity");
+ mapping[normal] = sinks::syslog::info;
+ mapping[warning] = sinks::syslog::warning;
+ mapping[error] = sinks::syslog::critical;
+
+ sink->locked_backend()->set_severity_mapper(mapping);
+
+#if !defined(BOOST_LOG_NO_ASIO)
+ // Set the remote address to sent syslog messages to
+ sink->locked_backend()->set_target_address("localhost");
+#endif
+
+ // Add the sink to the core
+ logging::core::get()->add_sink(sink);
+
+ // Add some attributes too
+ logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
+
+ // Do some logging
+ src::severity_logger< severity_levels > lg(keywords::severity = normal);
+ BOOST_LOG_SEV(lg, normal) << "A syslog record with normal level";
+ BOOST_LOG_SEV(lg, warning) << "A syslog record with warning level";
+ BOOST_LOG_SEV(lg, error) << "A syslog record with error level";
+
+ return 0;
+ }
+ catch (std::exception& e)
+ {
+ std::cout << "FAILURE: " << e.what() << std::endl;
+ return 1;
+ }
+}
diff --git a/src/boost/libs/log/example/trivial/Jamfile.v2 b/src/boost/libs/log/example/trivial/Jamfile.v2
new file mode 100644
index 000000000..3a02bf383
--- /dev/null
+++ b/src/boost/libs/log/example/trivial/Jamfile.v2
@@ -0,0 +1,57 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ ;
+
+exe trivial
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/trivial/main.cpp b/src/boost/libs/log/example/trivial/main.cpp
new file mode 100644
index 000000000..a59adb3b8
--- /dev/null
+++ b/src/boost/libs/log/example/trivial/main.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 07.11.2009
+ *
+ * \brief An example of trivial logging.
+ */
+
+// #define BOOST_ALL_DYN_LINK 1
+// #define BOOST_LOG_DYN_LINK 1
+
+#include <boost/log/trivial.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/expressions.hpp>
+
+int main(int argc, char* argv[])
+{
+ // Trivial logging: all log records are written into a file
+ BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
+ BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
+ BOOST_LOG_TRIVIAL(info) << "An informational severity message";
+ BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
+ BOOST_LOG_TRIVIAL(error) << "An error severity message";
+ BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
+
+ // Filtering can also be applied
+ using namespace boost::log;
+
+ core::get()->set_filter
+ (
+ trivial::severity >= trivial::info
+ );
+
+ // Now the first two lines will not pass the filter
+ BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
+ BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
+ BOOST_LOG_TRIVIAL(info) << "An informational severity message";
+ BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
+ BOOST_LOG_TRIVIAL(error) << "An error severity message";
+ BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
+
+ return 0;
+}
diff --git a/src/boost/libs/log/example/wide_char/Jamfile.v2 b/src/boost/libs/log/example/wide_char/Jamfile.v2
new file mode 100644
index 000000000..7a3c518ed
--- /dev/null
+++ b/src/boost/libs/log/example/wide_char/Jamfile.v2
@@ -0,0 +1,62 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+import ../../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <link>shared:<define>BOOST_ALL_DYN_LINK
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/locale//boost_locale
+ <library>/boost/thread//boost_thread
+ <threading>multi
+
+ # does not build on VxWorks due to lack of boost::locale support
+ <target-os>vxworks:<build>no
+ ;
+
+exe wide_char
+ : main.cpp
+ ;
diff --git a/src/boost/libs/log/example/wide_char/main.cpp b/src/boost/libs/log/example/wide_char/main.cpp
new file mode 100644
index 000000000..0c52afaa6
--- /dev/null
+++ b/src/boost/libs/log/example/wide_char/main.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file main.cpp
+ * \author Andrey Semashev
+ * \date 01.12.2012
+ *
+ * \brief An example of wide character logging.
+ */
+
+#include <iostream>
+#include <boost/locale/generator.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/utility/setup/file.hpp>
+#include <boost/log/utility/setup/console.hpp>
+#include <boost/log/utility/setup/common_attributes.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/support/date_time.hpp>
+
+namespace logging = boost::log;
+namespace sinks = boost::log::sinks;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace expr = boost::log::expressions;
+namespace keywords = boost::log::keywords;
+
+//[ example_wide_char_severity_level_definition
+enum severity_level
+{
+ normal,
+ notification,
+ warning,
+ error,
+ critical
+};
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (
+ std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl)
+{
+ static const char* const str[] =
+ {
+ "normal",
+ "notification",
+ "warning",
+ "error",
+ "critical"
+ };
+ if (static_cast< std::size_t >(lvl) < (sizeof(str) / sizeof(*str)))
+ strm << str[lvl];
+ else
+ strm << static_cast< int >(lvl);
+ return strm;
+}
+//]
+
+//[ example_wide_char_logging_initialization
+// Declare attribute keywords
+BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
+BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
+
+void init_logging()
+{
+ boost::shared_ptr< sinks::synchronous_sink< sinks::text_file_backend > > sink = logging::add_file_log
+ (
+ "sample.log",
+ keywords::format = expr::stream
+ << expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f")
+ << " <" << severity.or_default(normal)
+ << "> " << expr::message
+ );
+
+ // The sink will perform character code conversion as needed, according to the locale set with imbue()
+ std::locale loc = boost::locale::generator()("en_US.UTF-8");
+ sink->imbue(loc);
+
+ // Let's add some commonly used attributes, like timestamp and record counter.
+ logging::add_common_attributes();
+}
+//]
+
+//[ example_wide_char_logging
+void test_narrow_char_logging()
+{
+ // Narrow character logging still works
+ src::logger lg;
+ BOOST_LOG(lg) << "Hello, World! This is a narrow character message.";
+}
+
+void test_wide_char_logging()
+{
+ src::wlogger lg;
+ BOOST_LOG(lg) << L"Hello, World! This is a wide character message.";
+
+ // National characters are also supported
+ const wchar_t national_chars[] = { 0x041f, 0x0440, 0x0438, 0x0432, 0x0435, 0x0442, L',', L' ', 0x043c, 0x0438, 0x0440, L'!', 0 };
+ BOOST_LOG(lg) << national_chars;
+
+ // Now, let's try logging with severity
+ src::wseverity_logger< severity_level > slg;
+ BOOST_LOG_SEV(slg, normal) << L"A normal severity message, will not pass to the file";
+ BOOST_LOG_SEV(slg, warning) << L"A warning severity message, will pass to the file";
+ BOOST_LOG_SEV(slg, error) << L"An error severity message, will pass to the file";
+}
+//]
+
+int main(int argc, char* argv[])
+{
+ init_logging();
+ test_narrow_char_logging();
+ test_wide_char_logging();
+
+ return 0;
+}
diff --git a/src/boost/libs/log/index.html b/src/boost/libs/log/index.html
new file mode 100644
index 000000000..3a9bf94cd
--- /dev/null
+++ b/src/boost/libs/log/index.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
+</head>
+<body>
+Automatic redirection failed, please go to
+<a href="doc/html/index.html">doc/html/index.html</a> &nbsp;<hr>
+<p>&copy; Copyright Andrey Semashev, 2013</p>
+<p>Distributed under the Boost Software License, Version 1.0. (See accompanying
+file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy
+at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p>
+</body>
+</html>
diff --git a/src/boost/libs/log/meta/libraries.json b/src/boost/libs/log/meta/libraries.json
new file mode 100644
index 000000000..08e82d14e
--- /dev/null
+++ b/src/boost/libs/log/meta/libraries.json
@@ -0,0 +1,14 @@
+{
+ "key": "log",
+ "name": "Log",
+ "authors": [
+ "Andrey Semashev"
+ ],
+ "description": "Logging library.",
+ "category": [
+ "Miscellaneous"
+ ],
+ "maintainers": [
+ "Andrey Semashev <andrey.semashev -at- gmail.com>"
+ ]
+}
diff --git a/src/boost/libs/log/src/alignment_gap_between.hpp b/src/boost/libs/log/src/alignment_gap_between.hpp
new file mode 100644
index 000000000..cc16a9f12
--- /dev/null
+++ b/src/boost/libs/log/src/alignment_gap_between.hpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file alignment_gap_between.hpp
+ * \author Andrey Semashev
+ * \date 20.11.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_ALIGNMENT_GAP_BETWEEN_HPP_INCLUDED_
+#define BOOST_LOG_ALIGNMENT_GAP_BETWEEN_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! The metafunction computes the minimal gap between objects t1 and t2 of types T1 and T2
+//! that would be needed to maintain the alignment of t2 if it's placed right after t1
+template< typename T1, typename T2 >
+struct alignment_gap_between
+{
+ enum _
+ {
+ T2_alignment = boost::alignment_of< T2 >::value,
+ tail_size = sizeof(T1) % T2_alignment,
+ value = tail_size > 0 ? T2_alignment - tail_size : 0
+ };
+};
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_ALIGNMENT_GAP_BETWEEN_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/attribute_name.cpp b/src/boost/libs/log/src/attribute_name.cpp
new file mode 100644
index 000000000..a804fed82
--- /dev/null
+++ b/src/boost/libs/log/src/attribute_name.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attribute_name.cpp
+ * \author Andrey Semashev
+ * \date 28.06.2010
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstring>
+#include <deque>
+#include <ostream>
+#include <stdexcept>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/intrusive/set.hpp>
+#include <boost/intrusive/set_hook.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/log/detail/locks.hpp>
+#include <boost/log/detail/light_rw_mutex.hpp>
+#endif
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+//! A global container of all known attribute names
+class attribute_name::repository :
+ public log::aux::lazy_singleton<
+ repository,
+ shared_ptr< repository >
+ >
+{
+ typedef log::aux::lazy_singleton<
+ repository,
+ shared_ptr< repository >
+ > base_type;
+
+#if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
+ friend class log::aux::lazy_singleton<
+ repository,
+ shared_ptr< repository >
+ >;
+#else
+ friend class base_type;
+#endif
+
+public:
+ // Import types from the basic_attribute_name template
+ typedef attribute_name::id_type id_type;
+ typedef attribute_name::string_type string_type;
+
+ //! A base hook for arranging the attribute names into a set
+ typedef intrusive::set_base_hook<
+ intrusive::link_mode< intrusive::safe_link >,
+ intrusive::optimize_size< true >
+ > node_by_name_hook;
+
+private:
+ //! An element of the attribute names repository
+ struct node :
+ public node_by_name_hook
+ {
+ typedef node_by_name_hook base_type;
+
+ public:
+ //! A predicate for name-based ordering
+ struct order_by_name
+ {
+ typedef bool result_type;
+
+ bool operator() (node const& left, node const& right) const
+ {
+ return std::strcmp(left.m_name.c_str(), right.m_name.c_str()) < 0;
+ }
+ bool operator() (node const& left, const char* right) const
+ {
+ return std::strcmp(left.m_name.c_str(), right) < 0;
+ }
+ bool operator() (const char* left, node const& right) const
+ {
+ return std::strcmp(left, right.m_name.c_str()) < 0;
+ }
+ };
+
+ public:
+ id_type m_id;
+ string_type m_name;
+
+ public:
+ node() : m_id(0), m_name() {}
+ node(id_type i, string_type const& n) :
+ base_type(),
+ m_id(i),
+ m_name(n)
+ {
+ }
+ node(node const& that) :
+ base_type(),
+ m_id(that.m_id),
+ m_name(that.m_name)
+ {
+ }
+ };
+
+ //! The container that provides storage for nodes
+ typedef std::deque< node > node_list;
+ //! The container that provides name-based lookup
+ typedef intrusive::set<
+ node,
+ intrusive::base_hook< node_by_name_hook >,
+ intrusive::constant_time_size< false >,
+ intrusive::compare< node::order_by_name >
+ > node_set;
+
+private:
+#if !defined(BOOST_LOG_NO_THREADS)
+ typedef log::aux::light_rw_mutex mutex_type;
+ log::aux::light_rw_mutex m_Mutex;
+#endif
+ node_list m_NodeList;
+ node_set m_NodeSet;
+
+public:
+ //! Converts attribute name string to id
+ id_type get_id_from_string(const char* name)
+ {
+ BOOST_ASSERT(name != NULL);
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ {
+ // Do a non-blocking lookup first
+ log::aux::shared_lock_guard< mutex_type > _(m_Mutex);
+ node_set::const_iterator it =
+ m_NodeSet.find(name, node::order_by_name());
+ if (it != m_NodeSet.end())
+ return it->m_id;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+ BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex_type > _(m_Mutex);)
+ node_set::iterator it =
+ m_NodeSet.lower_bound(name, node::order_by_name());
+ if (it == m_NodeSet.end() || it->m_name != name)
+ {
+ const std::size_t new_id = m_NodeList.size();
+ if (new_id >= static_cast< id_type >(attribute_name::uninitialized))
+ BOOST_THROW_EXCEPTION(limitation_error("Too many log attribute names"));
+
+ m_NodeList.push_back(node(static_cast< id_type >(new_id), name));
+ it = m_NodeSet.insert(it, m_NodeList.back());
+ }
+ return it->m_id;
+ }
+
+ //! Converts id to the attribute name string
+ string_type const& get_string_from_id(id_type id)
+ {
+ BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< mutex_type > _(m_Mutex);)
+ BOOST_ASSERT(id < m_NodeList.size());
+ return m_NodeList[id].m_name;
+ }
+
+private:
+ //! Initializes the singleton instance
+ static void init_instance()
+ {
+ base_type::get_instance() = boost::make_shared< repository >();
+ }
+};
+
+BOOST_LOG_API attribute_name::id_type
+attribute_name::get_id_from_string(const char* name)
+{
+ return repository::get()->get_id_from_string(name);
+}
+
+BOOST_LOG_API attribute_name::string_type const&
+attribute_name::get_string_from_id(id_type id)
+{
+ return repository::get()->get_string_from_id(id);
+}
+
+template< typename CharT, typename TraitsT >
+BOOST_LOG_API std::basic_ostream< CharT, TraitsT >& operator<< (
+ std::basic_ostream< CharT, TraitsT >& strm,
+ attribute_name const& name)
+{
+ if (!!name)
+ strm << name.string().c_str();
+ else
+ strm << "[uninitialized]";
+ return strm;
+}
+
+// Explicitly instantiate attribute name implementation
+#ifdef BOOST_LOG_USE_CHAR
+template BOOST_LOG_API std::basic_ostream< char, std::char_traits< char > >&
+ operator<< < char, std::char_traits< char > >(
+ std::basic_ostream< char, std::char_traits< char > >& strm,
+ attribute_name const& name);
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template BOOST_LOG_API std::basic_ostream< wchar_t, std::char_traits< wchar_t > >&
+ operator<< < wchar_t, std::char_traits< wchar_t > >(
+ std::basic_ostream< wchar_t, std::char_traits< wchar_t > >& strm,
+ attribute_name const& name);
+#endif
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/attribute_set.cpp b/src/boost/libs/log/src/attribute_set.cpp
new file mode 100644
index 000000000..27379e134
--- /dev/null
+++ b/src/boost/libs/log/src/attribute_set.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attribute_set.cpp
+ * \author Andrey Semashev
+ * \date 19.04.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <deque>
+#include <boost/assert.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/link_mode.hpp>
+#include <boost/intrusive/derivation_value_traits.hpp>
+#include <boost/log/attributes/attribute.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include "attribute_set_impl.hpp"
+#include "stateless_allocator.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_LOG_API void* attribute::impl::operator new (std::size_t size)
+{
+ return aux::stateless_allocator< unsigned char >().allocate(size);
+}
+
+BOOST_LOG_API void attribute::impl::operator delete (void* p, std::size_t size) BOOST_NOEXCEPT
+{
+ aux::stateless_allocator< unsigned char >().deallocate(static_cast< unsigned char* >(p), size);
+}
+
+inline attribute_set::node_base::node_base() :
+ m_pPrev(NULL),
+ m_pNext(NULL)
+{
+}
+
+inline attribute_set::node::node(key_type const& key, mapped_type const& data) :
+ node_base(),
+ m_Value(key, data)
+{
+}
+
+//! Default constructor
+BOOST_LOG_API attribute_set::attribute_set() :
+ m_pImpl(new implementation())
+{
+}
+
+//! Copy constructor
+BOOST_LOG_API attribute_set::attribute_set(attribute_set const& that) :
+ m_pImpl(new implementation(*that.m_pImpl))
+{
+}
+
+//! Destructor
+BOOST_LOG_API attribute_set::~attribute_set() BOOST_NOEXCEPT
+{
+ delete m_pImpl;
+}
+
+// Iterator generators
+BOOST_LOG_API attribute_set::iterator attribute_set::begin() BOOST_NOEXCEPT
+{
+ return m_pImpl->begin();
+}
+BOOST_LOG_API attribute_set::iterator attribute_set::end() BOOST_NOEXCEPT
+{
+ return m_pImpl->end();
+}
+BOOST_LOG_API attribute_set::const_iterator attribute_set::begin() const BOOST_NOEXCEPT
+{
+ return const_iterator(m_pImpl->begin());
+}
+BOOST_LOG_API attribute_set::const_iterator attribute_set::end() const BOOST_NOEXCEPT
+{
+ return const_iterator(m_pImpl->end());
+}
+
+//! The method returns number of elements in the container
+BOOST_LOG_API attribute_set::size_type attribute_set::size() const BOOST_NOEXCEPT
+{
+ return m_pImpl->size();
+}
+
+//! Insertion method
+BOOST_LOG_API std::pair< attribute_set::iterator, bool >
+attribute_set::insert(key_type key, mapped_type const& data)
+{
+ return m_pImpl->insert(key, data);
+}
+
+//! The method erases all attributes with the specified name
+BOOST_LOG_API attribute_set::size_type attribute_set::erase(key_type key) BOOST_NOEXCEPT
+{
+ iterator it = m_pImpl->find(key);
+ if (it != end())
+ {
+ m_pImpl->erase(it);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+//! The method erases the specified attribute
+BOOST_LOG_API void attribute_set::erase(iterator it) BOOST_NOEXCEPT
+{
+ m_pImpl->erase(it);
+}
+
+//! The method erases all attributes within the specified range
+BOOST_LOG_API void attribute_set::erase(iterator begin, iterator end) BOOST_NOEXCEPT
+{
+ while (begin != end)
+ {
+ m_pImpl->erase(begin++);
+ }
+}
+
+//! The method clears the container
+BOOST_LOG_API void attribute_set::clear() BOOST_NOEXCEPT
+{
+ m_pImpl->clear();
+}
+
+//! Internal lookup implementation
+BOOST_LOG_API attribute_set::iterator attribute_set::find(key_type key) BOOST_NOEXCEPT
+{
+ return m_pImpl->find(key);
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/attribute_set_impl.hpp b/src/boost/libs/log/src/attribute_set_impl.hpp
new file mode 100644
index 000000000..044a8e764
--- /dev/null
+++ b/src/boost/libs/log/src/attribute_set_impl.hpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright Andrey Semashev 2007 - 2020.
+ * 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)
+ */
+/*!
+ * \file attribute_set_impl.hpp
+ * \author Andrey Semashev
+ * \date 03.07.2010
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_ATTRIBUTE_SET_IMPL_HPP_INCLUDED_
+#define BOOST_LOG_ATTRIBUTE_SET_IMPL_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <new>
+#include <memory>
+#include <limits>
+#include <utility>
+#include <algorithm>
+#include <cstddef>
+#include <boost/assert.hpp>
+#include <boost/array.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/link_mode.hpp>
+#include <boost/intrusive/derivation_value_traits.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/detail/allocator_traits.hpp>
+#include <boost/log/detail/header.hpp>
+
+#ifndef BOOST_LOG_HASH_TABLE_SIZE_LOG
+// Hash table size will be 2 ^ this value
+#define BOOST_LOG_HASH_TABLE_SIZE_LOG 4
+#endif
+
+#ifndef BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE
+// Maximum pool size that each attribute set maintains
+#define BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE 8
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+//! A simple pooling allocator
+template< typename T >
+class pool_allocator :
+ public std::allocator< T >
+{
+public:
+ template< typename U >
+ struct rebind
+ {
+ typedef pool_allocator< U > other;
+ };
+
+ typedef std::allocator< T > base_type;
+
+#if BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE > 0
+
+ typedef typename log::aux::allocator_traits< base_type >::value_type value_type;
+ typedef typename log::aux::allocator_traits< base_type >::size_type size_type;
+ typedef typename log::aux::allocator_traits< base_type >::difference_type difference_type;
+ typedef typename log::aux::allocator_traits< base_type >::pointer pointer;
+ typedef typename log::aux::allocator_traits< base_type >::const_pointer const_pointer;
+ typedef value_type& reference;
+ typedef value_type const& const_reference;
+
+private:
+ array< pointer, BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE > m_Pool;
+ size_type m_PooledCount;
+
+public:
+ pool_allocator() : m_PooledCount(0)
+ {
+ }
+
+ pool_allocator(pool_allocator const& that) :
+ base_type(static_cast< base_type const& >(that)),
+ m_PooledCount(0)
+ {
+ }
+
+ template< typename U >
+ pool_allocator(pool_allocator< U > const& that) :
+ base_type(static_cast< typename pool_allocator< U >::base_type const& >(that)),
+ m_PooledCount(0)
+ {
+ }
+
+ ~pool_allocator()
+ {
+ for (size_type i = 0; i < m_PooledCount; ++i)
+ {
+ log::aux::allocator_traits< base_type >::deallocate(*static_cast< base_type* >(this), m_Pool[i], 1);
+ }
+ }
+
+ pool_allocator& operator= (pool_allocator const& that)
+ {
+ base_type::operator= (static_cast< base_type const& >(that));
+ return *this;
+ }
+
+ template< typename U >
+ pool_allocator& operator= (pool_allocator< U > const& that)
+ {
+ base_type::operator= (
+ static_cast< typename pool_allocator< U >::base_type const& >(that));
+ return *this;
+ }
+
+ pointer allocate(size_type n, const void* hint = NULL)
+ {
+ if (BOOST_LIKELY(m_PooledCount > 0))
+ {
+ --m_PooledCount;
+ return m_Pool[m_PooledCount];
+ }
+ else
+ {
+ return log::aux::allocator_traits< base_type >::allocate(*static_cast< base_type* >(this), n, hint);
+ }
+ }
+
+ void deallocate(pointer p, size_type n)
+ {
+ if (BOOST_LIKELY(m_PooledCount < m_Pool.size()))
+ {
+ m_Pool[m_PooledCount] = p;
+ ++m_PooledCount;
+ }
+ else
+ {
+ log::aux::allocator_traits< base_type >::deallocate(*static_cast< base_type* >(this), p, n);
+ }
+ }
+
+#else
+
+ template< typename U >
+ pool_allocator(pool_allocator< U > const& that) :
+ base_type(static_cast< typename pool_allocator< U >::base_type const& >(that))
+ {
+ }
+
+#endif // BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE > 0
+};
+
+//! Attribute set implementation
+struct attribute_set::implementation
+{
+public:
+ //! Attribute name identifier type
+ typedef key_type::id_type id_type;
+
+ //! Allocator type
+ typedef pool_allocator< node > node_allocator;
+
+ //! Node base class traits for the intrusive list
+ struct node_traits
+ {
+ typedef node_base node;
+ typedef node* node_ptr;
+ typedef node const* const_node_ptr;
+ static node* get_next(const node* n) { return n->m_pNext; }
+ static void set_next(node* n, node* next) { n->m_pNext = next; }
+ static node* get_previous(const node* n) { return n->m_pPrev; }
+ static void set_previous(node* n, node* prev) { n->m_pPrev = prev; }
+ };
+
+ //! Contained node traits for the intrusive list
+ typedef intrusive::derivation_value_traits<
+ node,
+ node_traits,
+ intrusive::normal_link
+ > value_traits;
+
+ //! The container that allows to iterate through elements
+ typedef intrusive::list<
+ node,
+ intrusive::value_traits< value_traits >,
+ intrusive::constant_time_size< true >
+ > node_list;
+
+ //! A hash table bucket
+ struct bucket
+ {
+ //! Points to the first element in the bucket
+ node* first;
+ //! Points to the last element in the bucket (not the one after the last!)
+ node* last;
+
+ bucket() : first(NULL), last(NULL) {}
+ };
+
+ //! A list of buckets
+ typedef boost::array< bucket, 1u << BOOST_LOG_HASH_TABLE_SIZE_LOG > buckets;
+
+ //! Cleanup function object used to erase elements from the container
+ struct disposer
+ {
+ typedef void result_type;
+
+ explicit disposer(node_allocator& alloc) : m_Allocator(alloc)
+ {
+ }
+ void operator() (node* p) const
+ {
+ p->~node();
+ m_Allocator.deallocate(p, 1);
+ }
+
+ private:
+ node_allocator& m_Allocator;
+ };
+
+private:
+ //! List of nodes
+ node_list m_Nodes;
+ //! Node allocator
+ node_allocator m_Allocator;
+ //! Hash table buckets
+ buckets m_Buckets;
+
+public:
+ implementation()
+ {
+ }
+
+ implementation(implementation const& that) : m_Allocator(that.m_Allocator)
+ {
+ node_list::const_iterator it = that.m_Nodes.begin(), end = that.m_Nodes.end();
+ for (; it != end; ++it)
+ {
+ node* const n = m_Allocator.allocate(1, NULL);
+ new (n) node(it->m_Value.first, it->m_Value.second);
+ m_Nodes.push_back(*n);
+
+ bucket& b = get_bucket(it->m_Value.first.id());
+ if (b.first == NULL)
+ b.first = b.last = n;
+ else
+ b.last = n;
+ }
+ }
+
+ ~implementation()
+ {
+ m_Nodes.clear_and_dispose(disposer(m_Allocator));
+ }
+
+ size_type size() const { return m_Nodes.size(); }
+ iterator begin() { return iterator(m_Nodes.begin().pointed_node()); }
+ iterator end() { return iterator(m_Nodes.end().pointed_node()); }
+
+ void clear()
+ {
+ m_Nodes.clear_and_dispose(disposer(m_Allocator));
+ std::fill_n(m_Buckets.begin(), m_Buckets.size(), bucket());
+ }
+
+ std::pair< iterator, bool > insert(key_type key, mapped_type const& data)
+ {
+ BOOST_ASSERT(!!key);
+
+ bucket& b = get_bucket(key.id());
+ node* p = b.first;
+ if (p)
+ {
+ // The bucket is not empty, search among the elements
+ p = find_in_bucket(key, b);
+ if (p->m_Value.first == key)
+ return std::make_pair(iterator(p), false);
+ }
+
+ node* const n = m_Allocator.allocate(1, NULL);
+ new (n) node(key, data);
+
+ node_list::iterator it;
+ if (b.first == NULL)
+ {
+ // The bucket is empty
+ b.first = b.last = n;
+ it = m_Nodes.end();
+ }
+ else if (p == b.last && key.id() > p->m_Value.first.id())
+ {
+ // The new element should become the last element of the bucket
+ it = m_Nodes.iterator_to(*p);
+ ++it;
+ b.last = n;
+ }
+ else if (p == b.first)
+ {
+ // The new element should become the first element of the bucket
+ it = m_Nodes.iterator_to(*p);
+ b.first = n;
+ }
+ else
+ {
+ // The new element should be within the bucket
+ it = m_Nodes.iterator_to(*p);
+ }
+
+ m_Nodes.insert(it, *n);
+
+ return std::make_pair(iterator(n), true);
+ }
+
+ void erase(iterator it)
+ {
+ typedef node_list::node_traits node_traits;
+ typedef node_list::value_traits value_traits;
+
+ node* p = static_cast< node* >(it.base());
+
+ // Adjust bucket boundaries, if needed
+ bucket& b = get_bucket(it->first.id());
+ if (p == b.first)
+ {
+ if (p == b.last)
+ {
+ // The erased element is the only one in the bucket
+ b.first = b.last = NULL;
+ }
+ else
+ {
+ // The erased element is the first one in the bucket
+ b.first = value_traits::to_value_ptr(node_traits::get_next(b.first));
+ }
+ }
+ else if (p == b.last)
+ {
+ // The erased element is the last one in the bucket
+ b.last = value_traits::to_value_ptr(node_traits::get_previous(b.last));
+ }
+
+ m_Nodes.erase_and_dispose(m_Nodes.iterator_to(*p), disposer(m_Allocator));
+ }
+
+ iterator find(key_type key)
+ {
+ bucket& b = get_bucket(key.id());
+ node* p = b.first;
+ if (p)
+ {
+ // The bucket is not empty, search among the elements
+ p = find_in_bucket(key, b);
+ if (p->m_Value.first == key)
+ return iterator(p);
+ }
+
+ return end();
+ }
+
+private:
+ implementation& operator= (implementation const&);
+
+ //! The function returns a bucket for the specified element
+ bucket& get_bucket(id_type id)
+ {
+ return m_Buckets[id & (buckets::static_size - 1)];
+ }
+
+ //! Attempts to find an element with the specified key in the bucket
+ node* find_in_bucket(key_type key, bucket const& b)
+ {
+ typedef node_list::node_traits node_traits;
+ typedef node_list::value_traits value_traits;
+
+ // All elements within the bucket are sorted to speedup the search.
+ node* p = b.first;
+ while (p != b.last && p->m_Value.first.id() < key.id())
+ {
+ p = value_traits::to_value_ptr(node_traits::get_next(p));
+ }
+
+ return p;
+ }
+};
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_ATTRIBUTE_SET_IMPL_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/attribute_value_set.cpp b/src/boost/libs/log/src/attribute_value_set.cpp
new file mode 100644
index 000000000..14d9752a7
--- /dev/null
+++ b/src/boost/libs/log/src/attribute_value_set.cpp
@@ -0,0 +1,570 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attribute_value_set.cpp
+ * \author Andrey Semashev
+ * \date 19.04.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <new>
+#include <memory>
+#include <boost/array.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/link_mode.hpp>
+#include <boost/intrusive/derivation_value_traits.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/attributes/attribute_value.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include "alignment_gap_between.hpp"
+#include "attribute_set_impl.hpp"
+#include "stateless_allocator.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_FORCEINLINE attribute_value_set::node_base::node_base() :
+ m_pPrev(NULL),
+ m_pNext(NULL)
+{
+}
+
+BOOST_FORCEINLINE attribute_value_set::node::node(key_type const& key, mapped_type& data, bool dynamic) :
+ node_base(),
+ m_Value(key, mapped_type()),
+ m_DynamicallyAllocated(dynamic)
+{
+ m_Value.second.swap(data);
+}
+
+//! Container implementation
+struct attribute_value_set::implementation
+{
+public:
+ typedef key_type::id_type id_type;
+
+private:
+ typedef attribute_set::implementation attribute_set_impl_type;
+ typedef boost::log::aux::stateless_allocator< char > stateless_allocator;
+
+ //! Node base class traits for the intrusive list
+ struct node_traits
+ {
+ typedef node_base node;
+ typedef node* node_ptr;
+ typedef node const* const_node_ptr;
+ static node* get_next(const node* n) { return n->m_pNext; }
+ static void set_next(node* n, node* next) { n->m_pNext = next; }
+ static node* get_previous(const node* n) { return n->m_pPrev; }
+ static void set_previous(node* n, node* prev) { n->m_pPrev = prev; }
+ };
+
+ //! Contained node traits for the intrusive list
+ typedef intrusive::derivation_value_traits<
+ node,
+ node_traits,
+ intrusive::normal_link
+ > value_traits;
+
+ //! A container that provides iteration through elements of the container
+ typedef intrusive::list<
+ node,
+ intrusive::value_traits< value_traits >,
+ intrusive::constant_time_size< true >
+ > node_list;
+
+ //! A hash table bucket
+ struct bucket
+ {
+ //! Points to the first element in the bucket
+ node* first;
+ //! Points to the last element in the bucket (not the one after the last!)
+ node* last;
+
+ bucket() : first(NULL), last(NULL) {}
+ };
+
+ //! A list of buckets
+ typedef boost::array< bucket, 1u << BOOST_LOG_HASH_TABLE_SIZE_LOG > buckets;
+
+ //! Element disposer
+ struct disposer
+ {
+ typedef void result_type;
+ void operator() (node* p) const BOOST_NOEXCEPT
+ {
+ if (!p->m_DynamicallyAllocated)
+ p->~node();
+ else
+ delete p;
+ }
+ };
+
+private:
+ //! Pointer to the source-specific attributes
+ attribute_set_impl_type* m_pSourceAttributes;
+ //! Pointer to the thread-specific attributes
+ attribute_set_impl_type* m_pThreadAttributes;
+ //! Pointer to the global attributes
+ attribute_set_impl_type* m_pGlobalAttributes;
+
+ //! The container with elements
+ node_list m_Nodes;
+ //! The pointer to the end of the allocated elements within the storage
+ node* m_pEnd;
+ //! The pointer to the end of storage
+ node* m_pEOS;
+
+ //! Hash table buckets
+ buckets m_Buckets;
+
+private:
+ //! Constructor
+ implementation(
+ node* storage,
+ node* eos,
+ attribute_set_impl_type* source_attrs,
+ attribute_set_impl_type* thread_attrs,
+ attribute_set_impl_type* global_attrs
+ ) :
+ m_pSourceAttributes(source_attrs),
+ m_pThreadAttributes(thread_attrs),
+ m_pGlobalAttributes(global_attrs),
+ m_pEnd(storage),
+ m_pEOS(eos)
+ {
+ }
+
+ //! Destructor
+ ~implementation()
+ {
+ m_Nodes.clear_and_dispose(disposer());
+ }
+
+ //! The function allocates memory and creates the object
+ static implementation* create(
+ size_type element_count,
+ attribute_set_impl_type* source_attrs,
+ attribute_set_impl_type* thread_attrs,
+ attribute_set_impl_type* global_attrs)
+ {
+ // Calculate the buffer size
+ const size_type header_size = sizeof(implementation) +
+ aux::alignment_gap_between< implementation, node >::value;
+ const size_type buffer_size = header_size + element_count * sizeof(node);
+
+ implementation* p = reinterpret_cast< implementation* >(stateless_allocator().allocate(buffer_size));
+ node* const storage = reinterpret_cast< node* >(reinterpret_cast< char* >(p) + header_size);
+ new (p) implementation(storage, storage + element_count, source_attrs, thread_attrs, global_attrs);
+
+ return p;
+ }
+
+public:
+ //! The function allocates memory and creates the object
+ static implementation* create(
+ attribute_set const& source_attrs,
+ attribute_set const& thread_attrs,
+ attribute_set const& global_attrs,
+ size_type reserve_count)
+ {
+ return create(
+ source_attrs.m_pImpl->size() + thread_attrs.m_pImpl->size() + global_attrs.m_pImpl->size() + reserve_count,
+ source_attrs.m_pImpl,
+ thread_attrs.m_pImpl,
+ global_attrs.m_pImpl);
+ }
+
+ //! The function allocates memory and creates the object
+ static implementation* create(
+ attribute_value_set const& source_attrs,
+ attribute_set const& thread_attrs,
+ attribute_set const& global_attrs,
+ size_type reserve_count)
+ {
+ implementation* p = create(
+ source_attrs.m_pImpl->size() + thread_attrs.m_pImpl->size() + global_attrs.m_pImpl->size() + reserve_count,
+ NULL,
+ thread_attrs.m_pImpl,
+ global_attrs.m_pImpl);
+ p->copy_nodes_from(source_attrs.m_pImpl);
+ return p;
+ }
+
+ //! The function allocates memory and creates the object
+ static implementation* create(
+ BOOST_RV_REF(attribute_value_set) source_attrs,
+ attribute_set const& thread_attrs,
+ attribute_set const& global_attrs,
+ size_type reserve_count)
+ {
+ implementation* p = source_attrs.m_pImpl;
+ source_attrs.m_pImpl = NULL;
+ p->m_pThreadAttributes = thread_attrs.m_pImpl;
+ p->m_pGlobalAttributes = global_attrs.m_pImpl;
+ return p;
+ }
+
+ //! The function allocates memory and creates the object
+ static implementation* create(size_type reserve_count)
+ {
+ return create(reserve_count, NULL, NULL, NULL);
+ }
+
+ //! Creates a copy of the object
+ static implementation* copy(implementation* that)
+ {
+ // Create new object
+ implementation* p = create(that->size(), NULL, NULL, NULL);
+
+ // Copy all elements
+ p->copy_nodes_from(that);
+
+ return p;
+ }
+
+ //! Destroys the object and releases the memory
+ static void destroy(implementation* p)
+ {
+ const size_type buffer_size = reinterpret_cast< char* >(p->m_pEOS) - reinterpret_cast< char* >(p);
+ p->~implementation();
+ stateless_allocator().deallocate(reinterpret_cast< stateless_allocator::pointer >(p), buffer_size);
+ }
+
+ //! Returns the pointer to the first element
+ node_base* begin()
+ {
+ freeze();
+ return m_Nodes.begin().pointed_node();
+ }
+ //! Returns the pointer after the last element
+ node_base* end()
+ {
+ return m_Nodes.end().pointed_node();
+ }
+
+ //! Returns the number of elements in the container
+ size_type size()
+ {
+ freeze();
+ return m_Nodes.size();
+ }
+
+ //! Looks for the element with an equivalent key
+ node_base* find(key_type key)
+ {
+ // First try to find an acquired element
+ bucket& b = get_bucket(key.id());
+ node* p = b.first;
+ if (p)
+ {
+ // The bucket is not empty, search among the elements
+ p = find_in_bucket(key, b);
+ if (p->m_Value.first == key)
+ return p;
+ }
+
+ // Element not found, try to acquire the value from attribute sets
+ return freeze_node(key, b, p);
+ }
+
+ //! Freezes all elements of the container
+ void freeze()
+ {
+ if (m_pSourceAttributes)
+ {
+ freeze_nodes_from(m_pSourceAttributes);
+ m_pSourceAttributes = NULL;
+ }
+ if (m_pThreadAttributes)
+ {
+ freeze_nodes_from(m_pThreadAttributes);
+ m_pThreadAttributes = NULL;
+ }
+ if (m_pGlobalAttributes)
+ {
+ freeze_nodes_from(m_pGlobalAttributes);
+ m_pGlobalAttributes = NULL;
+ }
+ }
+
+ //! Inserts an element
+ std::pair< node*, bool > insert(key_type key, mapped_type const& mapped)
+ {
+ bucket& b = get_bucket(key.id());
+ node* p = find_in_bucket(key, b);
+ if (!p || p->m_Value.first != key)
+ {
+ p = insert_node(key, b, p, mapped);
+ return std::pair< node*, bool >(p, true);
+ }
+ else
+ {
+ return std::pair< node*, bool >(p, false);
+ }
+ }
+
+private:
+ //! The function returns a bucket for the specified element
+ bucket& get_bucket(id_type id)
+ {
+ return m_Buckets[id & (buckets::static_size - 1u)];
+ }
+
+ //! Attempts to find an element with the specified key in the bucket
+ node* find_in_bucket(key_type key, bucket const& b)
+ {
+ typedef node_list::node_traits node_traits;
+ typedef node_list::value_traits value_traits;
+
+ // All elements within the bucket are sorted to speedup the search.
+ node* p = b.first;
+ while (p != b.last && p->m_Value.first.id() < key.id())
+ {
+ p = value_traits::to_value_ptr(node_traits::get_next(p));
+ }
+
+ return p;
+ }
+
+ //! Acquires the attribute value from the attribute sets
+ node_base* freeze_node(key_type key, bucket& b, node* where)
+ {
+ attribute_set::iterator it;
+ if (m_pSourceAttributes)
+ {
+ it = m_pSourceAttributes->find(key);
+ if (it != m_pSourceAttributes->end())
+ {
+ // The attribute is found, acquiring the value
+ return insert_node(key, b, where, it->second.get_value());
+ }
+ }
+
+ if (m_pThreadAttributes)
+ {
+ it = m_pThreadAttributes->find(key);
+ if (it != m_pThreadAttributes->end())
+ {
+ // The attribute is found, acquiring the value
+ return insert_node(key, b, where, it->second.get_value());
+ }
+ }
+
+ if (m_pGlobalAttributes)
+ {
+ it = m_pGlobalAttributes->find(key);
+ if (it != m_pGlobalAttributes->end())
+ {
+ // The attribute is found, acquiring the value
+ return insert_node(key, b, where, it->second.get_value());
+ }
+ }
+
+ // The attribute is not found
+ return m_Nodes.end().pointed_node();
+ }
+
+ //! The function inserts a node into the container
+ node* insert_node(key_type key, bucket& b, node* where, mapped_type data)
+ {
+ node* p;
+ if (m_pEnd != m_pEOS)
+ {
+ p = m_pEnd++;
+ new (p) node(key, data, false);
+ }
+ else
+ {
+ p = new node(key, data, true);
+ }
+
+ node_list::iterator it;
+ if (b.first == NULL)
+ {
+ // The bucket is empty
+ b.first = b.last = p;
+ it = m_Nodes.end();
+ }
+ else if (where == b.last && key.id() > where->m_Value.first.id())
+ {
+ // The new element should become the last element of the bucket
+ it = m_Nodes.iterator_to(*where);
+ ++it;
+ b.last = p;
+ }
+ else if (where == b.first)
+ {
+ // The new element should become the first element of the bucket
+ it = m_Nodes.iterator_to(*where);
+ b.first = p;
+ }
+ else
+ {
+ // The new element should be within the bucket
+ it = m_Nodes.iterator_to(*where);
+ }
+
+ m_Nodes.insert(it, *p);
+
+ return p;
+ }
+
+ //! Acquires attribute values from the set of attributes
+ void freeze_nodes_from(attribute_set_impl_type* attrs)
+ {
+ attribute_set::const_iterator it = attrs->begin(), end = attrs->end();
+ for (; it != end; ++it)
+ {
+ key_type key = it->first;
+ bucket& b = get_bucket(key.id());
+ node* p = b.first;
+ if (p)
+ {
+ p = find_in_bucket(key, b);
+ if (p->m_Value.first == key)
+ continue; // the element is already frozen
+ }
+
+ insert_node(key, b, p, it->second.get_value());
+ }
+ }
+
+ //! Copies nodes of the container
+ void copy_nodes_from(implementation* from)
+ {
+ // Copy all elements
+ node_list::iterator it = from->m_Nodes.begin(), end = from->m_Nodes.end();
+ for (; it != end; ++it)
+ {
+ node* n = m_pEnd++;
+ mapped_type data = it->m_Value.second;
+ new (n) node(it->m_Value.first, data, false);
+ m_Nodes.push_back(*n);
+
+ // Since nodes within buckets are ordered, we can simply append the node to the end of the bucket
+ bucket& b = get_bucket(n->m_Value.first.id());
+ if (b.first == NULL)
+ b.first = b.last = n;
+ else
+ b.last = n;
+ }
+ }
+};
+
+//! The constructor creates an empty set
+BOOST_LOG_API attribute_value_set::attribute_value_set(
+ size_type reserve_count
+) :
+ m_pImpl(implementation::create(reserve_count))
+{
+}
+
+//! The constructor adopts three attribute sets to the set
+BOOST_LOG_API attribute_value_set::attribute_value_set(
+ attribute_set const& source_attrs,
+ attribute_set const& thread_attrs,
+ attribute_set const& global_attrs,
+ size_type reserve_count
+) :
+ m_pImpl(implementation::create(source_attrs, thread_attrs, global_attrs, reserve_count))
+{
+}
+
+//! The constructor adopts three attribute sets to the set
+BOOST_LOG_API attribute_value_set::attribute_value_set(
+ attribute_value_set const& source_attrs,
+ attribute_set const& thread_attrs,
+ attribute_set const& global_attrs,
+ size_type reserve_count
+) :
+ m_pImpl(implementation::create(source_attrs, thread_attrs, global_attrs, reserve_count))
+{
+}
+
+//! The constructor adopts three attribute sets to the set
+BOOST_LOG_API void attribute_value_set::construct(
+ attribute_value_set& source_attrs,
+ attribute_set const& thread_attrs,
+ attribute_set const& global_attrs,
+ size_type reserve_count
+)
+{
+ m_pImpl = implementation::create(boost::move(source_attrs), thread_attrs, global_attrs, reserve_count);
+}
+
+//! Copy constructor
+BOOST_LOG_API attribute_value_set::attribute_value_set(attribute_value_set const& that)
+{
+ if (that.m_pImpl)
+ m_pImpl = implementation::copy(that.m_pImpl);
+ else
+ m_pImpl = NULL;
+}
+
+//! Destructor
+BOOST_LOG_API attribute_value_set::~attribute_value_set() BOOST_NOEXCEPT
+{
+ if (m_pImpl)
+ {
+ implementation::destroy(m_pImpl);
+ m_pImpl = NULL;
+ }
+}
+
+// Iterator generators
+BOOST_LOG_API attribute_value_set::const_iterator
+attribute_value_set::begin() const
+{
+ return const_iterator(m_pImpl->begin(), const_cast< attribute_value_set* >(this));
+}
+
+BOOST_LOG_API attribute_value_set::const_iterator
+attribute_value_set::end() const
+{
+ return const_iterator(m_pImpl->end(), const_cast< attribute_value_set* >(this));
+}
+
+//! The method returns number of elements in the container
+BOOST_LOG_API attribute_value_set::size_type
+attribute_value_set::size() const
+{
+ return m_pImpl->size();
+}
+
+//! Internal lookup implementation
+BOOST_LOG_API attribute_value_set::const_iterator
+attribute_value_set::find(key_type key) const
+{
+ return const_iterator(m_pImpl->find(key), const_cast< attribute_value_set* >(this));
+}
+
+//! The method acquires values of all adopted attributes. Users don't need to call it, since will always get an already frozen set.
+BOOST_LOG_API void attribute_value_set::freeze()
+{
+ m_pImpl->freeze();
+}
+
+//! Inserts an element into the set
+BOOST_LOG_API std::pair< attribute_value_set::const_iterator, bool >
+attribute_value_set::insert(key_type key, mapped_type const& mapped)
+{
+ std::pair< node*, bool > res = m_pImpl->insert(key, mapped);
+ return std::pair< const_iterator, bool >(const_iterator(res.first, this), res.second);
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/bit_tools.hpp b/src/boost/libs/log/src/bit_tools.hpp
new file mode 100644
index 000000000..db28c405e
--- /dev/null
+++ b/src/boost/libs/log/src/bit_tools.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file bit_tools.hpp
+ * \author Andrey Semashev
+ * \date 16.01.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_BIT_TOOLS_HPP_INCLUDED_
+#define BOOST_LOG_BIT_TOOLS_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Checks that the integer is a power of 2.
+template< typename T >
+inline BOOST_CONSTEXPR bool is_power_of_2(T n) BOOST_NOEXCEPT
+{
+ return n != (T)0 && (n & (n - (T)1)) == (T)0;
+}
+
+//! Returns an integer comprising the four characters
+inline BOOST_CONSTEXPR uint32_t make_fourcc(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4) BOOST_NOEXCEPT
+{
+ return (static_cast< uint32_t >(c1) << 24) | (static_cast< uint32_t >(c2) << 16) | (static_cast< uint32_t >(c3) << 8) | static_cast< uint32_t >(c4);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_BIT_TOOLS_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/code_conversion.cpp b/src/boost/libs/log/src/code_conversion.cpp
new file mode 100644
index 000000000..d75d2a61a
--- /dev/null
+++ b/src/boost/libs/log/src/code_conversion.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file code_conversion.cpp
+ * \author Andrey Semashev
+ * \date 08.11.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <locale>
+#include <string>
+#include <stdexcept>
+#include <algorithm>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#if defined(BOOST_WINDOWS)
+#include <cstring>
+#include <limits>
+#include <boost/winapi/get_last_error.hpp>
+#include <boost/winapi/character_code_conversion.hpp>
+#endif
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! The function performs character conversion with the specified facet
+template< typename LocalCharT >
+inline std::codecvt_base::result convert(
+ std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
+ std::mbstate_t& state,
+ const char*& pSrcBegin,
+ const char* pSrcEnd,
+ LocalCharT*& pDstBegin,
+ LocalCharT* pDstEnd)
+{
+ return fac.in(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
+}
+
+//! The function performs character conversion with the specified facet
+template< typename LocalCharT >
+inline std::codecvt_base::result convert(
+ std::codecvt< LocalCharT, char, std::mbstate_t > const& fac,
+ std::mbstate_t& state,
+ const LocalCharT*& pSrcBegin,
+ const LocalCharT* pSrcEnd,
+ char*& pDstBegin,
+ char* pDstEnd)
+{
+ return fac.out(state, pSrcBegin, pSrcEnd, pSrcBegin, pDstBegin, pDstEnd, pDstBegin);
+}
+
+} // namespace
+
+template< typename SourceCharT, typename TargetCharT, typename FacetT >
+inline std::size_t code_convert(const SourceCharT* begin, const SourceCharT* end, std::basic_string< TargetCharT >& converted, std::size_t max_size, FacetT const& fac)
+{
+ typedef typename FacetT::state_type state_type;
+ TargetCharT converted_buffer[256];
+
+ const SourceCharT* const original_begin = begin;
+ state_type state = state_type();
+ std::size_t buf_size = (std::min)(max_size, sizeof(converted_buffer) / sizeof(*converted_buffer));
+ while (begin != end && buf_size > 0u)
+ {
+ TargetCharT* dest = converted_buffer;
+ std::codecvt_base::result res = convert(
+ fac,
+ state,
+ begin,
+ end,
+ dest,
+ dest + buf_size);
+
+ switch (res)
+ {
+ case std::codecvt_base::ok:
+ // All characters were successfully converted
+ // NOTE: MSVC 11 also returns ok when the source buffer was only partially consumed, so we also check that the begin pointer has reached the end.
+ converted.append(converted_buffer, dest);
+ max_size -= dest - converted_buffer;
+ break;
+
+ case std::codecvt_base::noconv:
+ {
+ // Not possible, unless both character types are actually equivalent
+ const std::size_t size = (std::min)(max_size, static_cast< std::size_t >(end - begin));
+ converted.append(begin, begin + size);
+ begin += size;
+ max_size -= size;
+ }
+ goto done;
+
+ case std::codecvt_base::partial:
+ // Some characters were converted, some were not
+ if (dest != converted_buffer)
+ {
+ // Some conversion took place, so it seems like
+ // the destination buffer might not have been long enough
+ converted.append(converted_buffer, dest);
+ max_size -= dest - converted_buffer;
+
+ // ...and go on for the next part
+ break;
+ }
+ else
+ {
+ // Nothing was converted
+ if (begin == end)
+ goto done;
+
+ // Looks like the tail of the source buffer contains only part of the last character.
+ // In this case we intentionally fall through to throw an exception.
+ }
+ BOOST_FALLTHROUGH;
+
+ default: // std::codecvt_base::error
+ BOOST_LOG_THROW_DESCR(conversion_error, "Could not convert character encoding");
+ }
+
+ buf_size = (std::min)(max_size, sizeof(converted_buffer) / sizeof(*converted_buffer));
+ }
+
+done:
+ return static_cast< std::size_t >(begin - original_begin);
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc)
+{
+ return code_convert(str1, str1 + len, str2, max_size, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc)) == len;
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc)
+{
+ return code_convert(str1, str1 + len, str2, max_size, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc)) == len;
+}
+
+#if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc)
+{
+ return code_convert(str1, str1 + len, str2, max_size, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc)) == len;
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::u16string& str2, std::size_t max_size, std::locale const& loc)
+{
+ return code_convert(str1, str1 + len, str2, max_size, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc)) == len;
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc)
+{
+ std::string temp_str;
+ code_convert(str1, str1 + len, temp_str, temp_str.max_size(), std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
+ const std::size_t temp_size = temp_str.size();
+ return code_convert(temp_str.c_str(), temp_str.c_str() + temp_size, str2, max_size, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc)) == temp_size;
+}
+
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc)
+{
+ return code_convert(str1, str1 + len, str2, max_size, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc)) == len;
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char* str1, std::size_t len, std::u32string& str2, std::size_t max_size, std::locale const& loc)
+{
+ return code_convert(str1, str1 + len, str2, max_size, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc)) == len;
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::wstring& str2, std::size_t max_size, std::locale const& loc)
+{
+ std::string temp_str;
+ code_convert(str1, str1 + len, temp_str, temp_str.max_size(), std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
+ const std::size_t temp_size = temp_str.size();
+ return code_convert(temp_str.c_str(), temp_str.c_str() + temp_size, str2, max_size, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc)) == temp_size;
+}
+
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_CHAR32_T)
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char16_t* str1, std::size_t len, std::u32string& str2, std::size_t max_size, std::locale const& loc)
+{
+ std::string temp_str;
+ code_convert(str1, str1 + len, temp_str, temp_str.max_size(), std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
+ const std::size_t temp_size = temp_str.size();
+ return code_convert(temp_str.c_str(), temp_str.c_str() + temp_size, str2, max_size, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc)) == temp_size;
+}
+
+//! The function converts one string to the character type of another
+BOOST_LOG_API bool code_convert_impl(const char32_t* str1, std::size_t len, std::u16string& str2, std::size_t max_size, std::locale const& loc)
+{
+ std::string temp_str;
+ code_convert(str1, str1 + len, temp_str, temp_str.max_size(), std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
+ const std::size_t temp_size = temp_str.size();
+ return code_convert(temp_str.c_str(), temp_str.c_str() + temp_size, str2, max_size, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc)) == temp_size;
+}
+
+#endif
+
+#endif // !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS)
+
+#if defined(BOOST_WINDOWS)
+
+//! Converts UTF-8 to UTF-16
+std::wstring utf8_to_utf16(const char* str)
+{
+ std::size_t utf8_len = std::strlen(str);
+ if (utf8_len == 0)
+ return std::wstring();
+ else if (BOOST_UNLIKELY(utf8_len > static_cast< std::size_t >((std::numeric_limits< int >::max)())))
+ BOOST_LOG_THROW_DESCR(bad_alloc, "UTF-8 string too long");
+
+ int len = boost::winapi::MultiByteToWideChar(boost::winapi::CP_UTF8_, boost::winapi::MB_ERR_INVALID_CHARS_, str, static_cast< int >(utf8_len), NULL, 0);
+ if (BOOST_LIKELY(len > 0))
+ {
+ std::wstring wstr;
+ wstr.resize(len);
+
+ len = boost::winapi::MultiByteToWideChar(boost::winapi::CP_UTF8_, boost::winapi::MB_ERR_INVALID_CHARS_, str, static_cast< int >(utf8_len), &wstr[0], len);
+ if (BOOST_LIKELY(len > 0))
+ {
+ return wstr;
+ }
+ }
+
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to convert UTF-8 to UTF-16", (err));
+ BOOST_LOG_UNREACHABLE_RETURN(std::wstring());
+}
+
+//! Converts UTF-16 to UTF-8
+std::string utf16_to_utf8(const wchar_t* wstr)
+{
+ std::size_t utf16_len = std::wcslen(wstr);
+ if (utf16_len == 0)
+ return std::string();
+ else if (BOOST_UNLIKELY(utf16_len > static_cast< std::size_t >((std::numeric_limits< int >::max)())))
+ BOOST_LOG_THROW_DESCR(bad_alloc, "UTF-16 string too long");
+
+ const boost::winapi::DWORD_ flags =
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ boost::winapi::WC_ERR_INVALID_CHARS_;
+#else
+ 0u;
+#endif
+ int len = boost::winapi::WideCharToMultiByte(boost::winapi::CP_UTF8_, flags, wstr, static_cast< int >(utf16_len), NULL, 0, NULL, NULL);
+ if (BOOST_LIKELY(len > 0))
+ {
+ std::string str;
+ str.resize(len);
+
+ len = boost::winapi::WideCharToMultiByte(boost::winapi::CP_UTF8_, flags, wstr, static_cast< int >(utf16_len), &str[0], len, NULL, NULL);
+ if (BOOST_LIKELY(len > 0))
+ {
+ return str;
+ }
+ }
+
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to convert UTF-16 to UTF-8", (err));
+ BOOST_LOG_UNREACHABLE_RETURN(std::string());
+}
+
+#endif // defined(BOOST_WINDOWS)
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/core.cpp b/src/boost/libs/log/src/core.cpp
new file mode 100644
index 000000000..4fe27c7ee
--- /dev/null
+++ b/src/boost/libs/log/src/core.cpp
@@ -0,0 +1,806 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file core.cpp
+ * \author Andrey Semashev
+ * \date 19.04.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <new>
+#include <vector>
+#include <algorithm>
+#include <boost/cstdint.hpp>
+#include <boost/assert.hpp>
+#include <boost/core/swap.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/smart_ptr/weak_ptr.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/range/iterator_range_core.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/random/taus88.hpp>
+#include <boost/move/core.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/log/core/core.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/core/record_view.hpp>
+#include <boost/log/sinks/sink.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/detail/singleton.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/thread/tss.hpp>
+#include <boost/thread/exceptions.hpp>
+#include <boost/log/detail/locks.hpp>
+#include <boost/log/detail/light_rw_mutex.hpp>
+#include <boost/log/detail/thread_id.hpp>
+#endif
+#include "unique_ptr.hpp"
+#include "default_sink.hpp"
+#include "stateless_allocator.hpp"
+#include "alignment_gap_between.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! Sequence shuffling algorithm. Very similar to std::random_shuffle, used for forward portability with compilers that removed it from the standard library (C++17).
+template< typename Iterator, typename RandomNumberGenerator >
+void random_shuffle(Iterator begin, Iterator end, RandomNumberGenerator& rng)
+{
+ Iterator it = begin;
+ ++it;
+ while (it != end)
+ {
+ Iterator where = begin + rng() % (it - begin + 1u);
+ if (where != it)
+ boost::swap(*where, *it);
+ ++it;
+ }
+}
+
+} // namespace
+
+} // namespace aux
+
+//! Private record data information, with core-specific structures
+struct record_view::private_data :
+ public public_data
+{
+ //! Underlying memory allocator
+ typedef boost::log::aux::stateless_allocator< char > stateless_allocator;
+ //! Sink pointer type
+ typedef weak_ptr< sinks::sink > sink_ptr;
+ //! Iterator range with pointers to the accepting sinks
+ typedef iterator_range< sink_ptr* > sink_list;
+
+private:
+ //! Number of sinks accepting the record
+ uint32_t m_accepting_sink_count;
+ //! Maximum number of sinks accepting the record
+ const uint32_t m_accepting_sink_capacity;
+ //! The flag indicates that the record has to be detached from the current thread
+ bool m_detach_from_thread_needed;
+
+private:
+ //! Initializing constructor
+ private_data(BOOST_RV_REF(attribute_value_set) values, uint32_t capacity) BOOST_NOEXCEPT :
+ public_data(boost::move(values)),
+ m_accepting_sink_count(0),
+ m_accepting_sink_capacity(capacity),
+ m_detach_from_thread_needed(false)
+ {
+ }
+
+public:
+ //! Creates the object with the specified capacity
+ static private_data* create(BOOST_RV_REF(attribute_value_set) values, uint32_t capacity)
+ {
+ private_data* p = reinterpret_cast< private_data* >(stateless_allocator().allocate
+ (
+ sizeof(private_data) +
+ boost::log::aux::alignment_gap_between< private_data, sink_ptr >::value +
+ capacity * sizeof(sink_ptr)
+ ));
+ new (p) private_data(boost::move(values), capacity);
+ return p;
+ }
+
+ //! Destroys the object and frees the underlying storage
+ void destroy() BOOST_NOEXCEPT
+ {
+ sink_ptr* psink = begin();
+ for (uint32_t i = 0u, n = m_accepting_sink_count; i < n; ++i)
+ {
+ psink[i].~sink_ptr();
+ }
+
+ const uint32_t capacity = m_accepting_sink_capacity;
+ this->~private_data();
+
+ stateless_allocator().deallocate
+ (
+ reinterpret_cast< stateless_allocator::pointer >(this),
+ sizeof(private_data) +
+ boost::log::aux::alignment_gap_between< private_data, sink_ptr >::value +
+ capacity * sizeof(sink_ptr)
+ );
+ }
+
+ //! Returns iterator range with the pointers to the accepting sinks
+ sink_list get_accepting_sinks() BOOST_NOEXCEPT
+ {
+ sink_ptr* p = begin();
+ return sink_list(p, p + m_accepting_sink_count);
+ }
+
+ //! Adds an accepting sink
+ void push_back_accepting_sink(shared_ptr< sinks::sink > const& sink)
+ {
+ BOOST_ASSERT(m_accepting_sink_count < m_accepting_sink_capacity);
+ sink_ptr* p = begin() + m_accepting_sink_count;
+ new (p) sink_ptr(sink);
+ ++m_accepting_sink_count;
+ m_detach_from_thread_needed |= sink->is_cross_thread();
+ }
+
+ //! Returns the number of accepting sinks
+ uint32_t accepting_sink_count() const BOOST_NOEXCEPT { return m_accepting_sink_count; }
+
+ //! Returns the flag indicating whether it is needed to detach the record from the current thread
+ bool is_detach_from_thread_needed() const BOOST_NOEXCEPT { return m_detach_from_thread_needed; }
+
+ BOOST_DELETED_FUNCTION(private_data(private_data const&))
+ BOOST_DELETED_FUNCTION(private_data& operator= (private_data const&))
+
+private:
+ //! Returns a pointer to the first accepting sink
+ sink_ptr* begin() BOOST_NOEXCEPT
+ {
+ return reinterpret_cast< sink_ptr* >
+ (
+ reinterpret_cast< char* >(this) +
+ sizeof(private_data) +
+ boost::log::aux::alignment_gap_between< private_data, sink_ptr >::value
+ );
+ }
+};
+
+//! Destructor
+BOOST_LOG_API void record_view::public_data::destroy(const public_data* p) BOOST_NOEXCEPT
+{
+ const_cast< private_data* >(static_cast< const private_data* >(p))->destroy();
+}
+
+//! The function ensures that the log record does not depend on any thread-specific data.
+BOOST_LOG_API record_view record::lock()
+{
+ BOOST_ASSERT(m_impl != NULL);
+
+ record_view::private_data* const impl = static_cast< record_view::private_data* >(m_impl);
+ if (impl->is_detach_from_thread_needed())
+ {
+ attribute_value_set::const_iterator
+ it = impl->m_attribute_values.begin(),
+ end = impl->m_attribute_values.end();
+ for (; it != end; ++it)
+ {
+ // Yep, a bit hackish. I'll need a better backdoor to do it gracefully.
+ const_cast< attribute_value_set::mapped_type& >(it->second).detach_from_thread();
+ }
+ }
+
+ // Move the implementation to the view
+ m_impl = NULL;
+ return record_view(impl);
+}
+
+//! Logging system implementation
+struct core::implementation :
+ public log::aux::lazy_singleton<
+ implementation,
+ core_ptr
+ >
+{
+public:
+ //! Base type of singleton holder
+ typedef log::aux::lazy_singleton<
+ implementation,
+ core_ptr
+ > base_type;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Read lock type
+ typedef log::aux::shared_lock_guard< log::aux::light_rw_mutex > scoped_read_lock;
+ //! Write lock type
+ typedef log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > scoped_write_lock;
+#endif
+
+ //! Sinks container type
+ typedef std::vector< shared_ptr< sinks::sink > > sink_list;
+
+ //! Thread-specific data
+ struct thread_data
+ {
+ //! Thread-specific attribute set
+ attribute_set m_thread_attributes;
+ //! Random number generator for shuffling
+ random::taus88 m_rng;
+
+ thread_data() : m_rng(get_random_seed())
+ {
+ }
+
+ private:
+ //! Creates a seed for RNG
+ static uint32_t get_random_seed()
+ {
+ uint32_t seed = static_cast< uint32_t >(posix_time::microsec_clock::universal_time().time_of_day().ticks());
+#if !defined(BOOST_LOG_NO_THREADS)
+ seed += static_cast< uint32_t >(log::aux::this_thread::get_id().native_id());
+#endif
+ return seed;
+ }
+ };
+
+public:
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex
+ log::aux::light_rw_mutex m_mutex;
+#endif
+
+ //! List of sinks involved into output
+ sink_list m_sinks;
+ //! Default sink
+ const shared_ptr< sinks::sink > m_default_sink;
+
+ //! Global attribute set
+ attribute_set m_global_attributes;
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Thread-specific data
+ thread_specific_ptr< thread_data > m_thread_data;
+
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ //! Cached pointer to the thread-specific data
+ static BOOST_LOG_TLS thread_data* m_thread_data_cache;
+#endif
+
+#else
+ //! Thread-specific data
+ log::aux::unique_ptr< thread_data > m_thread_data;
+#endif
+
+ //! The global state of logging
+#if !defined(BOOST_LOG_NO_THREADS)
+ boost::atomic< bool > m_enabled;
+#else
+ bool m_enabled;
+#endif
+ //! Global filter
+ filter m_filter;
+
+ //! Exception handler
+ exception_handler_type m_exception_handler;
+
+public:
+ //! Constructor
+ implementation() :
+ m_default_sink(boost::make_shared< sinks::aux::default_sink >()),
+ m_enabled(true)
+ {
+ }
+
+ //! Opens a record
+ template< typename SourceAttributesT >
+ BOOST_FORCEINLINE record open_record(BOOST_FWD_REF(SourceAttributesT) source_attributes)
+ {
+ record_view::private_data* rec_impl = NULL;
+ bool invoke_exception_handler = true;
+
+ // Try a quick win first
+#if !defined(BOOST_LOG_NO_THREADS)
+ if (BOOST_LIKELY(m_enabled.load(boost::memory_order_relaxed)))
+#else
+ if (BOOST_LIKELY(m_enabled))
+#endif
+ try
+ {
+ thread_data* tsd = get_thread_data();
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ // Lock the core to be safe against any attribute or sink set modifications
+ scoped_read_lock lock(m_mutex);
+
+ if (BOOST_LIKELY(m_enabled.load(boost::memory_order_relaxed)))
+#endif
+ {
+ // Compose a view of attribute values (unfrozen, yet)
+ attribute_value_set attr_values(boost::forward< SourceAttributesT >(source_attributes), tsd->m_thread_attributes, m_global_attributes);
+ if (m_filter(attr_values))
+ {
+ // The global filter passed, trying the sinks
+ attribute_value_set* values = &attr_values;
+
+ // apply_sink_filter will invoke the exception handler if it has to
+ invoke_exception_handler = false;
+
+ if (!m_sinks.empty())
+ {
+ uint32_t remaining_capacity = static_cast< uint32_t >(m_sinks.size());
+ sink_list::iterator it = m_sinks.begin(), end = m_sinks.end();
+ for (; it != end; ++it, --remaining_capacity)
+ {
+ apply_sink_filter(*it, rec_impl, values, remaining_capacity);
+ }
+ }
+ else
+ {
+ // Use the default sink
+ apply_sink_filter(m_default_sink, rec_impl, values, 1);
+ }
+
+ invoke_exception_handler = true;
+
+ if (rec_impl && rec_impl->accepting_sink_count() == 0)
+ {
+ // No sinks accepted the record
+ rec_impl->destroy();
+ rec_impl = NULL;
+ goto done;
+ }
+
+ // Some sinks have accepted the record
+ values->freeze();
+ }
+ }
+ }
+#if !defined(BOOST_LOG_NO_THREADS)
+ catch (thread_interrupted&)
+ {
+ if (rec_impl)
+ rec_impl->destroy();
+ throw;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ catch (...)
+ {
+ if (rec_impl)
+ {
+ rec_impl->destroy();
+ rec_impl = NULL;
+ }
+
+ if (invoke_exception_handler)
+ {
+ // Lock the core to be safe against any attribute or sink set modifications
+ BOOST_LOG_EXPR_IF_MT(scoped_read_lock lock(m_mutex);)
+ if (m_exception_handler.empty())
+ throw;
+
+ m_exception_handler();
+ }
+ else
+ throw;
+ }
+
+ done:
+ return record(rec_impl);
+ }
+
+ //! The method returns the current thread-specific data
+ thread_data* get_thread_data()
+ {
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ thread_data* p = m_thread_data_cache;
+#else
+ thread_data* p = m_thread_data.get();
+#endif
+ if (BOOST_UNLIKELY(!p))
+ {
+ init_thread_data();
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ p = m_thread_data_cache;
+#else
+ p = m_thread_data.get();
+#endif
+ }
+ return p;
+ }
+
+ //! The function initializes the logging system
+ static void init_instance()
+ {
+ base_type::get_instance().reset(new core());
+ }
+
+private:
+ //! The method initializes thread-specific data
+ void init_thread_data()
+ {
+ BOOST_LOG_EXPR_IF_MT(scoped_write_lock lock(m_mutex);)
+ if (!m_thread_data.get())
+ {
+ log::aux::unique_ptr< thread_data > p(new thread_data());
+ m_thread_data.reset(p.get());
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ m_thread_data_cache = p.release();
+#else
+ p.release();
+#endif
+ }
+ }
+
+ //! Invokes sink-specific filter and adds the sink to the record if the filter passes the log record
+ void apply_sink_filter(shared_ptr< sinks::sink > const& sink, record_view::private_data*& rec_impl, attribute_value_set*& attr_values, uint32_t remaining_capacity)
+ {
+ try
+ {
+ if (sink->will_consume(*attr_values))
+ {
+ // If at least one sink accepts the record, it's time to create it
+ record_view::private_data* impl = rec_impl;
+ if (!impl)
+ {
+ rec_impl = impl = record_view::private_data::create(boost::move(*attr_values), remaining_capacity);
+ attr_values = &impl->m_attribute_values;
+ }
+
+ impl->push_back_accepting_sink(sink);
+ }
+ }
+#if !defined(BOOST_LOG_NO_THREADS)
+ catch (thread_interrupted&)
+ {
+ throw;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ catch (...)
+ {
+ if (m_exception_handler.empty())
+ throw;
+ m_exception_handler();
+ }
+ }
+};
+
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+//! Cached pointer to the thread-specific data
+BOOST_LOG_TLS core::implementation::thread_data* core::implementation::m_thread_data_cache = NULL;
+#endif // defined(BOOST_LOG_USE_COMPILER_TLS)
+
+//! Logging system constructor
+core::core() :
+ m_impl(new implementation())
+{
+}
+
+//! Logging system destructor
+core::~core()
+{
+ delete m_impl;
+ m_impl = NULL;
+}
+
+//! The method returns a pointer to the logging system instance
+BOOST_LOG_API core_ptr core::get()
+{
+ return implementation::get();
+}
+
+//! The method enables or disables logging and returns the previous state of logging flag
+BOOST_LOG_API bool core::set_logging_enabled(bool enabled)
+{
+#if !defined(BOOST_LOG_NO_THREADS)
+ return m_impl->m_enabled.exchange(enabled, boost::memory_order_relaxed);
+#else
+ const bool old_value = m_impl->m_enabled;
+ m_impl->m_enabled = enabled;
+ return old_value;
+#endif
+}
+
+//! The method allows to detect if logging is enabled
+BOOST_LOG_API bool core::get_logging_enabled() const
+{
+#if !defined(BOOST_LOG_NO_THREADS)
+ return m_impl->m_enabled.load(boost::memory_order_relaxed);
+#else
+ return m_impl->m_enabled;
+#endif
+}
+
+//! The method adds a new sink
+BOOST_LOG_API void core::add_sink(shared_ptr< sinks::sink > const& s)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ implementation::sink_list::iterator it =
+ std::find(m_impl->m_sinks.begin(), m_impl->m_sinks.end(), s);
+ if (it == m_impl->m_sinks.end())
+ m_impl->m_sinks.push_back(s);
+}
+
+//! The method removes the sink from the output
+BOOST_LOG_API void core::remove_sink(shared_ptr< sinks::sink > const& s)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ implementation::sink_list::iterator it =
+ std::find(m_impl->m_sinks.begin(), m_impl->m_sinks.end(), s);
+ if (it != m_impl->m_sinks.end())
+ m_impl->m_sinks.erase(it);
+}
+
+//! The method removes all registered sinks from the output
+BOOST_LOG_API void core::remove_all_sinks()
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ m_impl->m_sinks.clear();
+}
+
+
+//! The method adds an attribute to the global attribute set
+BOOST_LOG_API std::pair< attribute_set::iterator, bool >
+core::add_global_attribute(attribute_name const& name, attribute const& attr)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ return m_impl->m_global_attributes.insert(name, attr);
+}
+
+//! The method removes an attribute from the global attribute set
+BOOST_LOG_API void core::remove_global_attribute(attribute_set::iterator it)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ m_impl->m_global_attributes.erase(it);
+}
+
+//! The method returns the complete set of currently registered global attributes
+BOOST_LOG_API attribute_set core::get_global_attributes() const
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_read_lock lock(m_impl->m_mutex);)
+ return m_impl->m_global_attributes;
+}
+
+//! The method replaces the complete set of currently registered global attributes with the provided set
+BOOST_LOG_API void core::set_global_attributes(attribute_set const& attrs)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ m_impl->m_global_attributes = attrs;
+}
+
+//! The method adds an attribute to the thread-specific attribute set
+BOOST_LOG_API std::pair< attribute_set::iterator, bool >
+core::add_thread_attribute(attribute_name const& name, attribute const& attr)
+{
+ implementation::thread_data* p = m_impl->get_thread_data();
+ return p->m_thread_attributes.insert(name, attr);
+}
+
+//! The method removes an attribute from the thread-specific attribute set
+BOOST_LOG_API void core::remove_thread_attribute(attribute_set::iterator it)
+{
+ implementation::thread_data* p = m_impl->get_thread_data();
+ p->m_thread_attributes.erase(it);
+}
+
+//! The method returns the complete set of currently registered thread-specific attributes
+BOOST_LOG_API attribute_set core::get_thread_attributes() const
+{
+ implementation::thread_data* p = m_impl->get_thread_data();
+ return p->m_thread_attributes;
+}
+//! The method replaces the complete set of currently registered thread-specific attributes with the provided set
+BOOST_LOG_API void core::set_thread_attributes(attribute_set const& attrs)
+{
+ implementation::thread_data* p = m_impl->get_thread_data();
+ p->m_thread_attributes = attrs;
+}
+
+//! An internal method to set the global filter
+BOOST_LOG_API void core::set_filter(filter const& filter)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ m_impl->m_filter = filter;
+}
+
+//! The method removes the global logging filter
+BOOST_LOG_API void core::reset_filter()
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ m_impl->m_filter.reset();
+}
+
+//! The method sets exception handler function
+BOOST_LOG_API void core::set_exception_handler(exception_handler_type const& handler)
+{
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ m_impl->m_exception_handler = handler;
+}
+
+//! The method performs flush on all registered sinks.
+BOOST_LOG_API void core::flush()
+{
+ // Acquire exclusive lock to prevent any logging attempts while flushing
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);)
+ if (BOOST_LIKELY(!m_impl->m_sinks.empty()))
+ {
+ implementation::sink_list::iterator it = m_impl->m_sinks.begin(), end = m_impl->m_sinks.end();
+ for (; it != end; ++it)
+ {
+ try
+ {
+ it->get()->flush();
+ }
+#if !defined(BOOST_LOG_NO_THREADS)
+ catch (thread_interrupted&)
+ {
+ throw;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ catch (...)
+ {
+ if (m_impl->m_exception_handler.empty())
+ throw;
+ m_impl->m_exception_handler();
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ m_impl->m_default_sink->flush();
+ }
+#if !defined(BOOST_LOG_NO_THREADS)
+ catch (thread_interrupted&)
+ {
+ throw;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ catch (...)
+ {
+ if (m_impl->m_exception_handler.empty())
+ throw;
+ m_impl->m_exception_handler();
+ }
+ }
+}
+
+//! The method attempts to open a new record to be written
+BOOST_LOG_API record core::open_record(attribute_set const& source_attributes)
+{
+ return m_impl->open_record(source_attributes);
+}
+
+//! The method attempts to open a new record to be written
+BOOST_LOG_API record core::open_record(attribute_value_set const& source_attributes)
+{
+ return m_impl->open_record(source_attributes);
+}
+
+//! The method attempts to open a new record to be written.
+BOOST_LOG_API record core::open_record_move(attribute_value_set& source_attributes)
+{
+ return m_impl->open_record(boost::move(source_attributes));
+}
+
+//! The method pushes the record
+BOOST_LOG_API void core::push_record_move(record& rec)
+{
+ try
+ {
+ record_view rec_view(rec.lock());
+ record_view::private_data* data = static_cast< record_view::private_data* >(rec_view.m_impl.get());
+
+ typedef std::vector< shared_ptr< sinks::sink > > accepting_sinks_t;
+ accepting_sinks_t accepting_sinks(data->accepting_sink_count());
+ shared_ptr< sinks::sink >* const begin = &*accepting_sinks.begin();
+ shared_ptr< sinks::sink >* end = begin;
+
+ // Lock sinks that are willing to consume the record
+ record_view::private_data::sink_list weak_sinks = data->get_accepting_sinks();
+ record_view::private_data::sink_list::iterator
+ weak_it = weak_sinks.begin(),
+ weak_end = weak_sinks.end();
+ for (; weak_it != weak_end; ++weak_it)
+ {
+ shared_ptr< sinks::sink >& last = *end;
+ weak_it->lock().swap(last);
+ if (last.get())
+ ++end;
+ }
+
+ bool shuffled = (end - begin) <= 1;
+ shared_ptr< sinks::sink >* it = begin;
+ while (true) try
+ {
+ // First try to distribute load between different sinks
+ bool all_locked = true;
+ while (it != end)
+ {
+ if (it->get()->try_consume(rec_view))
+ {
+ --end;
+ end->swap(*it);
+ all_locked = false;
+ }
+ else
+ ++it;
+ }
+
+ it = begin;
+ if (begin != end)
+ {
+ if (all_locked)
+ {
+ // If all sinks are busy then block on any
+ if (!shuffled)
+ {
+ implementation::thread_data* tsd = m_impl->get_thread_data();
+ log::aux::random_shuffle(begin, end, tsd->m_rng);
+ shuffled = true;
+ }
+
+ it->get()->consume(rec_view);
+ --end;
+ end->swap(*it);
+ }
+ }
+ else
+ break;
+ }
+#if !defined(BOOST_LOG_NO_THREADS)
+ catch (thread_interrupted&)
+ {
+ throw;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ catch (...)
+ {
+ // Lock the core to be safe against any attribute or sink set modifications
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_read_lock lock(m_impl->m_mutex);)
+ if (m_impl->m_exception_handler.empty())
+ throw;
+
+ m_impl->m_exception_handler();
+
+ // Skip the sink that failed to consume the record
+ --end;
+ end->swap(*it);
+ }
+ }
+#if !defined(BOOST_LOG_NO_THREADS)
+ catch (thread_interrupted&)
+ {
+ throw;
+ }
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ catch (...)
+ {
+ // Lock the core to be safe against any attribute or sink set modifications
+ BOOST_LOG_EXPR_IF_MT(implementation::scoped_read_lock lock(m_impl->m_mutex);)
+ if (m_impl->m_exception_handler.empty())
+ throw;
+
+ m_impl->m_exception_handler();
+ }
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/date_time_format_parser.cpp b/src/boost/libs/log/src/date_time_format_parser.cpp
new file mode 100644
index 000000000..5b1381ffe
--- /dev/null
+++ b/src/boost/libs/log/src/date_time_format_parser.cpp
@@ -0,0 +1,423 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file date_time_format_parser.cpp
+ * \author Andrey Semashev
+ * \date 30.09.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstring>
+#include <string>
+#include <algorithm>
+#include <boost/spirit/include/karma_uint.hpp>
+#include <boost/spirit/include/karma_generate.hpp>
+#include <boost/range/iterator_range_core.hpp>
+#include <boost/log/detail/attachable_sstream_buf.hpp>
+#include <boost/log/detail/date_time_format_parser.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace karma = boost::spirit::karma;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+template< typename CharT >
+struct string_constants;
+
+#ifdef BOOST_LOG_USE_CHAR
+
+template< >
+struct string_constants< char >
+{
+ typedef char char_type;
+
+ static const char_type* iso_date_format() { return "%Y%m%d"; }
+ static const char_type* extended_iso_date_format() { return "%Y-%m-%d"; }
+
+ static const char_type* iso_time_format() { return "%H%M%S"; }
+ static const char_type* extended_iso_time_format() { return "%H:%M:%S"; }
+ static const char_type* default_time_format() { return "%H:%M:%S.%f"; }
+};
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+template< >
+struct string_constants< wchar_t >
+{
+ typedef wchar_t char_type;
+
+ static const char_type* iso_date_format() { return L"%Y%m%d"; }
+ static const char_type* extended_iso_date_format() { return L"%Y-%m-%d"; }
+
+ static const char_type* iso_time_format() { return L"%H%M%S"; }
+ static const char_type* extended_iso_time_format() { return L"%H:%M:%S"; }
+ static const char_type* default_time_format() { return L"%H:%M:%S.%f"; }
+};
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+template< typename CallbackT >
+struct common_flags
+{
+ typedef CallbackT callback_type;
+ typedef typename callback_type::char_type char_type;
+ typedef std::basic_string< char_type > string_type;
+
+ const char_type* parse(const char_type* begin, const char_type* end, callback_type& callback)
+ {
+ switch (begin[1])
+ {
+ case '%':
+ m_literal.push_back('%');
+ break;
+
+ default:
+ flush(callback);
+ callback.on_placeholder(iterator_range< const char_type* >(begin, begin + 2));
+ break;
+ }
+
+ return begin + 2;
+ }
+
+ void add_literal(const char_type* begin, const char_type* end)
+ {
+ m_literal.append(begin, end);
+ }
+
+ void flush(callback_type& callback)
+ {
+ if (!m_literal.empty())
+ {
+ const char_type* p = m_literal.c_str();
+ callback.on_literal(iterator_range< const char_type* >(p, p + m_literal.size()));
+ m_literal.clear();
+ }
+ }
+
+private:
+ string_type m_literal;
+};
+
+template< typename BaseT >
+struct date_flags :
+ public BaseT
+{
+ typedef typename BaseT::callback_type callback_type;
+ typedef typename BaseT::char_type char_type;
+
+ const char_type* parse(const char_type* begin, const char_type* end, callback_type& callback)
+ {
+ typedef string_constants< char_type > constants;
+
+ switch (begin[1])
+ {
+ case 'Y':
+ {
+ this->flush(callback);
+
+ std::size_t len = end - begin;
+ if (len >= 8 && std::memcmp(begin, constants::extended_iso_date_format(), 8 * sizeof(char_type)) == 0)
+ {
+ callback.on_extended_iso_date();
+ return begin + 8;
+ }
+ else if (len >= 6 && std::memcmp(begin, constants::iso_date_format(), 6 * sizeof(char_type)) == 0)
+ {
+ callback.on_iso_date();
+ return begin + 6;
+ }
+ else
+ {
+ callback.on_full_year();
+ }
+ }
+ break;
+
+ case 'y':
+ this->flush(callback);
+ callback.on_short_year();
+ break;
+
+ case 'm':
+ this->flush(callback);
+ callback.on_numeric_month();
+ break;
+
+ case 'B':
+ this->flush(callback);
+ callback.on_full_month();
+ break;
+
+ case 'b':
+ this->flush(callback);
+ callback.on_short_month();
+ break;
+
+ case 'd':
+ this->flush(callback);
+ callback.on_month_day(true);
+ break;
+
+ case 'e':
+ this->flush(callback);
+ callback.on_month_day(false);
+ break;
+
+ case 'w':
+ this->flush(callback);
+ callback.on_numeric_week_day();
+ break;
+
+ case 'A':
+ this->flush(callback);
+ callback.on_full_week_day();
+ break;
+
+ case 'a':
+ this->flush(callback);
+ callback.on_short_week_day();
+ break;
+
+ default:
+ return BaseT::parse(begin, end, callback);
+ }
+
+ return begin + 2;
+ }
+};
+
+template< typename BaseT >
+struct time_flags :
+ public BaseT
+{
+ typedef typename BaseT::callback_type callback_type;
+ typedef typename BaseT::char_type char_type;
+
+ const char_type* parse(const char_type* begin, const char_type* end, callback_type& callback)
+ {
+ typedef string_constants< char_type > constants;
+
+ switch (begin[1])
+ {
+ case 'O':
+ case 'H':
+ {
+ this->flush(callback);
+
+ std::size_t len = end - begin;
+ if (len >= 11 && std::memcmp(begin, constants::default_time_format(), 11 * sizeof(char_type)) == 0)
+ {
+ callback.on_default_time();
+ return begin + 11;
+ }
+ else if (len >= 8 && std::memcmp(begin, constants::extended_iso_time_format(), 8 * sizeof(char_type)) == 0)
+ {
+ callback.on_extended_iso_time();
+ return begin + 8;
+ }
+ else if (len >= 6 && std::memcmp(begin, constants::iso_time_format(), 6 * sizeof(char_type)) == 0)
+ {
+ callback.on_iso_time();
+ return begin + 6;
+ }
+ else
+ {
+ callback.on_hours(true);
+ }
+ }
+ break;
+
+ case 'T':
+ this->flush(callback);
+ callback.on_extended_iso_time();
+ break;
+
+ case 'k':
+ this->flush(callback);
+ callback.on_hours(false);
+ break;
+
+ case 'I':
+ this->flush(callback);
+ callback.on_hours_12(true);
+ break;
+
+ case 'l':
+ this->flush(callback);
+ callback.on_hours_12(false);
+ break;
+
+ case 'M':
+ this->flush(callback);
+ callback.on_minutes();
+ break;
+
+ case 'S':
+ this->flush(callback);
+ callback.on_seconds();
+ break;
+
+ case 'f':
+ this->flush(callback);
+ callback.on_fractional_seconds();
+ break;
+
+ case 'P':
+ this->flush(callback);
+ callback.on_am_pm(false);
+ break;
+
+ case 'p':
+ this->flush(callback);
+ callback.on_am_pm(true);
+ break;
+
+ case 'Q':
+ this->flush(callback);
+ callback.on_extended_iso_time_zone();
+ break;
+
+ case 'q':
+ this->flush(callback);
+ callback.on_iso_time_zone();
+ break;
+
+ case '-':
+ this->flush(callback);
+ callback.on_duration_sign(false);
+ break;
+
+ case '+':
+ this->flush(callback);
+ callback.on_duration_sign(true);
+ break;
+
+ default:
+ return BaseT::parse(begin, end, callback);
+ }
+
+ return begin + 2;
+ }
+};
+
+template< typename CharT, typename ParserT, typename CallbackT >
+inline void parse_format(const CharT* begin, const CharT* end, ParserT& parser, CallbackT& callback)
+{
+ typedef CharT char_type;
+
+ while (begin != end)
+ {
+ const char_type* p = std::find(begin, end, static_cast< char_type >('%'));
+ parser.add_literal(begin, p);
+
+ if ((end - p) >= 2)
+ {
+ begin = parser.parse(p, end, callback);
+ }
+ else
+ {
+ if (p != end)
+ parser.add_literal(p, end); // a single '%' character at the end of the string
+ begin = end;
+ }
+ }
+
+ parser.flush(callback);
+}
+
+} // namespace
+
+//! Parses the date format string and invokes the callback object
+template< typename CharT >
+BOOST_LOG_API void parse_date_format(const CharT* begin, const CharT* end, date_format_parser_callback< CharT >& callback)
+{
+ typedef CharT char_type;
+ typedef date_format_parser_callback< char_type > callback_type;
+ date_flags< common_flags< callback_type > > parser;
+ parse_format(begin, end, parser, callback);
+}
+
+//! Parses the time format string and invokes the callback object
+template< typename CharT >
+BOOST_LOG_API void parse_time_format(const CharT* begin, const CharT* end, time_format_parser_callback< CharT >& callback)
+{
+ typedef CharT char_type;
+ typedef time_format_parser_callback< char_type > callback_type;
+ time_flags< common_flags< callback_type > > parser;
+ parse_format(begin, end, parser, callback);
+}
+
+//! Parses the date and time format string and invokes the callback object
+template< typename CharT >
+BOOST_LOG_API void parse_date_time_format(const CharT* begin, const CharT* end, date_time_format_parser_callback< CharT >& callback)
+{
+ typedef CharT char_type;
+ typedef date_time_format_parser_callback< char_type > callback_type;
+ date_flags< time_flags< common_flags< callback_type > > > parser;
+ parse_format(begin, end, parser, callback);
+}
+
+template< typename CharT >
+BOOST_LOG_API void put_integer(boost::log::aux::basic_ostringstreambuf< CharT >& strbuf, uint32_t value, unsigned int width, CharT fill_char)
+{
+ typedef CharT char_type;
+ char_type buf[std::numeric_limits< uint32_t >::digits10 + 2];
+ char_type* p = buf;
+
+ typedef karma::uint_generator< uint32_t, 10 > uint_gen;
+ karma::generate(p, uint_gen(), value);
+ const std::size_t len = p - buf;
+ if (len < width)
+ strbuf.append(width - len, fill_char);
+ strbuf.append(buf, len);
+}
+
+#ifdef BOOST_LOG_USE_CHAR
+
+template BOOST_LOG_API
+void parse_date_format(const char* begin, const char* end, date_format_parser_callback< char >& callback);
+template BOOST_LOG_API
+void parse_time_format(const char* begin, const char* end, time_format_parser_callback< char >& callback);
+template BOOST_LOG_API
+void parse_date_time_format(const char* begin, const char* end, date_time_format_parser_callback< char >& callback);
+template BOOST_LOG_API
+void put_integer(boost::log::aux::basic_ostringstreambuf< char >& strbuf, uint32_t value, unsigned int width, char fill_char);
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+template BOOST_LOG_API
+void parse_date_format(const wchar_t* begin, const wchar_t* end, date_format_parser_callback< wchar_t >& callback);
+template BOOST_LOG_API
+void parse_time_format(const wchar_t* begin, const wchar_t* end, time_format_parser_callback< wchar_t >& callback);
+template BOOST_LOG_API
+void parse_date_time_format(const wchar_t* begin, const wchar_t* end, date_time_format_parser_callback< wchar_t >& callback);
+template BOOST_LOG_API
+void put_integer(boost::log::aux::basic_ostringstreambuf< wchar_t >& strbuf, uint32_t value, unsigned int width, wchar_t fill_char);
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/default_attribute_names.cpp b/src/boost/libs/log/src/default_attribute_names.cpp
new file mode 100644
index 000000000..81bce3b9d
--- /dev/null
+++ b/src/boost/libs/log/src/default_attribute_names.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_attribute_names.cpp
+ * \author Andrey Semashev
+ * \date 13.07.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/log/detail/default_attribute_names.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+namespace default_attribute_names {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ class names :
+ public lazy_singleton< names, shared_ptr< names > >
+ {
+ private:
+ typedef lazy_singleton< names, shared_ptr< names > > base_type;
+
+#if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
+ friend class lazy_singleton< names, shared_ptr< names > >;
+#else
+ friend class base_type;
+#endif
+
+ public:
+ const attribute_name severity;
+ const attribute_name channel;
+ const attribute_name message;
+ const attribute_name line_id;
+ const attribute_name timestamp;
+ const attribute_name process_id;
+ const attribute_name thread_id;
+
+ private:
+ names() :
+ severity("Severity"),
+ channel("Channel"),
+ message("Message"),
+ line_id("LineID"),
+ timestamp("TimeStamp"),
+ process_id("ProcessID"),
+ thread_id("ThreadID")
+ {
+ }
+
+ static void init_instance()
+ {
+ get_instance().reset(new names());
+ }
+
+ public:
+ static names& get()
+ {
+ return *base_type::get();
+ }
+ };
+
+} // namespace
+
+BOOST_LOG_API attribute_name severity()
+{
+ return names::get().severity;
+}
+
+BOOST_LOG_API attribute_name channel()
+{
+ return names::get().channel;
+}
+
+BOOST_LOG_API attribute_name message()
+{
+ return names::get().message;
+}
+
+BOOST_LOG_API attribute_name line_id()
+{
+ return names::get().line_id;
+}
+
+BOOST_LOG_API attribute_name timestamp()
+{
+ return names::get().timestamp;
+}
+
+BOOST_LOG_API attribute_name process_id()
+{
+ return names::get().process_id;
+}
+
+BOOST_LOG_API attribute_name thread_id()
+{
+ return names::get().thread_id;
+}
+
+} // namespace default_attribute_names
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/default_sink.cpp b/src/boost/libs/log/src/default_sink.cpp
new file mode 100644
index 000000000..00188f35f
--- /dev/null
+++ b/src/boost/libs/log/src/default_sink.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_sink.cpp
+ * \author Andrey Semashev
+ * \date 19.04.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstdio>
+#include <boost/optional/optional.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/locks.hpp>
+#include <boost/log/detail/thread_id.hpp>
+#endif
+#include <boost/log/detail/default_attribute_names.hpp>
+#include <boost/date_time/microsec_time_clock.hpp>
+#include <boost/date_time/time_resolution_traits.hpp>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+#include "default_sink.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+namespace aux {
+
+// Defined in thread_id.cpp
+void format_thread_id(char* buf, std::size_t size, thread::id tid);
+
+} // namespace aux
+
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+namespace sinks {
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! A special time point type that contains decomposed date and time to avoid excessive calculations
+struct decomposed_time_point
+{
+ struct date_type :
+ public gregorian::greg_year_month_day
+ {
+ date_type(year_type y, month_type m, day_type d) :
+ gregorian::greg_year_month_day(y, m, d)
+ {
+ }
+ };
+
+ struct time_duration_type :
+ public date_time::micro_res
+ {
+ typedef date_time::micro_res rep_type;
+
+ hour_type hours;
+ min_type minutes;
+ sec_type seconds;
+ fractional_seconds_type useconds;
+
+ time_duration_type(hour_type h, min_type m, sec_type s, fractional_seconds_type u) :
+ hours(h),
+ minutes(m),
+ seconds(s),
+ useconds(u)
+ {
+ }
+ };
+
+ date_type date;
+ time_duration_type time;
+
+ decomposed_time_point(date_type const& d, time_duration_type const& t) :
+ date(d),
+ time(t)
+ {
+ }
+};
+
+inline const char* severity_level_to_string(boost::log::trivial::severity_level lvl)
+{
+ switch (lvl)
+ {
+ case boost::log::trivial::trace:
+ return "[trace] ";
+ case boost::log::trivial::debug:
+ return "[debug] ";
+ case boost::log::trivial::info:
+ return "[info] ";
+ case boost::log::trivial::warning:
+ return "[warning]";
+ case boost::log::trivial::error:
+ return "[error] ";
+ case boost::log::trivial::fatal:
+ return "[fatal] ";
+ default:
+ return "[-] ";
+ }
+}
+
+struct message_printer
+{
+ typedef void result_type;
+
+ explicit message_printer(boost::log::trivial::severity_level lvl) : m_level(lvl)
+ {
+ }
+
+#ifdef BOOST_LOG_USE_CHAR
+
+ result_type operator() (std::string const& msg) const
+ {
+#if !defined(BOOST_LOG_NO_THREADS)
+ char thread_id_buf[64];
+ boost::log::aux::format_thread_id(thread_id_buf, sizeof(thread_id_buf), boost::log::aux::this_thread::get_id());
+#endif
+
+ const decomposed_time_point now = date_time::microsec_clock< decomposed_time_point >::local_time();
+
+ std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%06u] "
+#if !defined(BOOST_LOG_NO_THREADS)
+ "[%s] "
+#endif
+ "%s %s\n",
+ static_cast< unsigned int >(now.date.year),
+ static_cast< unsigned int >(now.date.month),
+ static_cast< unsigned int >(now.date.day),
+ static_cast< unsigned int >(now.time.hours),
+ static_cast< unsigned int >(now.time.minutes),
+ static_cast< unsigned int >(now.time.seconds),
+ static_cast< unsigned int >(now.time.useconds),
+#if !defined(BOOST_LOG_NO_THREADS)
+ thread_id_buf,
+#endif
+ severity_level_to_string(m_level),
+ msg.c_str());
+ }
+
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+ result_type operator() (std::wstring const& msg) const
+ {
+#if !defined(BOOST_LOG_NO_THREADS)
+ char thread_id_buf[64];
+ boost::log::aux::format_thread_id(thread_id_buf, sizeof(thread_id_buf), boost::log::aux::this_thread::get_id());
+#endif
+
+ const decomposed_time_point now = date_time::microsec_clock< decomposed_time_point >::local_time();
+
+ std::printf("[%04u-%02u-%02u %02u:%02u:%02u.%06u] "
+#if !defined(BOOST_LOG_NO_THREADS)
+ "[%s] "
+#endif
+ "%s %ls\n",
+ static_cast< unsigned int >(now.date.year),
+ static_cast< unsigned int >(now.date.month),
+ static_cast< unsigned int >(now.date.day),
+ static_cast< unsigned int >(now.time.hours),
+ static_cast< unsigned int >(now.time.minutes),
+ static_cast< unsigned int >(now.time.seconds),
+ static_cast< unsigned int >(now.time.useconds),
+#if !defined(BOOST_LOG_NO_THREADS)
+ thread_id_buf,
+#endif
+ severity_level_to_string(m_level),
+ msg.c_str());
+ }
+
+#endif
+
+private:
+ const boost::log::trivial::severity_level m_level;
+};
+
+} // namespace
+
+default_sink::default_sink() :
+ sink(false),
+ m_severity_name(boost::log::aux::default_attribute_names::severity()),
+ m_message_name(boost::log::aux::default_attribute_names::message()),
+ m_severity_extractor(boost::log::trivial::info)
+{
+}
+
+default_sink::~default_sink()
+{
+}
+
+bool default_sink::will_consume(attribute_value_set const&)
+{
+ return true;
+}
+
+void default_sink::consume(record_view const& rec)
+{
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);)
+ m_message_visitor(m_message_name, rec.attribute_values(), message_printer(m_severity_extractor(m_severity_name, rec).get()));
+ std::fflush(stdout);
+}
+
+void default_sink::flush()
+{
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);)
+ std::fflush(stdout);
+}
+
+} // namespace aux
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/default_sink.hpp b/src/boost/libs/log/src/default_sink.hpp
new file mode 100644
index 000000000..bdcd3f46f
--- /dev/null
+++ b/src/boost/libs/log/src/default_sink.hpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_sink.hpp
+ * \author Andrey Semashev
+ * \date 08.01.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_DEFAULT_SINK_HPP_INCLUDED_
+#define BOOST_LOG_DEFAULT_SINK_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/sinks/sink.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/attributes/fallback_policy.hpp>
+#include <boost/log/expressions/message.hpp>
+#include <boost/log/trivial.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/mutex.hpp>
+#endif
+#include <boost/log/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+namespace aux {
+
+//! The default sink to be used when no sinks are registered in the logging core
+class default_sink :
+ public sink
+{
+private:
+#if !defined(BOOST_LOG_NO_THREADS)
+ typedef mutex mutex_type;
+ mutex_type m_mutex;
+#endif
+ attribute_name const m_severity_name, m_message_name;
+ value_extractor< boost::log::trivial::severity_level, fallback_to_default< boost::log::trivial::severity_level > > const m_severity_extractor;
+ value_visitor_invoker< expressions::tag::message::value_type > m_message_visitor;
+
+public:
+ default_sink();
+ ~default_sink();
+ bool will_consume(attribute_value_set const&);
+ void consume(record_view const& rec);
+ void flush();
+};
+
+} // namespace aux
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_DEFAULT_SINK_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/dump.cpp b/src/boost/libs/log/src/dump.cpp
new file mode 100644
index 000000000..e23cb2b43
--- /dev/null
+++ b/src/boost/libs/log/src/dump.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file dump.cpp
+ * \author Andrey Semashev
+ * \date 03.05.2013
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <ostream>
+#include <boost/cstdint.hpp>
+#include <boost/log/utility/manipulators/dump.hpp>
+#if defined(_MSC_VER) && (defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2))
+#include <boost/winapi/dll.hpp>
+#include <intrin.h> // __cpuid
+#endif
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#if defined(BOOST_LOG_USE_SSSE3)
+extern dump_data_char_t dump_data_char_ssse3;
+extern dump_data_wchar_t dump_data_wchar_ssse3;
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+extern dump_data_char16_t dump_data_char16_ssse3;
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+extern dump_data_char32_t dump_data_char32_ssse3;
+#endif
+#endif
+#if defined(BOOST_LOG_USE_AVX2)
+extern dump_data_char_t dump_data_char_avx2;
+extern dump_data_wchar_t dump_data_wchar_avx2;
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+extern dump_data_char16_t dump_data_char16_avx2;
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+extern dump_data_char32_t dump_data_char32_avx2;
+#endif
+#endif
+
+enum { stride = 256 };
+
+extern const char g_hex_char_table[2][16] =
+{
+ { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' },
+ { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }
+};
+
+template< typename CharT >
+void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
+{
+ typedef CharT char_type;
+
+ char_type buf[stride * 3u];
+
+ const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0];
+ const std::size_t stride_count = size / stride, tail_size = size % stride;
+
+ const uint8_t* p = static_cast< const uint8_t* >(data);
+ char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
+ char_type* buf_end = buf + sizeof(buf) / sizeof(*buf);
+
+ for (std::size_t i = 0; i < stride_count; ++i)
+ {
+ char_type* b = buf;
+ for (unsigned int j = 0; j < stride; ++j, b += 3u, ++p)
+ {
+ uint32_t n = *p;
+ b[0] = static_cast< char_type >(' ');
+ b[1] = static_cast< char_type >(char_table[n >> 4]);
+ b[2] = static_cast< char_type >(char_table[n & 0x0F]);
+ }
+
+ strm.write(buf_begin, buf_end - buf_begin);
+ buf_begin = buf;
+ }
+
+ if (tail_size > 0)
+ {
+ char_type* b = buf;
+ unsigned int i = 0;
+ do
+ {
+ uint32_t n = *p;
+ b[0] = static_cast< char_type >(' ');
+ b[1] = static_cast< char_type >(char_table[n >> 4]);
+ b[2] = static_cast< char_type >(char_table[n & 0x0F]);
+ ++i;
+ ++p;
+ b += 3u;
+ }
+ while (i < tail_size);
+
+ strm.write(buf_begin, b - buf_begin);
+ }
+}
+
+BOOST_LOG_API dump_data_char_t* dump_data_char = &dump_data_generic< char >;
+BOOST_LOG_API dump_data_wchar_t* dump_data_wchar = &dump_data_generic< wchar_t >;
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+BOOST_LOG_API dump_data_char16_t* dump_data_char16 = &dump_data_generic< char16_t >;
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+BOOST_LOG_API dump_data_char32_t* dump_data_char32 = &dump_data_generic< char32_t >;
+#endif
+
+#if defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+struct function_pointer_initializer
+{
+ function_pointer_initializer()
+ {
+ // First, let's check for the max supported cpuid function
+ uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+ cpuid(eax, ebx, ecx, edx);
+
+ const uint32_t max_cpuid_function = eax;
+ if (max_cpuid_function >= 1)
+ {
+ eax = 1;
+ ebx = ecx = edx = 0;
+ cpuid(eax, ebx, ecx, edx);
+
+ // Check for SSSE3 support
+ if (ecx & (1u << 9))
+ enable_ssse3();
+
+#if defined(BOOST_LOG_USE_AVX2)
+ if (max_cpuid_function >= 7)
+ {
+ // To check for AVX2 availability we also need to verify that OS supports it
+ // Check that OSXSAVE is supported by CPU
+ if (ecx & (1u << 27))
+ {
+ // Check that it is used by the OS
+ bool mmstate = false;
+#if defined(__GNUC__)
+ // Get the XFEATURE_ENABLED_MASK register
+ __asm__ __volatile__
+ (
+ "xgetbv\n\t"
+ : "=a" (eax), "=d" (edx)
+ : "c" (0)
+ );
+ mmstate = (eax & 6U) == 6U;
+#elif defined(BOOST_WINDOWS)
+ // MSVC does not have an intrinsic for xgetbv, we have to query OS
+ boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ {
+ typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t);
+ get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures");
+ if (get_enabled_extended_features)
+ {
+ // XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6
+ mmstate = get_enabled_extended_features(6u) == 6u;
+ }
+ }
+#endif
+
+ if (mmstate)
+ {
+ // Finally, check for AVX2 support in CPU
+ eax = 7;
+ ebx = ecx = edx = 0;
+ cpuid(eax, ebx, ecx, edx);
+
+ if (ebx & (1U << 5))
+ enable_avx2();
+ }
+ }
+ }
+#endif // defined(BOOST_LOG_USE_AVX2)
+ }
+ }
+
+private:
+ static void cpuid(uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx)
+ {
+#if defined(__GNUC__)
+#if (defined(__i386__) || defined(__VXWORKS__)) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && BOOST_GCC >= 50100))
+ // Unless the compiler can do it automatically, we have to backup ebx in 32-bit PIC/PIE code because it is reserved by the ABI.
+ // For VxWorks ebx is reserved on 64-bit as well.
+#if defined(__x86_64__)
+ uint64_t rbx = ebx;
+ __asm__ __volatile__
+ (
+ "xchgq %%rbx, %0\n\t"
+ "cpuid\n\t"
+ "xchgq %%rbx, %0\n\t"
+ : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx)
+ );
+ ebx = static_cast< uint32_t >(rbx);
+#else // defined(__x86_64__)
+ __asm__ __volatile__
+ (
+ "xchgl %%ebx, %0\n\t"
+ "cpuid\n\t"
+ "xchgl %%ebx, %0\n\t"
+ : "+DS" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx)
+ );
+#endif // defined(__x86_64__)
+#else
+ __asm__ __volatile__
+ (
+ "cpuid\n\t"
+ : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)
+ );
+#endif
+#elif defined(_MSC_VER)
+ int regs[4] = {};
+ __cpuid(regs, eax);
+ eax = regs[0];
+ ebx = regs[1];
+ ecx = regs[2];
+ edx = regs[3];
+#else
+#error Boost.Log: Unexpected compiler
+#endif
+ }
+
+ static void enable_ssse3()
+ {
+ dump_data_char = &dump_data_char_ssse3;
+ dump_data_wchar = &dump_data_wchar_ssse3;
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+ dump_data_char16 = &dump_data_char16_ssse3;
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+ dump_data_char32 = &dump_data_char32_ssse3;
+#endif
+ }
+
+#if defined(BOOST_LOG_USE_AVX2)
+ static void enable_avx2()
+ {
+ dump_data_char = &dump_data_char_avx2;
+ dump_data_wchar = &dump_data_wchar_avx2;
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+ dump_data_char16 = &dump_data_char16_avx2;
+#endif
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+ dump_data_char32 = &dump_data_char32_avx2;
+#endif
+ }
+#endif // defined(BOOST_LOG_USE_AVX2)
+};
+
+static function_pointer_initializer g_function_pointer_initializer;
+
+} // namespace
+
+#endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/dump_avx2.cpp b/src/boost/libs/log/src/dump_avx2.cpp
new file mode 100644
index 000000000..4ab12500f
--- /dev/null
+++ b/src/boost/libs/log/src/dump_avx2.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file dump_avx2.cpp
+ * \author Andrey Semashev
+ * \date 05.05.2013
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+// NOTE: You should generally avoid including headers as much as possible here, because this file
+// is compiled with special compiler options, and any included header may result in generation of
+// unintended code with these options and violation of ODR.
+#include <boost/log/detail/config.hpp>
+#include <ostream>
+#include <immintrin.h>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/header.hpp>
+
+#if defined(__x86_64) || defined(__x86_64__) || \
+ defined(__amd64__) || defined(__amd64) || \
+ defined(_M_X64)
+#define BOOST_LOG_AUX_X86_64
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+extern const char g_hex_char_table[2][16];
+
+template< typename CharT >
+extern void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm);
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+enum
+{
+ packs_per_stride = 32,
+ stride = packs_per_stride * 32
+};
+
+union ymm_constant
+{
+ uint8_t as_bytes[32];
+ __m256i as_mm;
+
+ BOOST_FORCEINLINE operator __m256i () const { return as_mm; }
+};
+
+static const ymm_constant mm_shuffle_pattern1 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80 }};
+static const ymm_constant mm_shuffle_pattern2 = {{ 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10 }};
+static const ymm_constant mm_shuffle_pattern3 = {{ 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15 }};
+static const ymm_constant mm_shuffle_pattern13 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15 }};
+
+#if defined(BOOST_LOG_AUX_X86_64)
+
+// x86-64 architecture has more registers which we can utilize to pass constants
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL __m256i mm_15, __m256i mm_9, __m256i mm_char_0, __m256i mm_char_space,
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_15, mm_9, mm_char_0, mm_char_space,
+#define BOOST_LOG_AUX_MM_CONSTANTS \
+ const __m256i mm_15 = _mm256_set1_epi32(0x0F0F0F0F);\
+ const __m256i mm_9 = _mm256_set1_epi32(0x09090909);\
+ const __m256i mm_char_0 = _mm256_set1_epi32(0x30303030);\
+ const __m256i mm_char_space = _mm256_set1_epi32(0x20202020);
+
+#else
+
+// MSVC in 32-bit mode is not able to pass all constants to dump_pack, and is also not able to align them on the stack, so we have to fetch them from global constants
+static const ymm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }};
+static const ymm_constant mm_9 = {{ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09 }};
+static const ymm_constant mm_char_0 = {{ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 }};
+static const ymm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }};
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS
+#define BOOST_LOG_AUX_MM_CONSTANTS
+
+#endif
+
+/*!
+ * \brief Dumps a pack of input data into a string of 8 bit ASCII characters.
+ *
+ * The composed string is placed as follows (in Intel notation): mm_output1[127:0], mm_output2[127:0], mm_output3[127:0], mm_output1[255:128], mm_output2[255:128], mm_output3[255:128].
+ */
+static BOOST_FORCEINLINE void dump_pack
+(
+ BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL
+ __m256i mm_char_10_to_a, __m256i mm_input,
+ __m256i& mm_output1, __m256i& mm_output2, __m256i& mm_output3
+)
+{
+ // Split half-bytes
+ __m256i mm_input_hi = _mm256_and_si256(_mm256_srli_epi16(mm_input, 4), mm_15);
+ __m256i mm_input_lo = _mm256_and_si256(mm_input, mm_15);
+
+ // Stringize each of the halves
+ __m256i mm_addend_hi = _mm256_cmpgt_epi8(mm_input_hi, mm_9);
+ __m256i mm_addend_lo = _mm256_cmpgt_epi8(mm_input_lo, mm_9);
+ mm_addend_hi = _mm256_and_si256(mm_char_10_to_a, mm_addend_hi);
+ mm_addend_lo = _mm256_and_si256(mm_char_10_to_a, mm_addend_lo);
+
+ mm_input_hi = _mm256_add_epi8(mm_input_hi, mm_char_0);
+ mm_input_lo = _mm256_add_epi8(mm_input_lo, mm_char_0);
+
+ mm_input_hi = _mm256_add_epi8(mm_input_hi, mm_addend_hi);
+ mm_input_lo = _mm256_add_epi8(mm_input_lo, mm_addend_lo);
+
+ // Join them back together
+ __m256i mm_1 = _mm256_unpacklo_epi8(mm_input_hi, mm_input_lo);
+ __m256i mm_2 = _mm256_unpackhi_epi8(mm_input_hi, mm_input_lo);
+
+ // Insert spaces between stringized bytes:
+ // |0123456789abcdef|0123456789abcdef|
+ // | 01 23 45 67 89 |ab cd ef 01 23 4|5 67 89 ab cd ef|
+ __m256i mm_out1 = _mm256_shuffle_epi8(mm_1, mm_shuffle_pattern1.as_mm);
+ __m256i mm_out3 = _mm256_shuffle_epi8(mm_2, mm_shuffle_pattern3.as_mm);
+ __m256i mm_out2 = _mm256_shuffle_epi8(_mm256_alignr_epi8(mm_2, mm_1, 10), mm_shuffle_pattern2.as_mm);
+
+ mm_output1 = _mm256_max_epu8(mm_out1, mm_char_space);
+ mm_output2 = _mm256_max_epu8(mm_out2, mm_char_space);
+ mm_output3 = _mm256_max_epu8(mm_out3, mm_char_space);
+}
+
+//! Dumps a pack of input data into a string of 8 bit ASCII characters
+static BOOST_FORCEINLINE void dump_pack
+(
+ BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL
+ __m256i mm_char_10_to_a, __m128i mm_input,
+ __m128i& mm_output1, __m128i& mm_output2, __m128i& mm_output3
+)
+{
+ // Split half-bytes
+ __m128i mm_input_hi = _mm_srli_epi16(mm_input, 4);
+ __m256i mm = _mm256_inserti128_si256(_mm256_castsi128_si256(_mm_unpacklo_epi8(mm_input_hi, mm_input)), _mm_unpackhi_epi8(mm_input_hi, mm_input), 1);
+ mm = _mm256_and_si256(mm, mm_15);
+
+ // Stringize the halves
+ __m256i mm_addend = _mm256_cmpgt_epi8(mm, mm_9);
+ mm_addend = _mm256_and_si256(mm_char_10_to_a, mm_addend);
+
+ mm = _mm256_add_epi8(mm, mm_char_0);
+ mm = _mm256_add_epi8(mm, mm_addend);
+
+ // Insert spaces between stringized bytes:
+ __m256i mm_out13 = _mm256_shuffle_epi8(mm, mm_shuffle_pattern13.as_mm);
+ __m128i mm_out2 = _mm_shuffle_epi8(_mm_alignr_epi8(_mm256_extracti128_si256(mm, 1), _mm256_castsi256_si128(mm), 10), _mm256_castsi256_si128(mm_shuffle_pattern2.as_mm));
+
+ mm_out13 = _mm256_max_epu8(mm_out13, mm_char_space);
+ mm_output2 = _mm_max_epu8(mm_out2, _mm256_castsi256_si128(mm_char_space));
+ mm_output1 = _mm256_castsi256_si128(mm_out13);
+ mm_output3 = _mm256_extracti128_si256(mm_out13, 1);
+}
+
+template< typename CharT >
+BOOST_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf)
+{
+ switch (sizeof(CharT))
+ {
+ case 1:
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars);
+ break;
+
+ case 2:
+ _mm256_store_si256(reinterpret_cast< __m256i* >(buf), _mm256_cvtepu8_epi16(mm_chars));
+ break;
+
+ case 4:
+ {
+ __m128i mm = _mm_unpackhi_epi64(mm_chars, mm_chars);
+ _mm256_store_si256(reinterpret_cast< __m256i* >(buf), _mm256_cvtepu8_epi32(mm_chars));
+ _mm256_store_si256(reinterpret_cast< __m256i* >(buf) + 1, _mm256_cvtepu8_epi32(mm));
+ }
+ break;
+ }
+}
+
+template< typename CharT >
+BOOST_FORCEINLINE void store_characters_x3(__m256i mm_chars1, __m256i mm_chars2, __m256i mm_chars3, CharT* buf)
+{
+ store_characters(_mm256_castsi256_si128(mm_chars1), buf);
+ store_characters(_mm256_castsi256_si128(mm_chars2), buf + 16);
+ store_characters(_mm256_castsi256_si128(mm_chars3), buf + 32);
+ store_characters(_mm256_extracti128_si256(mm_chars1, 1), buf + 48);
+ store_characters(_mm256_extracti128_si256(mm_chars2, 1), buf + 64);
+ store_characters(_mm256_extracti128_si256(mm_chars3, 1), buf + 80);
+}
+
+template< typename CharT >
+BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
+{
+ typedef CharT char_type;
+
+ char_type buf_storage[stride * 3u + 32u];
+ // Align the temporary buffer at 32 bytes
+ char_type* const buf = reinterpret_cast< char_type* >((uint8_t*)buf_storage + (32u - (((uintptr_t)(char_type*)buf_storage) & 31u)));
+ char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
+ char_type* buf_end = buf + stride * 3u;
+
+ __m256i mm_char_10_to_a;
+ if (strm.flags() & std::ios_base::uppercase)
+ mm_char_10_to_a = _mm256_set1_epi32(0x07070707); // '9' is 0x39 and 'A' is 0x41 in ASCII, so we have to add 0x07 to 0x3A to get uppercase letters
+ else
+ mm_char_10_to_a = _mm256_set1_epi32(0x27272727); // ...and 'a' is 0x61, which means we have to add 0x27 to 0x3A to get lowercase letters
+
+ // First, check the input alignment. Also, if we can dump the whole data in one go, do it right away. It turns out to be faster than splitting
+ // the work between prealign and tail part. It is also a fairly common case since on most platforms memory is not aligned to 32 bytes (i.e. prealign is often needed).
+ const uint8_t* p = static_cast< const uint8_t* >(data);
+ const std::size_t prealign_size = size == 32u ? static_cast< std::size_t >(32u) : static_cast< std::size_t >((32u - ((uintptr_t)p & 31u)) & 31u);
+ if (prealign_size)
+ {
+ __m256i mm_input = _mm256_lddqu_si256(reinterpret_cast< const __m256i* >(p));
+ BOOST_LOG_AUX_MM_CONSTANTS
+
+ __m256i mm_output1, mm_output2, mm_output3;
+ dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+
+ store_characters_x3(mm_output1, mm_output2, mm_output3, buf);
+
+ _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call
+ strm.write(buf_begin, prealign_size * 3u - 1u);
+
+ buf_begin = buf;
+ size -= prealign_size;
+ p += prealign_size;
+ }
+
+ const std::size_t stride_count = size / stride;
+ std::size_t tail_size = size % stride;
+ for (std::size_t i = 0; i < stride_count; ++i)
+ {
+ char_type* b = buf;
+ BOOST_LOG_AUX_MM_CONSTANTS
+
+ for (unsigned int j = 0; j < packs_per_stride; ++j, b += 3u * 32u, p += 32u)
+ {
+ __m256i mm_input = _mm256_load_si256(reinterpret_cast< const __m256i* >(p));
+ __m256i mm_output1, mm_output2, mm_output3;
+ dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+
+ store_characters_x3(mm_output1, mm_output2, mm_output3, b);
+ }
+
+ _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call
+ strm.write(buf_begin, buf_end - buf_begin);
+ buf_begin = buf;
+ }
+
+ if (BOOST_UNLIKELY(tail_size > 0))
+ {
+ char_type* b = buf;
+ while (tail_size >= 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ BOOST_LOG_AUX_MM_CONSTANTS
+
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+
+ store_characters(mm_output1, b);
+ store_characters(mm_output2, b + 16u);
+ store_characters(mm_output3, b + 32u);
+
+ b += 3u * 16u;
+ p += 16u;
+ tail_size -= 16u;
+ }
+
+ _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call
+ const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0];
+ for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u)
+ {
+ uint32_t n = *p;
+ b[0] = static_cast< char_type >(' ');
+ b[1] = static_cast< char_type >(char_table[n >> 4]);
+ b[2] = static_cast< char_type >(char_table[n & 0x0F]);
+ }
+
+ strm.write(buf_begin, b - buf_begin);
+ }
+}
+
+} // namespace
+
+void dump_data_char_avx2(const void* data, std::size_t size, std::basic_ostream< char >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+void dump_data_wchar_avx2(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+void dump_data_char16_avx2(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+void dump_data_char32_avx2(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/dump_ssse3.cpp b/src/boost/libs/log/src/dump_ssse3.cpp
new file mode 100644
index 000000000..1325b49c0
--- /dev/null
+++ b/src/boost/libs/log/src/dump_ssse3.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file dump_ssse3.cpp
+ * \author Andrey Semashev
+ * \date 05.05.2013
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+// NOTE: You should generally avoid including headers as much as possible here, because this file
+// is compiled with special compiler options, and any included header may result in generation of
+// unintended code with these options and violation of ODR.
+#include <boost/log/detail/config.hpp>
+#include <ostream>
+#include <tmmintrin.h>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/header.hpp>
+
+#if defined(__x86_64) || defined(__x86_64__) || \
+ defined(__amd64__) || defined(__amd64) || \
+ defined(_M_X64)
+#define BOOST_LOG_AUX_X86_64
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+extern const char g_hex_char_table[2][16];
+
+template< typename CharT >
+extern void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm);
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+enum
+{
+ packs_per_stride = 32,
+ stride = packs_per_stride * 16
+};
+
+union xmm_constant
+{
+ uint8_t as_bytes[16];
+ __m128i as_mm;
+
+ BOOST_FORCEINLINE operator __m128i () const { return as_mm; }
+};
+
+static const xmm_constant mm_shuffle_pattern1 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80 }};
+static const xmm_constant mm_shuffle_pattern2 = {{ 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10 }};
+static const xmm_constant mm_shuffle_pattern3 = {{ 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15 }};
+
+#if defined(BOOST_LOG_AUX_X86_64)
+
+// x86-64 architecture has more registers which we can utilize to pass constants
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL __m128i mm_15, __m128i mm_9, __m128i mm_char_0, __m128i mm_char_space,
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_15, mm_9, mm_char_0, mm_char_space,
+#define BOOST_LOG_AUX_MM_CONSTANTS \
+ const __m128i mm_15 = _mm_set1_epi32(0x0F0F0F0F);\
+ const __m128i mm_9 = _mm_set1_epi32(0x09090909);\
+ const __m128i mm_char_0 = _mm_set1_epi32(0x30303030);\
+ const __m128i mm_char_space = _mm_set1_epi32(0x20202020);
+
+#else
+
+// MSVC in 32-bit mode is not able to pass all constants to dump_pack, and is also not able to align them on the stack, so we have to fetch them from global constants
+static const xmm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }};
+static const xmm_constant mm_9 = {{ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09 }};
+static const xmm_constant mm_char_0 = {{ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 }};
+static const xmm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }};
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL
+#define BOOST_LOG_AUX_MM_CONSTANT_ARGS
+#define BOOST_LOG_AUX_MM_CONSTANTS
+
+#endif
+
+//! Dumps a pack of input data into a string of 8 bit ASCII characters
+static BOOST_FORCEINLINE void dump_pack
+(
+ BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL
+ __m128i mm_char_10_to_a, __m128i mm_input,
+ __m128i& mm_output1, __m128i& mm_output2, __m128i& mm_output3
+)
+{
+ // Split half-bytes
+ __m128i mm_input_hi = _mm_and_si128(_mm_srli_epi16(mm_input, 4), mm_15);
+ __m128i mm_input_lo = _mm_and_si128(mm_input, mm_15);
+
+ // Stringize each of the halves
+ __m128i mm_addend_hi = _mm_cmpgt_epi8(mm_input_hi, mm_9);
+ __m128i mm_addend_lo = _mm_cmpgt_epi8(mm_input_lo, mm_9);
+ mm_addend_hi = _mm_and_si128(mm_char_10_to_a, mm_addend_hi);
+ mm_addend_lo = _mm_and_si128(mm_char_10_to_a, mm_addend_lo);
+
+ mm_input_hi = _mm_add_epi8(mm_input_hi, mm_char_0);
+ mm_input_lo = _mm_add_epi8(mm_input_lo, mm_char_0);
+
+ mm_input_hi = _mm_add_epi8(mm_input_hi, mm_addend_hi);
+ mm_input_lo = _mm_add_epi8(mm_input_lo, mm_addend_lo);
+
+ // Join them back together
+ __m128i mm_1 = _mm_unpacklo_epi8(mm_input_hi, mm_input_lo);
+ __m128i mm_2 = _mm_unpackhi_epi8(mm_input_hi, mm_input_lo);
+
+ // Insert spaces between stringized bytes:
+ // |0123456789abcdef|0123456789abcdef|
+ // | 01 23 45 67 89 |ab cd ef 01 23 4|5 67 89 ab cd ef|
+ mm_output1 = _mm_shuffle_epi8(mm_1, mm_shuffle_pattern1.as_mm);
+ mm_output2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 10), mm_shuffle_pattern2.as_mm);
+ mm_output3 = _mm_shuffle_epi8(mm_2, mm_shuffle_pattern3.as_mm);
+
+ mm_output1 = _mm_max_epu8(mm_output1, mm_char_space);
+ mm_output2 = _mm_max_epu8(mm_output2, mm_char_space);
+ mm_output3 = _mm_max_epu8(mm_output3, mm_char_space);
+}
+
+template< typename CharT >
+BOOST_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf)
+{
+ switch (sizeof(CharT))
+ {
+ case 1:
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars);
+ break;
+
+ case 2:
+ {
+ __m128i mm_0 = _mm_setzero_si128();
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi8(mm_chars, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi8(mm_chars, mm_0));
+ }
+ break;
+
+ case 4:
+ {
+ __m128i mm_0 = _mm_setzero_si128();
+ __m128i mm = _mm_unpacklo_epi8(mm_chars, mm_0);
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi16(mm, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi16(mm, mm_0));
+ mm = _mm_unpackhi_epi8(mm_chars, mm_0);
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 2, _mm_unpacklo_epi16(mm, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 3, _mm_unpackhi_epi16(mm, mm_0));
+ }
+ break;
+ }
+}
+
+template< typename CharT >
+BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
+{
+ typedef CharT char_type;
+
+ char_type buf_storage[stride * 3u + 16u];
+ // Align the temporary buffer at 16 bytes
+ char_type* const buf = reinterpret_cast< char_type* >((uint8_t*)buf_storage + (16u - (((uintptr_t)(char_type*)buf_storage) & 15u)));
+ char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
+ char_type* buf_end = buf + stride * 3u;
+
+ __m128i mm_char_10_to_a;
+ if (strm.flags() & std::ios_base::uppercase)
+ mm_char_10_to_a = _mm_set1_epi32(0x07070707); // '9' is 0x39 and 'A' is 0x41 in ASCII, so we have to add 0x07 to 0x3A to get uppercase letters
+ else
+ mm_char_10_to_a = _mm_set1_epi32(0x27272727); // ...and 'a' is 0x61, which means we have to add 0x27 to 0x3A to get lowercase letters
+
+ // First, check the input alignment
+ const uint8_t* p = static_cast< const uint8_t* >(data);
+ const std::size_t prealign_size = ((16u - ((uintptr_t)p & 15u)) & 15u);
+ if (BOOST_UNLIKELY(prealign_size > 0))
+ {
+ __m128i mm_input = _mm_lddqu_si128(reinterpret_cast< const __m128i* >(p));
+ BOOST_LOG_AUX_MM_CONSTANTS
+
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+
+ strm.write(buf_begin, prealign_size * 3u - 1u);
+
+ buf_begin = buf;
+ size -= prealign_size;
+ p += prealign_size;
+ }
+
+ const std::size_t stride_count = size / stride;
+ std::size_t tail_size = size % stride;
+ for (std::size_t i = 0; i < stride_count; ++i)
+ {
+ char_type* b = buf;
+ BOOST_LOG_AUX_MM_CONSTANTS
+
+ for (unsigned int j = 0; j < packs_per_stride; ++j, b += 3u * 16u, p += 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+
+ store_characters(mm_output1, b);
+ store_characters(mm_output2, b + 16u);
+ store_characters(mm_output3, b + 32u);
+ }
+
+ strm.write(buf_begin, buf_end - buf_begin);
+ buf_begin = buf;
+ }
+
+ if (BOOST_UNLIKELY(tail_size > 0))
+ {
+ char_type* b = buf;
+ while (tail_size >= 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ BOOST_LOG_AUX_MM_CONSTANTS
+
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+
+ store_characters(mm_output1, b);
+ store_characters(mm_output2, b + 16u);
+ store_characters(mm_output3, b + 32u);
+
+ b += 3u * 16u;
+ p += 16u;
+ tail_size -= 16u;
+ }
+
+ const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0];
+ for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u)
+ {
+ uint32_t n = *p;
+ b[0] = static_cast< char_type >(' ');
+ b[1] = static_cast< char_type >(char_table[n >> 4]);
+ b[2] = static_cast< char_type >(char_table[n & 0x0F]);
+ }
+
+ strm.write(buf_begin, b - buf_begin);
+ }
+}
+
+} // namespace
+
+void dump_data_char_ssse3(const void* data, std::size_t size, std::basic_ostream< char >& strm)
+{
+ if (size >= 16)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+void dump_data_wchar_ssse3(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm)
+{
+ if (size >= 16)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+void dump_data_char16_ssse3(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm)
+{
+ if (size >= 16)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+void dump_data_char32_ssse3(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm)
+{
+ if (size >= 16)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/event.cpp b/src/boost/libs/log/src/event.cpp
new file mode 100644
index 000000000..5485154d7
--- /dev/null
+++ b/src/boost/libs/log/src/event.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file event.cpp
+ * \author Andrey Semashev
+ * \date 24.07.2011
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+
+#ifndef BOOST_LOG_NO_THREADS
+
+#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/log/detail/event.hpp>
+#include <boost/log/exceptions.hpp>
+
+#if defined(BOOST_LOG_EVENT_USE_FUTEX)
+
+#include <stddef.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <linux/futex.h>
+#include <boost/memory_order.hpp>
+
+// Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex
+#if defined(SYS_futex)
+#define BOOST_LOG_SYS_FUTEX SYS_futex
+#else
+#define BOOST_LOG_SYS_FUTEX __NR_futex
+#endif
+
+#if defined(FUTEX_WAIT_PRIVATE)
+#define BOOST_LOG_FUTEX_WAIT FUTEX_WAIT_PRIVATE
+#else
+#define BOOST_LOG_FUTEX_WAIT FUTEX_WAIT
+#endif
+
+#if defined(FUTEX_WAKE_PRIVATE)
+#define BOOST_LOG_FUTEX_WAKE FUTEX_WAKE_PRIVATE
+#else
+#define BOOST_LOG_FUTEX_WAKE FUTEX_WAKE
+#endif
+
+#elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE)
+
+#include <errno.h>
+#include <semaphore.h>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/fences.hpp>
+
+#elif defined(BOOST_LOG_EVENT_USE_WINAPI)
+
+#include <windows.h>
+#include <boost/detail/interlocked.hpp>
+
+#else
+
+#include <boost/thread/locks.hpp>
+
+#endif
+
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#if defined(BOOST_LOG_EVENT_USE_FUTEX)
+
+//! Default constructor
+BOOST_LOG_API futex_based_event::futex_based_event() : m_state(0)
+{
+}
+
+//! Destructor
+BOOST_LOG_API futex_based_event::~futex_based_event()
+{
+}
+
+//! Waits for the object to become signalled
+BOOST_LOG_API void futex_based_event::wait()
+{
+ if (m_state.exchange(0, boost::memory_order_acq_rel) == 0)
+ {
+ while (true)
+ {
+ if (::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAIT, 0, NULL, NULL, 0) == 0)
+ {
+ // Another thread has set the event while sleeping
+ break;
+ }
+
+ const int err = errno;
+ if (err == EWOULDBLOCK)
+ {
+ // Another thread has set the event before sleeping
+ break;
+ }
+ else if (BOOST_UNLIKELY(err != EINTR))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the futex", (err));
+ }
+ }
+
+ m_state.store(0, boost::memory_order_relaxed);
+ }
+}
+
+//! Sets the object to a signalled state
+BOOST_LOG_API void futex_based_event::set_signalled()
+{
+ if (m_state.exchange(1, boost::memory_order_release) == 0)
+ {
+ if (BOOST_UNLIKELY(::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAKE, 1, NULL, NULL, 0) < 0))
+ {
+ const int err = errno;
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake threads blocked on the futex", (err));
+ }
+ }
+}
+
+#elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE)
+
+//! Default constructor
+BOOST_LOG_API sem_based_event::sem_based_event() : m_state()
+{
+ if (BOOST_UNLIKELY(sem_init(&m_semaphore, 0, 0) != 0))
+ {
+ const int err = errno;
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize semaphore", (err));
+ }
+}
+
+//! Destructor
+BOOST_LOG_API sem_based_event::~sem_based_event()
+{
+ BOOST_VERIFY(sem_destroy(&m_semaphore) == 0);
+}
+
+//! Waits for the object to become signalled
+BOOST_LOG_API void sem_based_event::wait()
+{
+ boost::atomic_thread_fence(boost::memory_order_acq_rel);
+ while (true)
+ {
+ if (sem_wait(&m_semaphore) != 0)
+ {
+ const int err = errno;
+ if (BOOST_UNLIKELY(err != EINTR))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the semaphore", (err));
+ }
+ }
+ else
+ break;
+ }
+ m_state.clear(boost::memory_order_relaxed);
+}
+
+//! Sets the object to a signalled state
+BOOST_LOG_API void sem_based_event::set_signalled()
+{
+ if (!m_state.test_and_set(boost::memory_order_release))
+ {
+ if (BOOST_UNLIKELY(sem_post(&m_semaphore) != 0))
+ {
+ const int err = errno;
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err));
+ }
+ }
+}
+
+#elif defined(BOOST_LOG_EVENT_USE_WINAPI)
+
+//! Default constructor
+BOOST_LOG_API winapi_based_event::winapi_based_event() :
+ m_state(0),
+ m_event(CreateEventA(NULL, false, false, NULL))
+{
+ if (BOOST_UNLIKELY(!m_event))
+ {
+ const DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err));
+ }
+}
+
+//! Destructor
+BOOST_LOG_API winapi_based_event::~winapi_based_event()
+{
+ BOOST_VERIFY(CloseHandle(m_event) != 0);
+}
+
+//! Waits for the object to become signalled
+BOOST_LOG_API void winapi_based_event::wait()
+{
+ // On Windows we assume that memory view is always actual (Intel x86 and x86_64 arch)
+ if (const_cast< volatile boost::uint32_t& >(m_state) == 0)
+ {
+ if (BOOST_UNLIKELY(WaitForSingleObject(m_event, INFINITE) != 0))
+ {
+ const DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err));
+ }
+ }
+ const_cast< volatile boost::uint32_t& >(m_state) = 0;
+}
+
+//! Sets the object to a signalled state
+BOOST_LOG_API void winapi_based_event::set_signalled()
+{
+ if (BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast< long* >(&m_state), 1, 0) == 0)
+ {
+ if (BOOST_UNLIKELY(SetEvent(m_event) == 0))
+ {
+ const DWORD err = GetLastError();
+ const_cast< volatile boost::uint32_t& >(m_state) = 0;
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err));
+ }
+ }
+}
+
+#else
+
+//! Default constructor
+BOOST_LOG_API generic_event::generic_event() : m_state(false)
+{
+}
+
+//! Destructor
+BOOST_LOG_API generic_event::~generic_event()
+{
+}
+
+//! Waits for the object to become signalled
+BOOST_LOG_API void generic_event::wait()
+{
+ boost::unique_lock< boost::mutex > lock(m_mutex);
+ while (!m_state)
+ {
+ m_cond.wait(lock);
+ }
+ m_state = false;
+}
+
+//! Sets the object to a signalled state
+BOOST_LOG_API void generic_event::set_signalled()
+{
+ boost::lock_guard< boost::mutex > lock(m_mutex);
+ if (!m_state)
+ {
+ m_state = true;
+ m_cond.notify_one();
+ }
+}
+
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_NO_THREADS
diff --git a/src/boost/libs/log/src/exceptions.cpp b/src/boost/libs/log/src/exceptions.cpp
new file mode 100644
index 000000000..779b4311b
--- /dev/null
+++ b/src/boost/libs/log/src/exceptions.cpp
@@ -0,0 +1,646 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file exceptions.cpp
+ * \author Andrey Semashev
+ * \date 31.10.2009
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/exception/exception.hpp>
+#include <boost/exception/errinfo_at_line.hpp>
+#include <boost/exception/info.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/support/exception.hpp>
+#include <boost/log/detail/header.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+// conversion from 'size_t' to 'boost::error_info<boost::throw_line_,int>::value_type', possible loss of data
+// No idea why line number is stored as a signed integer in the error info...
+#pragma warning(disable: 4267)
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Attaches attribute name exception information
+BOOST_LOG_API void attach_attribute_name_info(exception& e, attribute_name const& name)
+{
+ e << attribute_name_info(name);
+}
+
+} // namespace aux
+
+bad_alloc::bad_alloc(const char* descr) :
+ m_message(descr)
+{
+}
+
+bad_alloc::bad_alloc(std::string const& descr) :
+ m_message(descr)
+{
+}
+
+bad_alloc::~bad_alloc() throw()
+{
+}
+
+const char* bad_alloc::what() const throw()
+{
+ return m_message.c_str();
+}
+
+void bad_alloc::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(bad_alloc(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void bad_alloc::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(bad_alloc(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+capacity_limit_reached::capacity_limit_reached(const char* descr) :
+ bad_alloc(descr)
+{
+}
+
+capacity_limit_reached::capacity_limit_reached(std::string const& descr) :
+ bad_alloc(descr)
+{
+}
+
+capacity_limit_reached::~capacity_limit_reached() throw()
+{
+}
+
+void capacity_limit_reached::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(capacity_limit_reached(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void capacity_limit_reached::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(capacity_limit_reached(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+runtime_error::runtime_error(std::string const& descr) :
+ std::runtime_error(descr)
+{
+}
+
+runtime_error::~runtime_error() throw()
+{
+}
+
+missing_value::missing_value() :
+ runtime_error("Requested value not found")
+{
+}
+
+missing_value::missing_value(std::string const& descr) :
+ runtime_error(descr)
+{
+}
+
+missing_value::~missing_value() throw()
+{
+}
+
+void missing_value::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(missing_value())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void missing_value::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(missing_value(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void missing_value::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(missing_value(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void missing_value::throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name)
+{
+ boost::throw_exception(boost::enable_error_info(missing_value(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ );
+}
+
+void missing_value::throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name)
+{
+ boost::throw_exception(boost::enable_error_info(missing_value(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ );
+}
+
+invalid_type::invalid_type() :
+ runtime_error("Requested value has invalid type")
+{
+}
+
+invalid_type::invalid_type(std::string const& descr) :
+ runtime_error(descr)
+{
+}
+
+invalid_type::~invalid_type() throw()
+{
+}
+
+void invalid_type::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, const char* descr, typeindex::type_index const& type)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << type_info_info(type)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, std::string const& descr, typeindex::type_index const& type)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << type_info_info(type)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name, typeindex::type_index const& type)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ << type_info_info(type)
+ );
+}
+
+void invalid_type::throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name, typeindex::type_index const& type)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_type(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ << type_info_info(type)
+ );
+}
+
+invalid_value::invalid_value() :
+ runtime_error("The value is invalid")
+{
+}
+
+invalid_value::invalid_value(std::string const& descr) :
+ runtime_error(descr)
+{
+}
+
+invalid_value::~invalid_value() throw()
+{
+}
+
+void invalid_value::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_value())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void invalid_value::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_value(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void invalid_value::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(invalid_value(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+parse_error::parse_error() :
+ runtime_error("Failed to parse content")
+{
+}
+
+parse_error::parse_error(std::string const& descr) :
+ runtime_error(descr)
+{
+}
+
+parse_error::~parse_error() throw()
+{
+}
+
+void parse_error::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void parse_error::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void parse_error::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void parse_error::throw_(const char* file, std::size_t line, const char* descr, std::size_t content_line)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << boost::errinfo_at_line(content_line)
+ );
+}
+
+void parse_error::throw_(const char* file, std::size_t line, std::string const& descr, std::size_t content_line)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << boost::errinfo_at_line(content_line)
+ );
+}
+
+void parse_error::throw_(const char* file, std::size_t line, const char* descr, attribute_name const& name)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ );
+}
+
+void parse_error::throw_(const char* file, std::size_t line, std::string const& descr, attribute_name const& name)
+{
+ boost::throw_exception(boost::enable_error_info(parse_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ << attribute_name_info(name)
+ );
+}
+
+conversion_error::conversion_error() :
+ runtime_error("Failed to perform conversion")
+{
+}
+
+conversion_error::conversion_error(std::string const& descr) :
+ runtime_error(descr)
+{
+}
+
+conversion_error::~conversion_error() throw()
+{
+}
+
+void conversion_error::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(conversion_error())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void conversion_error::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(conversion_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void conversion_error::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(conversion_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+system_error::system_error(boost::system::error_code code, std::string const& descr) :
+ boost::system::system_error(code, descr)
+{
+}
+
+system_error::~system_error() throw()
+{
+}
+
+void system_error::throw_(const char* file, std::size_t line, const char* descr, int system_error_code)
+{
+ boost::throw_exception(boost::enable_error_info(system_error(boost::system::error_code(system_error_code, boost::system::system_category()), descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void system_error::throw_(const char* file, std::size_t line, std::string const& descr, int system_error_code)
+{
+ boost::throw_exception(boost::enable_error_info(system_error(boost::system::error_code(system_error_code, boost::system::system_category()), descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void system_error::throw_(const char* file, std::size_t line, const char* descr, boost::system::error_code code)
+{
+ boost::throw_exception(boost::enable_error_info(system_error(code, descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void system_error::throw_(const char* file, std::size_t line, std::string const& descr, boost::system::error_code code)
+{
+ boost::throw_exception(boost::enable_error_info(system_error(code, descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+logic_error::logic_error(std::string const& descr) :
+ std::logic_error(descr)
+{
+}
+
+logic_error::~logic_error() throw()
+{
+}
+
+void logic_error::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(logic_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void logic_error::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(logic_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+odr_violation::odr_violation() :
+ logic_error("ODR violation detected")
+{
+}
+
+odr_violation::odr_violation(std::string const& descr) :
+ logic_error(descr)
+{
+}
+
+odr_violation::~odr_violation() throw()
+{
+}
+
+void odr_violation::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(odr_violation())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void odr_violation::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(odr_violation(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void odr_violation::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(odr_violation(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+unexpected_call::unexpected_call() :
+ logic_error("Invalid call sequence")
+{
+}
+
+unexpected_call::unexpected_call(std::string const& descr) :
+ logic_error(descr)
+{
+}
+
+unexpected_call::~unexpected_call() throw()
+{
+}
+
+void unexpected_call::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(unexpected_call())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void unexpected_call::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(unexpected_call(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void unexpected_call::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(unexpected_call(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+setup_error::setup_error() :
+ logic_error("The library is not initialized properly")
+{
+}
+
+setup_error::setup_error(std::string const& descr) :
+ logic_error(descr)
+{
+}
+
+setup_error::~setup_error() throw()
+{
+}
+
+void setup_error::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(setup_error())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void setup_error::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(setup_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void setup_error::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(setup_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+limitation_error::limitation_error() :
+ logic_error("Boost.Log library limit reached")
+{
+}
+
+limitation_error::limitation_error(std::string const& descr) :
+ logic_error(descr)
+{
+}
+
+limitation_error::~limitation_error() throw()
+{
+}
+
+void limitation_error::throw_(const char* file, std::size_t line)
+{
+ boost::throw_exception(boost::enable_error_info(limitation_error())
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void limitation_error::throw_(const char* file, std::size_t line, const char* descr)
+{
+ boost::throw_exception(boost::enable_error_info(limitation_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+void limitation_error::throw_(const char* file, std::size_t line, std::string const& descr)
+{
+ boost::throw_exception(boost::enable_error_info(limitation_error(descr))
+ << boost::throw_file(file)
+ << boost::throw_line(line)
+ );
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/format_parser.cpp b/src/boost/libs/log/src/format_parser.cpp
new file mode 100644
index 000000000..1215d6b2c
--- /dev/null
+++ b/src/boost/libs/log/src/format_parser.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file format_parser.cpp
+ * \author Andrey Semashev
+ * \date 16.11.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <string>
+#include <algorithm>
+#include <boost/throw_exception.hpp>
+#include <boost/exception/exception.hpp>
+#include <boost/move/core.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/spirit/include/qi_uint.hpp>
+#include <boost/spirit/include/qi_parse.hpp>
+#include <boost/log/detail/format.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/support/exception.hpp>
+#include "spirit_encoding.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace qi = boost::spirit::qi;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+template< typename CharT >
+BOOST_LOG_API format_description< CharT > parse_format(const CharT* begin, const CharT* end)
+{
+ typedef CharT char_type;
+ typedef format_description< char_type > description;
+ typedef typename encoding< char_type >::type traits;
+
+ const char_type* original_begin = begin;
+ description descr;
+ unsigned int literal_start_pos = 0;
+
+ while (begin != end)
+ {
+ const char_type* p = std::find(begin, end, static_cast< char_type >('%'));
+ descr.literal_chars.append(begin, p);
+
+ if ((end - p) >= 2)
+ {
+ // Check for a percent placeholder
+ char_type c = p[1];
+ if (c == static_cast< char_type >('%'))
+ {
+ descr.literal_chars.push_back(static_cast< char_type >('%'));
+ begin = p + 2;
+ continue;
+ }
+
+ // From here on, no more literals are possible. Append the literal element.
+ {
+ const unsigned int literal_chars_size = static_cast< unsigned int >(descr.literal_chars.size());
+ if (literal_start_pos < literal_chars_size)
+ {
+ descr.format_elements.push_back(format_element::literal(literal_start_pos, literal_chars_size - literal_start_pos));
+ literal_start_pos = literal_chars_size;
+ }
+ }
+
+ // Check if this is a positional argument
+ if (traits::isdigit(c))
+ {
+ if (c != static_cast< char_type >('0'))
+ {
+ // Positional argument in the form "%N%"
+ unsigned int n = 0;
+ const char_type* pp = p + 1;
+ qi::parse(pp, end, qi::uint_, n);
+ if (n == 0 || pp == end || *pp != static_cast< char_type >('%'))
+ {
+ boost::throw_exception(boost::enable_error_info(parse_error("Invalid positional format placeholder")) << boost::throw_file(__FILE__) << boost::throw_line(__LINE__)
+ << boost::log::position_info(static_cast< unsigned int >(p - original_begin))
+ );
+ }
+
+ // Safety check against ridiculously large argument numbers which would lead to excessive memory consumption.
+ // This could be useful if the format string is gathered from an external source (e.g. a config file).
+ if (n > 1000)
+ {
+ boost::throw_exception(boost::enable_error_info(limitation_error("Positional format placeholder too big")) << boost::throw_file(__FILE__) << boost::throw_line(__LINE__)
+ << boost::log::position_info(static_cast< unsigned int >(p - original_begin))
+ );
+ }
+
+ // We count positional arguments from 0, not from 1 as in format strings
+ descr.format_elements.push_back(format_element::positional_argument(n - 1));
+ begin = pp + 1; // skip the closing '%'
+
+ continue;
+ }
+ else
+ {
+ // This must be the filler character, not supported yet
+ }
+ }
+
+ // This must be something else, not supported yet
+ boost::throw_exception(boost::enable_error_info(parse_error("Unsupported format placeholder")) << boost::throw_file(__FILE__) << boost::throw_line(__LINE__)
+ << boost::log::position_info(static_cast< unsigned int >(p - original_begin))
+ );
+ }
+ else
+ {
+ if (p != end)
+ descr.literal_chars.push_back(static_cast< char_type >('%')); // a single '%' character at the end of the string
+ begin = end;
+ }
+ }
+
+ const unsigned int literal_chars_size = static_cast< unsigned int >(descr.literal_chars.size());
+ if (literal_start_pos < literal_chars_size)
+ descr.format_elements.push_back(format_element::literal(literal_start_pos, literal_chars_size - literal_start_pos));
+
+ return BOOST_LOG_NRVO_RESULT(descr);
+}
+
+
+#ifdef BOOST_LOG_USE_CHAR
+
+template BOOST_LOG_API
+format_description< char > parse_format(const char* begin, const char* end);
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+template BOOST_LOG_API
+format_description< wchar_t > parse_format(const wchar_t* begin, const wchar_t* end);
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/global_logger_storage.cpp b/src/boost/libs/log/src/global_logger_storage.cpp
new file mode 100644
index 000000000..6ddcc1b7c
--- /dev/null
+++ b/src/boost/libs/log/src/global_logger_storage.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file global_logger_storage.cpp
+ * \author Andrey Semashev
+ * \date 21.04.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <map>
+#include <string>
+#include <boost/limits.hpp>
+#include <boost/type_index.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/detail/snprintf.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/sources/global_logger_storage.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/mutex.hpp>
+#include <boost/log/detail/locks.hpp>
+#endif
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sources {
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! The loggers repository singleton
+struct loggers_repository :
+ public log::aux::lazy_singleton< loggers_repository >
+{
+ //! Repository map type
+ typedef std::map< typeindex::type_index, shared_ptr< logger_holder_base > > loggers_map_t;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization primitive
+ mutable mutex m_Mutex;
+#endif
+ //! Map of logger holders
+ loggers_map_t m_Loggers;
+};
+
+} // namespace
+
+//! Finds or creates the logger and returns its holder
+BOOST_LOG_API shared_ptr< logger_holder_base > global_storage::get_or_init(typeindex::type_index key, initializer_t initializer)
+{
+ typedef loggers_repository::loggers_map_t loggers_map_t;
+ loggers_repository& repo = loggers_repository::get();
+
+ BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex > lock(repo.m_Mutex);)
+ loggers_map_t::iterator it = repo.m_Loggers.find(key);
+ if (it != repo.m_Loggers.end())
+ {
+ // There is an instance
+ return it->second;
+ }
+ else
+ {
+ // We have to create a logger instance
+ shared_ptr< logger_holder_base > inst = initializer();
+ repo.m_Loggers[key] = inst;
+ return inst;
+ }
+}
+
+//! Throws the \c odr_violation exception
+BOOST_LOG_API BOOST_LOG_NORETURN void throw_odr_violation(
+ typeindex::type_index tag_type,
+ typeindex::type_index logger_type,
+ logger_holder_base const& registered)
+{
+ char buf[std::numeric_limits< unsigned int >::digits10 + 3];
+ if (log::aux::snprintf(buf, sizeof(buf), "%u", registered.m_RegistrationLine) < 0)
+ buf[0] = '\0';
+ std::string str =
+ std::string("Could not initialize global logger with tag \"") +
+ tag_type.pretty_name() +
+ "\" and type \"" +
+ logger_type.pretty_name() +
+ "\". A logger of type \"" +
+ registered.m_LoggerType.pretty_name() +
+ "\" with the same tag has already been registered at " +
+ registered.m_RegistrationFile + ":" + buf + ".";
+
+ BOOST_LOG_THROW_DESCR(odr_violation, str);
+}
+
+} // namespace aux
+
+} // namespace sources
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/id_formatting.hpp b/src/boost/libs/log/src/id_formatting.hpp
new file mode 100644
index 000000000..b42c5128f
--- /dev/null
+++ b/src/boost/libs/log/src/id_formatting.hpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file id_formatting.hpp
+ * \author Andrey Semashev
+ * \date 25.01.2015
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_ID_FORMATTING_HPP_INCLUDED_
+#define BOOST_LOG_ID_FORMATTING_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+// Defined in dump.cpp
+extern const char g_hex_char_table[2][16];
+
+template< std::size_t IdSize, typename CharT, typename IdT >
+inline void format_id(CharT* buf, std::size_t size, IdT id, bool uppercase) BOOST_NOEXCEPT
+{
+ const char* const char_table = g_hex_char_table[uppercase];
+
+ // Input buffer is assumed to be always larger than 2 chars
+ *buf++ = static_cast< CharT >(char_table[0]); // '0'
+ *buf++ = static_cast< CharT >(char_table[10] + ('x' - 'a')); // 'x'
+
+ size -= 3; // reserve space for the terminating 0
+ std::size_t i = 0;
+ const std::size_t n = (size > (IdSize * 2u)) ? IdSize * 2u : size;
+ for (std::size_t shift = n * 4u - 4u; i < n; ++i, shift -= 4u)
+ {
+ buf[i] = static_cast< CharT >(char_table[(id >> shift) & 15u]);
+ }
+
+ buf[i] = static_cast< CharT >('\0');
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_ID_FORMATTING_HPP_INCLUDED_
+
diff --git a/src/boost/libs/log/src/murmur3.hpp b/src/boost/libs/log/src/murmur3.hpp
new file mode 100644
index 000000000..2968c084c
--- /dev/null
+++ b/src/boost/libs/log/src/murmur3.hpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file murmur3.hpp
+ * \author Andrey Semashev
+ * \date 16.01.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ *
+ * This file implements MurmurHash3 hash function implementation. See https://en.wikipedia.org/wiki/MurmurHash.
+ */
+
+#ifndef BOOST_LOG_MURMUR3_HPP_INCLUDED_
+#define BOOST_LOG_MURMUR3_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! 32-bit MurmurHash3 algorithm implementation (https://en.wikipedia.org/wiki/MurmurHash)
+class murmur3_32
+{
+private:
+ uint32_t m_state;
+ uint32_t m_len;
+
+ static BOOST_CONSTEXPR_OR_CONST uint32_t c1 = 0xcc9e2d51;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t c2 = 0x1b873593;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t r1 = 15;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t r2 = 13;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t m = 5;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t n = 0xe6546b64;
+
+public:
+ explicit BOOST_CONSTEXPR murmur3_32(uint32_t seed) BOOST_NOEXCEPT : m_state(seed), m_len(0u)
+ {
+ }
+
+ //! Mixing stage of the 32-bit MurmurHash3 algorithm
+ void mix(uint32_t value) BOOST_NOEXCEPT
+ {
+ value *= c1;
+ value = (value << r1) | (value >> (32u - r1));
+ value *= c2;
+
+ uint32_t h = m_state ^ value;
+ m_state = ((h << r2) | (h >> (32u - r2))) * m + n;
+ m_len += 4u;
+ }
+
+ //! Finalization stage of the 32-bit MurmurHash3 algorithm
+ uint32_t finalize() BOOST_NOEXCEPT
+ {
+ uint32_t h = m_state ^ m_len;
+ h ^= h >> 16u;
+ h *= 0x85ebca6bu;
+ h ^= h >> 13u;
+ h *= 0xc2b2ae35u;
+ h ^= h >> 16u;
+ m_state = h;
+ return h;
+ }
+};
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_MURMUR3_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/named_scope.cpp b/src/boost/libs/log/src/named_scope.cpp
new file mode 100644
index 000000000..fff80a1d4
--- /dev/null
+++ b/src/boost/libs/log/src/named_scope.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file named_scope.cpp
+ * \author Andrey Semashev
+ * \date 24.06.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <utility>
+#include <algorithm>
+#include <boost/type_index.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/log/attributes/attribute.hpp>
+#include <boost/log/attributes/attribute_value.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+#include <boost/log/utility/type_dispatch/type_dispatcher.hpp>
+#include <boost/log/detail/allocator_traits.hpp>
+#include <boost/log/detail/singleton.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/tss.hpp>
+#endif
+#include "unique_ptr.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace attributes {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ //! Actual implementation of the named scope list
+ class writeable_named_scope_list :
+ public named_scope_list
+ {
+ //! Base type
+ typedef named_scope_list base_type;
+
+ public:
+ //! Const reference type
+ typedef base_type::const_reference const_reference;
+
+ public:
+ //! The method pushes the scope to the back of the list
+ BOOST_FORCEINLINE void push_back(const_reference entry) BOOST_NOEXCEPT
+ {
+ aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
+ entry._m_pPrev = top;
+ entry._m_pNext = &this->m_RootNode;
+
+ BOOST_LOG_ASSUME(&entry != 0);
+ this->m_RootNode._m_pPrev = top->_m_pNext =
+ const_cast< aux::named_scope_list_node* >(
+ static_cast< const aux::named_scope_list_node* >(&entry));
+
+ ++this->m_Size;
+ }
+ //! The method removes the top scope entry from the list
+ BOOST_FORCEINLINE void pop_back() BOOST_NOEXCEPT
+ {
+ aux::named_scope_list_node* top = this->m_RootNode._m_pPrev;
+ top->_m_pPrev->_m_pNext = top->_m_pNext;
+ top->_m_pNext->_m_pPrev = top->_m_pPrev;
+ --this->m_Size;
+ }
+ };
+
+ //! Named scope attribute value
+ class named_scope_value :
+ public attribute_value::impl
+ {
+ //! Scope names stack
+ typedef named_scope_list scope_stack;
+
+ //! Pointer to the actual scope value
+ scope_stack* m_pValue;
+ //! A thread-independent value
+ optional< scope_stack > m_DetachedValue;
+
+ public:
+ //! Constructor
+ explicit named_scope_value(scope_stack* p) : m_pValue(p) {}
+
+ //! The method dispatches the value to the given object. It returns true if the
+ //! object was capable to consume the real attribute value type and false otherwise.
+ bool dispatch(type_dispatcher& dispatcher)
+ {
+ type_dispatcher::callback< scope_stack > callback =
+ dispatcher.get_callback< scope_stack >();
+ if (callback)
+ {
+ callback(*m_pValue);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /*!
+ * \return The attribute value type
+ */
+ typeindex::type_index get_type() const { return typeindex::type_id< scope_stack >(); }
+
+ //! The method is called when the attribute value is passed to another thread (e.g.
+ //! in case of asynchronous logging). The value should ensure it properly owns all thread-specific data.
+ intrusive_ptr< attribute_value::impl > detach_from_thread()
+ {
+ if (!m_DetachedValue)
+ {
+ m_DetachedValue = *m_pValue;
+ m_pValue = m_DetachedValue.get_ptr();
+ }
+
+ return this;
+ }
+ };
+
+} // namespace
+
+//! Named scope attribute implementation
+struct BOOST_SYMBOL_VISIBLE named_scope::impl :
+ public attribute::impl,
+ public log::aux::singleton<
+ impl,
+ intrusive_ptr< impl >
+ >
+{
+ //! Singleton base type
+ typedef log::aux::singleton<
+ impl,
+ intrusive_ptr< impl >
+ > singleton_base_type;
+
+ //! Writable scope list type
+ typedef writeable_named_scope_list scope_list;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Pointer to the thread-specific scope stack
+ thread_specific_ptr< scope_list > pScopes;
+
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ //! Cached pointer to the thread-specific scope stack
+ static BOOST_LOG_TLS scope_list* pScopesCache;
+#endif
+
+#else
+ //! Pointer to the scope stack
+ log::aux::unique_ptr< scope_list > pScopes;
+#endif
+
+ //! The method returns current thread scope stack
+ scope_list& get_scope_list()
+ {
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ scope_list* p = pScopesCache;
+#else
+ scope_list* p = pScopes.get();
+#endif
+ if (!p)
+ {
+ log::aux::unique_ptr< scope_list > pNew(new scope_list());
+ pScopes.reset(pNew.get());
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+ pScopesCache = p = pNew.release();
+#else
+ p = pNew.release();
+#endif
+ }
+
+ return *p;
+ }
+
+ //! Instance initializer
+ static void init_instance()
+ {
+ singleton_base_type::get_instance().reset(new impl());
+ }
+
+ //! The method returns the actual attribute value. It must not return NULL.
+ attribute_value get_value()
+ {
+ return attribute_value(new named_scope_value(&get_scope_list()));
+ }
+
+private:
+ impl() {}
+};
+
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+//! Cached pointer to the thread-specific scope stack
+BOOST_LOG_TLS named_scope::impl::scope_list*
+named_scope::impl::pScopesCache = NULL;
+#endif // defined(BOOST_LOG_USE_COMPILER_TLS)
+
+
+//! Copy constructor
+BOOST_LOG_API named_scope_list::named_scope_list(named_scope_list const& that) :
+ allocator_type(static_cast< allocator_type const& >(that)),
+ m_Size(that.size()),
+ m_fNeedToDeallocate(!that.empty())
+{
+ if (m_Size > 0)
+ {
+ // Copy the container contents
+ pointer p = log::aux::allocator_traits< allocator_type >::allocate(*static_cast< allocator_type* >(this), that.size());
+ aux::named_scope_list_node* prev = &m_RootNode;
+ for (const_iterator src = that.begin(), end = that.end(); src != end; ++src, ++p)
+ {
+ log::aux::allocator_traits< allocator_type >::construct(*static_cast< allocator_type* >(this), p, *src); // won't throw
+ p->_m_pPrev = prev;
+ prev->_m_pNext = p;
+ prev = p;
+ }
+ m_RootNode._m_pPrev = prev;
+ prev->_m_pNext = &m_RootNode;
+ }
+}
+
+//! Destructor
+BOOST_LOG_API named_scope_list::~named_scope_list()
+{
+ if (m_fNeedToDeallocate)
+ {
+ iterator it(m_RootNode._m_pNext);
+ iterator end(&m_RootNode);
+ while (it != end)
+ log::aux::allocator_traits< allocator_type >::destroy(*static_cast< allocator_type* >(this), &*(it++));
+ log::aux::allocator_traits< allocator_type >::deallocate(*static_cast< allocator_type* >(this), static_cast< pointer >(m_RootNode._m_pNext), m_Size);
+ }
+}
+
+//! Swaps two instances of the container
+BOOST_LOG_API void named_scope_list::swap(named_scope_list& that)
+{
+ if (!this->empty())
+ {
+ if (!that.empty())
+ {
+ // both containers are not empty
+ std::swap(m_RootNode._m_pNext->_m_pPrev, that.m_RootNode._m_pNext->_m_pPrev);
+ std::swap(m_RootNode._m_pPrev->_m_pNext, that.m_RootNode._m_pPrev->_m_pNext);
+ std::swap(m_RootNode, that.m_RootNode);
+ std::swap(m_Size, that.m_Size);
+ std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
+ }
+ else
+ {
+ // this is not empty
+ m_RootNode._m_pNext->_m_pPrev = m_RootNode._m_pPrev->_m_pNext = &that.m_RootNode;
+ that.m_RootNode = m_RootNode;
+ m_RootNode._m_pNext = m_RootNode._m_pPrev = &m_RootNode;
+ std::swap(m_Size, that.m_Size);
+ std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
+ }
+ }
+ else if (!that.empty())
+ {
+ // that is not empty
+ that.m_RootNode._m_pNext->_m_pPrev = that.m_RootNode._m_pPrev->_m_pNext = &m_RootNode;
+ m_RootNode = that.m_RootNode;
+ that.m_RootNode._m_pNext = that.m_RootNode._m_pPrev = &that.m_RootNode;
+ std::swap(m_Size, that.m_Size);
+ std::swap(m_fNeedToDeallocate, that.m_fNeedToDeallocate);
+ }
+}
+
+//! Constructor
+named_scope::named_scope() :
+ attribute(impl::instance)
+{
+}
+
+//! Constructor for casting support
+named_scope::named_scope(cast_source const& source) :
+ attribute(source.as< impl >())
+{
+}
+
+//! The method pushes the scope to the stack
+void named_scope::push_scope(scope_entry const& entry) BOOST_NOEXCEPT
+{
+ impl::scope_list& s = impl::instance->get_scope_list();
+ s.push_back(entry);
+}
+
+//! The method pops the top scope
+void named_scope::pop_scope() BOOST_NOEXCEPT
+{
+ impl::scope_list& s = impl::instance->get_scope_list();
+ s.pop_back();
+}
+
+//! Returns the current thread's scope stack
+named_scope::value_type const& named_scope::get_scopes()
+{
+ return impl::instance->get_scope_list();
+}
+
+} // namespace attributes
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/named_scope_format_parser.cpp b/src/boost/libs/log/src/named_scope_format_parser.cpp
new file mode 100644
index 000000000..b39325947
--- /dev/null
+++ b/src/boost/libs/log/src/named_scope_format_parser.cpp
@@ -0,0 +1,749 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file named_scope_format_parser.cpp
+ * \author Andrey Semashev
+ * \date 14.11.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <limits>
+#include <algorithm>
+#include <boost/cstdint.hpp>
+#include <boost/move/core.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/spirit/include/karma_uint.hpp>
+#include <boost/spirit/include/karma_generate.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+#include <boost/log/expressions/formatters/named_scope.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace karma = boost::spirit::karma;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace expressions {
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! The function skips any spaces from the current position
+BOOST_FORCEINLINE const char* skip_spaces(const char* p, const char* end)
+{
+ while (p < end && *p == ' ')
+ ++p;
+ return p;
+}
+
+//! The function checks if the given character can be part of a function/type/namespace name
+BOOST_FORCEINLINE bool is_name_character(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z');
+}
+
+//! The function checks if there is 'operator' keyword at the specified position
+BOOST_FORCEINLINE bool is_operator_keyword(const char* p)
+{
+ return std::memcmp(p, "operator", 8) == 0;
+}
+
+//! The function tries to parse operator signature
+bool detect_operator(const char* begin, const char* end, const char* operator_keyword, const char*& operator_end)
+{
+ if (end - operator_keyword < 9 || !is_operator_keyword(operator_keyword))
+ return false;
+ // Check that it's not a function name ending with 'operator', like detect_operator
+ if (operator_keyword > begin && is_name_character(*(operator_keyword - 1)))
+ return false;
+
+ const char* p = skip_spaces(operator_keyword + 8, end);
+ if (p == end)
+ return false;
+
+ // Check to see where the operator token ends
+ switch (*p)
+ {
+ case '(':
+ // Handle operator()
+ p = skip_spaces(++p, end);
+ if (p < end && *p == ')')
+ {
+ operator_end = p + 1;
+ return true;
+ }
+
+ return false;
+
+ case '[':
+ // Handle operator[]
+ p = skip_spaces(++p, end);
+ if (p < end && *p == ']')
+ {
+ operator_end = p + 1;
+ return true;
+ }
+
+ return false;
+
+ case '>':
+ case '<':
+ // Handle operator<=, operator>=, operator<<, operator>>, operator<<=, operator>>=
+ if (end - p >= 3 && (p[0] == p[1] && p[2] == '='))
+ operator_end = p + 3;
+ else if (end - p >= 2 && (p[0] == p[1] || p[1] == '='))
+ operator_end = p + 2;
+ else
+ operator_end = p + 1;
+
+ return true;
+
+ case '-':
+ // Handle operator->, operator->*
+ if (end - p >= 2 && p[1] == '>')
+ {
+ if (end - p >= 3 && p[2] == '*')
+ operator_end = p + 3;
+ else
+ operator_end = p + 2;
+
+ return true;
+ }
+ // Fall through to other cases involving '-'
+ BOOST_FALLTHROUGH;
+
+ case '=':
+ case '|':
+ case '&':
+ case '+':
+ // Handle operator=, operator==, operator+=, operator++, operator||, operator&&, etc.
+ if (end - p >= 2 && (p[0] == p[1] || p[1] == '='))
+ operator_end = p + 2;
+ else
+ operator_end = p + 1;
+
+ return true;
+
+ case '*':
+ case '/':
+ case '%':
+ case '^':
+ // Handle operator*, operator*=, etc.
+ if (end - p >= 2 && p[1] == '=')
+ operator_end = p + 2;
+ else
+ operator_end = p + 1;
+
+ return true;
+
+ case ',':
+ case '~':
+ case '!':
+ // Handle operator,, operator~, etc.
+ operator_end = p + 1;
+ return true;
+
+ case '"':
+ // Handle operator""
+ if (end - p >= 2 && p[0] == p[1])
+ {
+ p = skip_spaces(p + 2, end);
+ // Skip through the literal suffix
+ while (p < end && is_name_character(*p))
+ ++p;
+ operator_end = p;
+ return true;
+ }
+
+ return false;
+
+ default:
+ // Handle type conversion operators. We can't find the end of the type reliably here.
+ operator_end = p;
+ return true;
+ }
+}
+
+//! The function skips all template parameters
+inline const char* skip_template_parameters(const char* begin, const char* end)
+{
+ unsigned int depth = 1;
+ const char* p = begin;
+ while (depth > 0 && p != end)
+ {
+ switch (*p)
+ {
+ case '>':
+ --depth;
+ break;
+
+ case '<':
+ ++depth;
+ break;
+
+ case 'o':
+ {
+ // Skip operators (e.g. when an operator is a non-type template parameter)
+ const char* operator_end;
+ if (detect_operator(begin, end, p, operator_end))
+ {
+ p = operator_end;
+ continue;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ++p;
+ }
+
+ return p;
+}
+
+//! The function seeks for the opening parenthesis and also tries to find the function name beginning
+inline const char* find_opening_parenthesis(const char* begin, const char* end, const char*& first_name_begin, const char*& last_name_begin)
+{
+ enum sequence_state
+ {
+ not_started, // no significant (non-space) characters have been encountered so far
+ started, // some name has started; the name is a contiguous sequence of characters that may constitute a function or scope name
+ continued, // the previous characters were the scope operator ("::"), so the name is not finished yet
+ ended, // the name has ended; in particular, this means that there were significant characters previously in the string
+ operator_detected // operator has been found in the string, don't parse for scopes anymore; this is needed for conversion operators
+ };
+ sequence_state state = not_started;
+
+ const char* p = begin;
+ while (p != end)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case '(':
+ if (state == not_started)
+ {
+ // If the opening brace is the first meaningful character in the string then this can't be a function signature.
+ // Pretend we didn't find the paranthesis to fail the parsing process.
+ return end;
+ }
+ return p;
+
+ case '<':
+ if (state == not_started)
+ {
+ // Template parameters cannot start as the first meaningful character in the signature.
+ // Pretend we didn't find the paranthesis to fail the parsing process.
+ return end;
+ }
+ p = skip_template_parameters(p + 1, end);
+ if (state != operator_detected)
+ state = ended;
+ continue;
+
+ case ' ':
+ if (state == started)
+ state = ended;
+ break;
+
+ case ':':
+ ++p;
+ if (p != end && *p == ':')
+ {
+ if (state == not_started)
+ {
+ // Include the starting "::" in the full name
+ first_name_begin = p - 1;
+ }
+ if (state != operator_detected)
+ state = continued;
+ ++p;
+ }
+ else if (state != operator_detected)
+ {
+ // Weird case, a single colon. Maybe, some compilers would put things like "public:" in front of the signature.
+ state = ended;
+ }
+ continue;
+
+ case 'o':
+ {
+ const char* operator_end;
+ if (detect_operator(begin, end, p, operator_end))
+ {
+ if (state == not_started || state == ended)
+ first_name_begin = p;
+ last_name_begin = p;
+ p = operator_end;
+ state = operator_detected;
+ continue;
+ }
+ }
+ // Fall through to process this character as other characters
+ BOOST_FALLTHROUGH;
+
+ default:
+ if (state != operator_detected)
+ {
+ if (is_name_character(c) || c == '~') // check for '~' in case of a destructor
+ {
+ if (state != started)
+ {
+ if (state == not_started || state == ended)
+ first_name_begin = p;
+ last_name_begin = p;
+ state = started;
+ }
+ }
+ else
+ {
+ state = ended;
+ }
+ }
+ break;
+ }
+
+ ++p;
+ }
+
+ return p;
+}
+
+//! The function seeks for the closing parenthesis
+inline const char* find_closing_parenthesis(const char* begin, const char* end, char& first_char)
+{
+ bool found_first_meaningful_char = false;
+ unsigned int depth = 1;
+ const char* p = begin;
+ while (p != end)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case ')':
+ --depth;
+ if (depth == 0)
+ return p;
+ break;
+
+ case '(':
+ ++depth;
+ break;
+
+ case '<':
+ p = skip_template_parameters(p + 1, end);
+ continue;
+
+ case 'o':
+ {
+ const char* operator_end;
+ if (detect_operator(begin, end, p, operator_end))
+ {
+ p = operator_end;
+ continue;
+ }
+ }
+ // Fall through to process this character as other characters
+ BOOST_FALLTHROUGH;
+
+ default:
+ if (!found_first_meaningful_char && c != ' ')
+ {
+ found_first_meaningful_char = true;
+ first_char = c;
+ }
+ break;
+ }
+
+ ++p;
+ }
+
+ return p;
+}
+
+bool parse_function_name(const char*& begin, const char*& end, bool include_scope)
+{
+ // The algorithm tries to match several patterns to recognize function signatures. The most obvious is:
+ //
+ // A B(C)
+ //
+ // or just:
+ //
+ // B(C)
+ //
+ // in case of constructors, destructors and type conversion operators. The algorithm looks for the opening parenthesis and while doing that
+ // it detects the beginning of B. As a result B is the function name.
+ //
+ // The first significant complication is function and array return types, in which case the syntax becomes nested:
+ //
+ // A (*B(C))(D)
+ // A (&B(C))[D]
+ //
+ // In addition to that MSVC adds calling convention, such as __cdecl, to function types. In order to detect these cases the algorithm
+ // seeks for the closing parenthesis after the opening one. If there is an opening parenthesis or square bracket after the closing parenthesis
+ // then this is a function or array return type. The case of arrays is additionally complicated by GCC output:
+ //
+ // A B(C) [D]
+ //
+ // where D is template parameters description and is not part of the signature. To discern this special case from the array return type, the algorithm
+ // checks for the first significant character within the parenthesis. This character is '&' in case of arrays and something else otherwise.
+ //
+ // Speaking of template parameters, the parsing algorithm ignores them completely, assuming they are part of the name being parsed. This includes
+ // any possible parenthesis, nested template parameters and even operators, which may be present there as non-type template parameters.
+ //
+ // Operators pose another problem. This is especially the case for type conversion operators, and even more so for conversion operators to
+ // function types. In this latter case at least MSVC is known to produce incomprehensible strings which we cannot parse. In other cases it is
+ // too difficult to parse the type correctly. So we cheat a little. Whenever we find "operator", we know that we've found the function name
+ // already, and the name ends at the opening parenthesis. For other operators we are able to parse them correctly but that doesn't really matter.
+ //
+ // Note that the algorithm should be tolerant to different flavors of the input strings from different compilers, so we can't rely on spaces
+ // delimiting function names and other elements. Also, the algorithm should behave well in case of the fallback string generated by
+ // BOOST_CURRENT_FUNCTION (which is "(unknown)" currently). In case of any parsing failure the algorithm should return false, in which case the
+ // full original string will be used as the output.
+
+ const char* b = begin;
+ const char* e = end;
+ while (b != e)
+ {
+ // Find the opening parenthesis. While looking for it, also find the function name.
+ // first_name_begin is the beginning of the function scope, last_name_begin is the actual function name.
+ const char* first_name_begin = NULL, *last_name_begin = NULL;
+ const char* paren_open = find_opening_parenthesis(b, e, first_name_begin, last_name_begin);
+ if (paren_open == e)
+ return false;
+ // Find the closing parenthesis. Also peek at the first character in the parenthesis, which we'll use to detect array return types.
+ char first_char_in_parenthesis = 0;
+ const char* paren_close = find_closing_parenthesis(paren_open + 1, e, first_char_in_parenthesis);
+ if (paren_close == e)
+ return false;
+
+ const char* p = skip_spaces(paren_close + 1, e);
+
+ // Detect function and array return types
+ if (p < e && (*p == '(' || (*p == '[' && first_char_in_parenthesis == '&')))
+ {
+ // This is a function or array return type, the actual function name is within the parenthesis.
+ // Re-parse the string within the parenthesis as a function signature.
+ b = paren_open + 1;
+ e = paren_close;
+ continue;
+ }
+
+ // We found something that looks like a function signature
+ if (include_scope)
+ {
+ if (!first_name_begin)
+ return false;
+
+ begin = first_name_begin;
+ }
+ else
+ {
+ if (!last_name_begin)
+ return false;
+
+ begin = last_name_begin;
+ }
+
+ end = paren_open;
+
+ return true;
+ }
+
+ return false;
+}
+
+template< typename CharT >
+class named_scope_formatter
+{
+ BOOST_COPYABLE_AND_MOVABLE_ALT(named_scope_formatter)
+
+public:
+ typedef void result_type;
+
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef basic_formatting_ostream< char_type > stream_type;
+ typedef attributes::named_scope::value_type::value_type value_type;
+
+ struct literal
+ {
+ typedef void result_type;
+
+ explicit literal(string_type& lit) { m_literal.swap(lit); }
+
+ result_type operator() (stream_type& strm, value_type const&) const
+ {
+ strm << m_literal;
+ }
+
+ private:
+ string_type m_literal;
+ };
+
+ struct scope_name
+ {
+ typedef void result_type;
+
+ result_type operator() (stream_type& strm, value_type const& value) const
+ {
+ strm << value.scope_name;
+ }
+ };
+
+ struct function_name
+ {
+ typedef void result_type;
+
+ explicit function_name(bool include_scope) : m_include_scope(include_scope)
+ {
+ }
+
+ result_type operator() (stream_type& strm, value_type const& value) const
+ {
+ if (value.type == attributes::named_scope_entry::function)
+ {
+ const char* begin = value.scope_name.c_str();
+ const char* end = begin + value.scope_name.size();
+ if (parse_function_name(begin, end, m_include_scope))
+ {
+ strm.write(begin, end - begin);
+ return;
+ }
+ }
+
+ strm << value.scope_name;
+ }
+
+ private:
+ const bool m_include_scope;
+ };
+
+ struct full_file_name
+ {
+ typedef void result_type;
+
+ result_type operator() (stream_type& strm, value_type const& value) const
+ {
+ strm << value.file_name;
+ }
+ };
+
+ struct file_name
+ {
+ typedef void result_type;
+
+ result_type operator() (stream_type& strm, value_type const& value) const
+ {
+ std::size_t n = value.file_name.size(), i = n;
+ for (; i > 0; --i)
+ {
+ const char c = value.file_name[i - 1];
+#if defined(BOOST_WINDOWS)
+ if (c == '\\')
+ break;
+#endif
+ if (c == '/')
+ break;
+ }
+ strm.write(value.file_name.c_str() + i, n - i);
+ }
+ };
+
+ struct line_number
+ {
+ typedef void result_type;
+
+ result_type operator() (stream_type& strm, value_type const& value) const
+ {
+ strm.flush();
+
+ char_type buf[std::numeric_limits< unsigned int >::digits10 + 2];
+ char_type* p = buf;
+
+ typedef karma::uint_generator< unsigned int, 10 > uint_gen;
+ karma::generate(p, uint_gen(), value.line);
+
+ typedef typename stream_type::streambuf_type streambuf_type;
+ static_cast< streambuf_type* >(strm.rdbuf())->append(buf, static_cast< std::size_t >(p - buf));
+ }
+ };
+
+private:
+ typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_type;
+ typedef std::vector< formatter_type > formatters;
+
+private:
+ formatters m_formatters;
+
+public:
+ BOOST_DEFAULTED_FUNCTION(named_scope_formatter(), {})
+ named_scope_formatter(named_scope_formatter const& that) : m_formatters(that.m_formatters) {}
+ named_scope_formatter(BOOST_RV_REF(named_scope_formatter) that) { m_formatters.swap(that.m_formatters); }
+
+ named_scope_formatter& operator= (named_scope_formatter that)
+ {
+ this->swap(that);
+ return *this;
+ }
+
+ result_type operator() (stream_type& strm, value_type const& value) const
+ {
+ for (typename formatters::const_iterator it = m_formatters.begin(), end = m_formatters.end(); strm.good() && it != end; ++it)
+ {
+ (*it)(strm, value);
+ }
+ }
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template< typename FunT >
+ void add_formatter(FunT&& fun)
+ {
+ m_formatters.emplace_back(boost::forward< FunT >(fun));
+ }
+#else
+ template< typename FunT >
+ void add_formatter(FunT const& fun)
+ {
+ m_formatters.push_back(formatter_type(fun));
+ }
+#endif
+
+ void swap(named_scope_formatter& that)
+ {
+ m_formatters.swap(that.m_formatters);
+ }
+};
+
+//! Parses the named scope format string and constructs the formatter function
+template< typename CharT >
+BOOST_FORCEINLINE boost::log::aux::light_function< void (basic_formatting_ostream< CharT >&, attributes::named_scope::value_type::value_type const&) >
+do_parse_named_scope_format(const CharT* begin, const CharT* end)
+{
+ typedef CharT char_type;
+ typedef boost::log::aux::light_function< void (basic_formatting_ostream< char_type >&, attributes::named_scope::value_type::value_type const&) > result_type;
+ typedef named_scope_formatter< char_type > formatter_type;
+ formatter_type fmt;
+
+ std::basic_string< char_type > literal;
+
+ while (begin != end)
+ {
+ const char_type* p = std::find(begin, end, static_cast< char_type >('%'));
+ literal.append(begin, p);
+
+ if ((end - p) >= 2)
+ {
+ switch (p[1])
+ {
+ case '%':
+ literal.push_back(static_cast< char_type >('%'));
+ break;
+
+ case 'n':
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+ fmt.add_formatter(typename formatter_type::scope_name());
+ break;
+
+ case 'c':
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+ fmt.add_formatter(typename formatter_type::function_name(true));
+ break;
+
+ case 'C':
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+ fmt.add_formatter(typename formatter_type::function_name(false));
+ break;
+
+ case 'f':
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+ fmt.add_formatter(typename formatter_type::full_file_name());
+ break;
+
+ case 'F':
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+ fmt.add_formatter(typename formatter_type::file_name());
+ break;
+
+ case 'l':
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+ fmt.add_formatter(typename formatter_type::line_number());
+ break;
+
+ default:
+ literal.append(p, p + 2);
+ break;
+ }
+
+ begin = p + 2;
+ }
+ else
+ {
+ if (p != end)
+ literal.push_back(static_cast< char_type >('%')); // a single '%' character at the end of the string
+ begin = end;
+ }
+ }
+
+ if (!literal.empty())
+ fmt.add_formatter(typename formatter_type::literal(literal));
+
+ return result_type(boost::move(fmt));
+}
+
+} // namespace
+
+
+#ifdef BOOST_LOG_USE_CHAR
+
+//! Parses the named scope format string and constructs the formatter function
+BOOST_LOG_API boost::log::aux::light_function< void (basic_formatting_ostream< char >&, attributes::named_scope::value_type::value_type const&) >
+parse_named_scope_format(const char* begin, const char* end)
+{
+ return do_parse_named_scope_format(begin, end);
+}
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+//! Parses the named scope format string and constructs the formatter function
+BOOST_LOG_API boost::log::aux::light_function< void (basic_formatting_ostream< wchar_t >&, attributes::named_scope::value_type::value_type const&) >
+parse_named_scope_format(const wchar_t* begin, const wchar_t* end)
+{
+ return do_parse_named_scope_format(begin, end);
+}
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace aux
+
+} // namespace expressions
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/once_block.cpp b/src/boost/libs/log/src/once_block.cpp
new file mode 100644
index 000000000..c76009da0
--- /dev/null
+++ b/src/boost/libs/log/src/once_block.cpp
@@ -0,0 +1,471 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file once_block.cpp
+ * \author Andrey Semashev
+ * \date 23.06.2010
+ *
+ * \brief This file is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ *
+ * The code in this file is based on the \c call_once function implementation in Boost.Thread.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/utility/once_block.hpp>
+#ifndef BOOST_LOG_NO_THREADS
+
+#include <cstdlib>
+#include <boost/assert.hpp>
+
+#if defined(BOOST_THREAD_PLATFORM_WIN32)
+
+#include <boost/winapi/wait.hpp> // INFINITE
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+#include <boost/winapi/srw_lock.hpp>
+#include <boost/winapi/condition_variable.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+boost::winapi::SRWLOCK_ g_OnceBlockMutex = BOOST_WINAPI_SRWLOCK_INIT;
+boost::winapi::CONDITION_VARIABLE_ g_OnceBlockCond = BOOST_WINAPI_CONDITION_VARIABLE_INIT;
+
+} // namespace
+
+BOOST_LOG_API bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT
+{
+ boost::winapi::AcquireSRWLockExclusive(&g_OnceBlockMutex);
+
+ once_block_flag volatile& flag = m_flag;
+ while (flag.status != once_block_flag::initialized)
+ {
+ if (flag.status == once_block_flag::uninitialized)
+ {
+ flag.status = once_block_flag::being_initialized;
+ boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex);
+
+ // Invoke the initializer block
+ return false;
+ }
+ else
+ {
+ while (flag.status == once_block_flag::being_initialized)
+ {
+ BOOST_VERIFY(boost::winapi::SleepConditionVariableSRW(
+ &g_OnceBlockCond, &g_OnceBlockMutex, boost::winapi::INFINITE_, 0));
+ }
+ }
+ }
+
+ boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex);
+
+ return true;
+}
+
+BOOST_LOG_API void once_block_sentry::commit() BOOST_NOEXCEPT
+{
+ boost::winapi::AcquireSRWLockExclusive(&g_OnceBlockMutex);
+
+ // The initializer executed successfully
+ m_flag.status = once_block_flag::initialized;
+
+ boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex);
+ boost::winapi::WakeAllConditionVariable(&g_OnceBlockCond);
+}
+
+BOOST_LOG_API void once_block_sentry::rollback() BOOST_NOEXCEPT
+{
+ boost::winapi::AcquireSRWLockExclusive(&g_OnceBlockMutex);
+
+ // The initializer failed, marking the flag as if it hasn't run at all
+ m_flag.status = once_block_flag::uninitialized;
+
+ boost::winapi::ReleaseSRWLockExclusive(&g_OnceBlockMutex);
+ boost::winapi::WakeAllConditionVariable(&g_OnceBlockCond);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+#include <cstdlib> // atexit
+#include <boost/detail/interlocked.hpp>
+#include <boost/winapi/basic_types.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ struct BOOST_LOG_NO_VTABLE once_block_impl_base
+ {
+ virtual ~once_block_impl_base() {}
+ virtual bool enter_once_block(once_block_flag volatile& flag) = 0;
+ virtual void commit(once_block_flag& flag) = 0;
+ virtual void rollback(once_block_flag& flag) = 0;
+ };
+
+ class once_block_impl_nt6 :
+ public once_block_impl_base
+ {
+ public:
+ struct winapi_srwlock { void* p; };
+ struct winapi_condition_variable { void* p; };
+
+ typedef void (BOOST_WINAPI_WINAPI_CC *InitializeSRWLock_t)(winapi_srwlock*);
+ typedef void (BOOST_WINAPI_WINAPI_CC *AcquireSRWLockExclusive_t)(winapi_srwlock*);
+ typedef void (BOOST_WINAPI_WINAPI_CC *ReleaseSRWLockExclusive_t)(winapi_srwlock*);
+ typedef void (BOOST_WINAPI_WINAPI_CC *InitializeConditionVariable_t)(winapi_condition_variable*);
+ typedef boost::winapi::BOOL_ (BOOST_WINAPI_WINAPI_CC *SleepConditionVariableSRW_t)(winapi_condition_variable*, winapi_srwlock*, boost::winapi::DWORD_, boost::winapi::ULONG_);
+ typedef void (BOOST_WINAPI_WINAPI_CC *WakeAllConditionVariable_t)(winapi_condition_variable*);
+
+ private:
+ winapi_srwlock m_Mutex;
+ winapi_condition_variable m_Cond;
+
+ AcquireSRWLockExclusive_t m_pAcquireSRWLockExclusive;
+ ReleaseSRWLockExclusive_t m_pReleaseSRWLockExclusive;
+ SleepConditionVariableSRW_t m_pSleepConditionVariableSRW;
+ WakeAllConditionVariable_t m_pWakeAllConditionVariable;
+
+ public:
+ once_block_impl_nt6(
+ InitializeSRWLock_t pInitializeSRWLock,
+ AcquireSRWLockExclusive_t pAcquireSRWLockExclusive,
+ ReleaseSRWLockExclusive_t pReleaseSRWLockExclusive,
+ InitializeConditionVariable_t pInitializeConditionVariable,
+ SleepConditionVariableSRW_t pSleepConditionVariableSRW,
+ WakeAllConditionVariable_t pWakeAllConditionVariable
+ ) :
+ m_pAcquireSRWLockExclusive(pAcquireSRWLockExclusive),
+ m_pReleaseSRWLockExclusive(pReleaseSRWLockExclusive),
+ m_pSleepConditionVariableSRW(pSleepConditionVariableSRW),
+ m_pWakeAllConditionVariable(pWakeAllConditionVariable)
+ {
+ pInitializeSRWLock(&m_Mutex);
+ pInitializeConditionVariable(&m_Cond);
+ }
+
+ bool enter_once_block(once_block_flag volatile& flag)
+ {
+ m_pAcquireSRWLockExclusive(&m_Mutex);
+
+ while (flag.status != once_block_flag::initialized)
+ {
+ if (flag.status == once_block_flag::uninitialized)
+ {
+ flag.status = once_block_flag::being_initialized;
+ m_pReleaseSRWLockExclusive(&m_Mutex);
+
+ // Invoke the initializer block
+ return false;
+ }
+ else
+ {
+ while (flag.status == once_block_flag::being_initialized)
+ {
+ BOOST_VERIFY(m_pSleepConditionVariableSRW(
+ &m_Cond, &m_Mutex, boost::winapi::INFINITE_, 0));
+ }
+ }
+ }
+
+ m_pReleaseSRWLockExclusive(&m_Mutex);
+
+ return true;
+ }
+
+ void commit(once_block_flag& flag)
+ {
+ m_pAcquireSRWLockExclusive(&m_Mutex);
+
+ // The initializer executed successfully
+ flag.status = once_block_flag::initialized;
+
+ m_pReleaseSRWLockExclusive(&m_Mutex);
+ m_pWakeAllConditionVariable(&m_Cond);
+ }
+
+ void rollback(once_block_flag& flag)
+ {
+ m_pAcquireSRWLockExclusive(&m_Mutex);
+
+ // The initializer failed, marking the flag as if it hasn't run at all
+ flag.status = once_block_flag::uninitialized;
+
+ m_pReleaseSRWLockExclusive(&m_Mutex);
+ m_pWakeAllConditionVariable(&m_Cond);
+ }
+ };
+
+ class once_block_impl_nt5 :
+ public once_block_impl_base
+ {
+ private:
+ mutex m_Mutex;
+ condition_variable m_Cond;
+
+ public:
+ bool enter_once_block(once_block_flag volatile& flag)
+ {
+ unique_lock< mutex > lock(m_Mutex);
+
+ while (flag.status != once_block_flag::initialized)
+ {
+ if (flag.status == once_block_flag::uninitialized)
+ {
+ flag.status = once_block_flag::being_initialized;
+
+ // Invoke the initializer block
+ return false;
+ }
+ else
+ {
+ while (flag.status == once_block_flag::being_initialized)
+ {
+ m_Cond.wait(lock);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ void commit(once_block_flag& flag)
+ {
+ {
+ lock_guard< mutex > lock(m_Mutex);
+ flag.status = once_block_flag::initialized;
+ }
+ m_Cond.notify_all();
+ }
+
+ void rollback(once_block_flag& flag)
+ {
+ {
+ lock_guard< mutex > lock(m_Mutex);
+ flag.status = once_block_flag::uninitialized;
+ }
+ m_Cond.notify_all();
+ }
+ };
+
+ once_block_impl_base* create_once_block_impl()
+ {
+ boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ {
+ once_block_impl_nt6::InitializeSRWLock_t pInitializeSRWLock =
+ (once_block_impl_nt6::InitializeSRWLock_t)boost::winapi::get_proc_address(hKernel32, "InitializeSRWLock");
+ if (pInitializeSRWLock)
+ {
+ once_block_impl_nt6::AcquireSRWLockExclusive_t pAcquireSRWLockExclusive =
+ (once_block_impl_nt6::AcquireSRWLockExclusive_t)boost::winapi::get_proc_address(hKernel32, "AcquireSRWLockExclusive");
+ if (pAcquireSRWLockExclusive)
+ {
+ once_block_impl_nt6::ReleaseSRWLockExclusive_t pReleaseSRWLockExclusive =
+ (once_block_impl_nt6::ReleaseSRWLockExclusive_t)boost::winapi::get_proc_address(hKernel32, "ReleaseSRWLockExclusive");
+ if (pReleaseSRWLockExclusive)
+ {
+ once_block_impl_nt6::InitializeConditionVariable_t pInitializeConditionVariable =
+ (once_block_impl_nt6::InitializeConditionVariable_t)boost::winapi::get_proc_address(hKernel32, "InitializeConditionVariable");
+ if (pInitializeConditionVariable)
+ {
+ once_block_impl_nt6::SleepConditionVariableSRW_t pSleepConditionVariableSRW =
+ (once_block_impl_nt6::SleepConditionVariableSRW_t)boost::winapi::get_proc_address(hKernel32, "SleepConditionVariableSRW");
+ if (pSleepConditionVariableSRW)
+ {
+ once_block_impl_nt6::WakeAllConditionVariable_t pWakeAllConditionVariable =
+ (once_block_impl_nt6::WakeAllConditionVariable_t)boost::winapi::get_proc_address(hKernel32, "WakeAllConditionVariable");
+ if (pWakeAllConditionVariable)
+ {
+ return new once_block_impl_nt6(
+ pInitializeSRWLock,
+ pAcquireSRWLockExclusive,
+ pReleaseSRWLockExclusive,
+ pInitializeConditionVariable,
+ pSleepConditionVariableSRW,
+ pWakeAllConditionVariable);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return new once_block_impl_nt5();
+ }
+
+ once_block_impl_base* g_pOnceBlockImpl = NULL;
+
+ void destroy_once_block_impl()
+ {
+ once_block_impl_base* impl = (once_block_impl_base*)
+ BOOST_INTERLOCKED_EXCHANGE_POINTER((void**)&g_pOnceBlockImpl, NULL);
+ delete impl;
+ }
+
+ once_block_impl_base* get_once_block_impl() BOOST_NOEXCEPT
+ {
+ once_block_impl_base* impl = g_pOnceBlockImpl;
+ if (!impl) try
+ {
+ once_block_impl_base* new_impl = create_once_block_impl();
+ impl = (once_block_impl_base*)
+ BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER((void**)&g_pOnceBlockImpl, (void*)new_impl, NULL);
+ if (impl)
+ {
+ delete new_impl;
+ }
+ else
+ {
+ std::atexit(&destroy_once_block_impl);
+ return new_impl;
+ }
+ }
+ catch (...)
+ {
+ BOOST_ASSERT_MSG(false, "Boost.Log: Failed to initialize the once block thread synchronization structures");
+ std::abort();
+ }
+
+ return impl;
+ }
+
+} // namespace
+
+BOOST_LOG_API bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT
+{
+ return get_once_block_impl()->enter_once_block(m_flag);
+}
+
+BOOST_LOG_API void once_block_sentry::commit() BOOST_NOEXCEPT
+{
+ get_once_block_impl()->commit(m_flag);
+}
+
+BOOST_LOG_API void once_block_sentry::rollback() BOOST_NOEXCEPT
+{
+ get_once_block_impl()->rollback(m_flag);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
+
+#include <pthread.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+static pthread_mutex_t g_OnceBlockMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t g_OnceBlockCond = PTHREAD_COND_INITIALIZER;
+
+} // namespace
+
+BOOST_LOG_API bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT
+{
+ BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex));
+
+ once_block_flag volatile& flag = m_flag;
+ while (flag.status != once_block_flag::initialized)
+ {
+ if (flag.status == once_block_flag::uninitialized)
+ {
+ flag.status = once_block_flag::being_initialized;
+ BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex));
+
+ // Invoke the initializer block
+ return false;
+ }
+ else
+ {
+ while (flag.status == once_block_flag::being_initialized)
+ {
+ BOOST_VERIFY(!pthread_cond_wait(&g_OnceBlockCond, &g_OnceBlockMutex));
+ }
+ }
+ }
+
+ BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex));
+
+ return true;
+}
+
+BOOST_LOG_API void once_block_sentry::commit() BOOST_NOEXCEPT
+{
+ BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex));
+
+ // The initializer executed successfully
+ m_flag.status = once_block_flag::initialized;
+
+ BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex));
+ BOOST_VERIFY(!pthread_cond_broadcast(&g_OnceBlockCond));
+}
+
+BOOST_LOG_API void once_block_sentry::rollback() BOOST_NOEXCEPT
+{
+ BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex));
+
+ // The initializer failed, marking the flag as if it hasn't run at all
+ m_flag.status = once_block_flag::uninitialized;
+
+ BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex));
+ BOOST_VERIFY(!pthread_cond_broadcast(&g_OnceBlockCond));
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#else
+#error Boost.Log: unsupported threading API
+#endif
+
+#endif // BOOST_LOG_NO_THREADS
diff --git a/src/boost/libs/log/src/permissions.cpp b/src/boost/libs/log/src/permissions.cpp
new file mode 100644
index 000000000..9bf80964a
--- /dev/null
+++ b/src/boost/libs/log/src/permissions.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright Andrey Semashev 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)
+ */
+/*!
+ * \file permissions.cpp
+ * \author Andrey Semashev
+ * \date 26.12.2015
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/utility/permissions.hpp>
+#include <boost/interprocess/permissions.hpp>
+
+#if defined(BOOST_WINDOWS)
+
+#include <boost/log/exceptions.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/log/utility/once_block.hpp>
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+static ::SECURITY_DESCRIPTOR g_unrestricted_security_descriptor;
+static ::SECURITY_ATTRIBUTES g_unrestricted_security_attributes;
+
+} // namespace
+
+BOOST_LOG_API permissions::native_type permissions::get_unrestricted_security_attributes()
+{
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ if (!InitializeSecurityDescriptor(&g_unrestricted_security_descriptor, SECURITY_DESCRIPTOR_REVISION))
+ {
+ DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize security descriptor", (err));
+ }
+
+ if (!SetSecurityDescriptorDacl(&g_unrestricted_security_descriptor, TRUE, NULL, FALSE))
+ {
+ DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set null DACL to a security descriptor", (err));
+ }
+
+ g_unrestricted_security_attributes.nLength = sizeof(g_unrestricted_security_attributes);
+ g_unrestricted_security_attributes.lpSecurityDescriptor = &g_unrestricted_security_descriptor;
+ g_unrestricted_security_attributes.bInheritHandle = FALSE;
+ }
+
+ return &g_unrestricted_security_attributes;
+}
+
+//! Initializing constructor
+BOOST_LOG_API permissions::permissions(boost::interprocess::permissions const& perms) BOOST_NOEXCEPT :
+ m_perms(reinterpret_cast< native_type >(perms.get_permissions()))
+{
+}
+
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#else // defined(BOOST_WINDOWS)
+
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+//! Initializing constructor
+BOOST_LOG_API permissions::permissions(boost::interprocess::permissions const& perms) BOOST_NOEXCEPT :
+ m_perms(static_cast< native_type >(perms.get_permissions()))
+{
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS)
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/posix/ipc_reliable_message_queue.cpp b/src/boost/libs/log/src/posix/ipc_reliable_message_queue.cpp
new file mode 100644
index 000000000..07d61fa55
--- /dev/null
+++ b/src/boost/libs/log/src/posix/ipc_reliable_message_queue.cpp
@@ -0,0 +1,881 @@
+/*
+ * Copyright Lingxi Li 2015.
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file posix/ipc_reliable_message_queue.cpp
+ * \author Lingxi Li
+ * \author Andrey Semashev
+ * \date 17.11.2015
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ *
+ * This file provides an interprocess message queue implementation on POSIX platforms.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <cerrno>
+#include <cstring>
+#include <new>
+#include <string>
+#include <stdexcept>
+#include <algorithm>
+#include <unistd.h>
+#if defined(BOOST_HAS_SCHED_YIELD)
+#include <sched.h>
+#elif defined(BOOST_HAS_PTHREAD_YIELD)
+#include <pthread.h>
+#elif defined(BOOST_HAS_NANOSLEEP)
+#include <time.h>
+#endif
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/atomic/capabilities.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/ipc/reliable_message_queue.hpp>
+#include <boost/log/support/exception.hpp>
+#include <boost/log/detail/pause.hpp>
+#include <boost/exception/info.hpp>
+#include <boost/exception/enable_error_info.hpp>
+#include <boost/interprocess/creation_tags.hpp>
+#include <boost/interprocess/exceptions.hpp>
+#include <boost/interprocess/permissions.hpp>
+#include <boost/interprocess/mapped_region.hpp>
+#include <boost/interprocess/shared_memory_object.hpp>
+#include <boost/align/align_up.hpp>
+#include "ipc_sync_wrappers.hpp"
+#include "murmur3.hpp"
+#include "bit_tools.hpp"
+#include <boost/log/detail/header.hpp>
+
+#if BOOST_ATOMIC_INT32_LOCK_FREE != 2
+// 32-bit atomic ops are required to be able to place atomic<uint32_t> in the process-shared memory
+#error Boost.Log: Native 32-bit atomic operations are required but not supported by Boost.Atomic on the target platform
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+//! Message queue implementation data
+struct reliable_message_queue::implementation
+{
+private:
+ //! Header of an allocation block within the message queue. Placed at the beginning of the block within the shared memory segment.
+ struct block_header
+ {
+ // Element data alignment, in bytes
+ enum { data_alignment = 32u };
+
+ //! Size of the element data, in bytes
+ size_type m_size;
+
+ //! Returns the block header overhead, in bytes
+ static BOOST_CONSTEXPR size_type get_header_overhead() BOOST_NOEXCEPT
+ {
+ return static_cast< size_type >(boost::alignment::align_up(sizeof(block_header), data_alignment));
+ }
+
+ //! Returns a pointer to the element data
+ void* get_data() const BOOST_NOEXCEPT
+ {
+ return const_cast< unsigned char* >(reinterpret_cast< const unsigned char* >(this)) + get_header_overhead();
+ }
+ };
+
+ //! Header of the message queue. Placed at the beginning of the shared memory segment.
+ struct header
+ {
+ // Increment this constant whenever you change the binary layout of the queue (apart from this header structure)
+ enum { abi_version = 0 };
+
+ // !!! Whenever you add/remove members in this structure, also modify get_abi_tag() function accordingly !!!
+
+ //! A tag value to ensure the correct binary layout of the message queue data structures. Must be placed first and always have a fixed size and alignment.
+ uint32_t m_abi_tag;
+ //! Padding to protect against alignment changes in Boost.Atomic. Don't use BOOST_ALIGNMENT to ensure portability.
+ unsigned char m_padding[BOOST_LOG_CPU_CACHE_LINE_SIZE - sizeof(uint32_t)];
+ //! Reference counter. Also acts as a flag indicating that the queue is constructed (i.e. the queue is constructed when the counter is not 0).
+ boost::atomic< uint32_t > m_ref_count;
+ //! Number of allocation blocks in the queue.
+ const uint32_t m_capacity;
+ //! Size of an allocation block, in bytes.
+ const size_type m_block_size;
+ //! Mutex for protecting queue data structures.
+ boost::log::ipc::aux::interprocess_mutex m_mutex;
+ //! Condition variable used to block readers when the queue is empty.
+ boost::log::ipc::aux::interprocess_condition_variable m_nonempty_queue;
+ //! Condition variable used to block writers when the queue is full.
+ boost::log::ipc::aux::interprocess_condition_variable m_nonfull_queue;
+ //! The current number of allocated blocks in the queue.
+ uint32_t m_size;
+ //! The current writing position (allocation block index).
+ uint32_t m_put_pos;
+ //! The current reading position (allocation block index).
+ uint32_t m_get_pos;
+
+ header(uint32_t capacity, size_type block_size) :
+ m_abi_tag(get_abi_tag()),
+ m_capacity(capacity),
+ m_block_size(block_size),
+ m_size(0u),
+ m_put_pos(0u),
+ m_get_pos(0u)
+ {
+ // Must be initialized last. m_ref_count is zero-initialized initially.
+ m_ref_count.fetch_add(1u, boost::memory_order_release);
+ }
+
+ //! Returns the header structure ABI tag
+ static uint32_t get_abi_tag() BOOST_NOEXCEPT
+ {
+ // This FOURCC identifies the queue type
+ boost::log::aux::murmur3_32 hash(boost::log::aux::make_fourcc('r', 'e', 'l', 'q'));
+
+ // This FOURCC identifies the queue implementation
+ hash.mix(boost::log::aux::make_fourcc('p', 't', 'h', 'r'));
+ hash.mix(abi_version);
+
+ // We will use these constants to align pointers
+ hash.mix(BOOST_LOG_CPU_CACHE_LINE_SIZE);
+ hash.mix(block_header::data_alignment);
+
+ // The members in the sequence below must be enumerated in the same order as they are declared in the header structure.
+ // The ABI tag is supposed change whenever a member changes size or offset from the beginning of the header.
+
+#define BOOST_LOG_MIX_HEADER_MEMBER(name)\
+ hash.mix(static_cast< uint32_t >(sizeof(((header*)NULL)->name)));\
+ hash.mix(static_cast< uint32_t >(offsetof(header, name)))
+
+ BOOST_LOG_MIX_HEADER_MEMBER(m_abi_tag);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_padding);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_ref_count);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_capacity);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_block_size);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_mutex);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_nonempty_queue);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_nonfull_queue);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_size);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_put_pos);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_get_pos);
+
+#undef BOOST_LOG_MIX_HEADER_MEMBER
+
+ return hash.finalize();
+ }
+
+ //! Returns an element header at the specified index
+ block_header* get_block(uint32_t index) const BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT(index < m_capacity);
+ unsigned char* p = const_cast< unsigned char* >(reinterpret_cast< const unsigned char* >(this)) + boost::alignment::align_up(sizeof(header), BOOST_LOG_CPU_CACHE_LINE_SIZE);
+ p += static_cast< std::size_t >(m_block_size) * static_cast< std::size_t >(index);
+ return reinterpret_cast< block_header* >(p);
+ }
+
+ BOOST_DELETED_FUNCTION(header(header const&))
+ BOOST_DELETED_FUNCTION(header& operator=(header const&))
+ };
+
+private:
+ //! Shared memory object
+ boost::interprocess::shared_memory_object m_shared_memory;
+ //! Shared memory mapping into the process address space
+ boost::interprocess::mapped_region m_region;
+ //! Queue overflow handling policy
+ const overflow_policy m_overflow_policy;
+ //! The mask for selecting bits that constitute size values from 0 to (block_size - 1)
+ size_type m_block_size_mask;
+ //! The number of the bit set in block_size (i.e. log base 2 of block_size)
+ uint32_t m_block_size_log2;
+ //! The flag indicates that stop has been requested
+ bool m_stop;
+
+ //! Queue shared memory object name
+ const object_name m_name;
+
+public:
+ //! The constructor creates a new shared memory segment
+ implementation
+ (
+ open_mode::create_only_tag,
+ object_name const& name,
+ uint32_t capacity,
+ size_type block_size,
+ overflow_policy oflow_policy,
+ permissions const& perms
+ ) :
+ m_shared_memory(boost::interprocess::create_only, name.c_str(), boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())),
+ m_region(),
+ m_overflow_policy(oflow_policy),
+ m_block_size_mask(0u),
+ m_block_size_log2(0u),
+ m_stop(false),
+ m_name(name)
+ {
+ create_region(capacity, block_size);
+ }
+
+ //! The constructor creates a new shared memory segment or opens the existing one
+ implementation
+ (
+ open_mode::open_or_create_tag,
+ object_name const& name,
+ uint32_t capacity,
+ size_type block_size,
+ overflow_policy oflow_policy,
+ permissions const& perms
+ ) :
+ m_shared_memory(boost::interprocess::open_or_create, name.c_str(), boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())),
+ m_region(),
+ m_overflow_policy(oflow_policy),
+ m_block_size_mask(0u),
+ m_block_size_log2(0u),
+ m_stop(false),
+ m_name(name)
+ {
+ boost::interprocess::offset_t shmem_size = 0;
+ if (!m_shared_memory.get_size(shmem_size) || shmem_size == 0)
+ create_region(capacity, block_size);
+ else
+ adopt_region(shmem_size);
+ }
+
+ //! The constructor opens the existing shared memory segment
+ implementation
+ (
+ open_mode::open_only_tag,
+ object_name const& name,
+ overflow_policy oflow_policy
+ ) :
+ m_shared_memory(boost::interprocess::open_only, name.c_str(), boost::interprocess::read_write),
+ m_region(),
+ m_overflow_policy(oflow_policy),
+ m_block_size_mask(0u),
+ m_block_size_log2(0u),
+ m_stop(false),
+ m_name(name)
+ {
+ boost::interprocess::offset_t shmem_size = 0;
+ if (!m_shared_memory.get_size(shmem_size))
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment not found");
+
+ adopt_region(shmem_size);
+ }
+
+ ~implementation()
+ {
+ close_region();
+ }
+
+ object_name const& name() const BOOST_NOEXCEPT
+ {
+ return m_name;
+ }
+
+ uint32_t capacity() const BOOST_NOEXCEPT
+ {
+ return get_header()->m_capacity;
+ }
+
+ size_type block_size() const BOOST_NOEXCEPT
+ {
+ return get_header()->m_block_size;
+ }
+
+ operation_result send(void const* message_data, size_type message_size)
+ {
+ const uint32_t block_count = estimate_block_count(message_size);
+
+ header* const hdr = get_header();
+
+ if (BOOST_UNLIKELY(block_count > hdr->m_capacity))
+ BOOST_LOG_THROW_DESCR(logic_error, "Message size exceeds the interprocess queue capacity");
+
+ if (m_stop)
+ return aborted;
+
+ lock_queue();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex);
+
+ while (true)
+ {
+ if (m_stop)
+ return aborted;
+
+ if ((hdr->m_capacity - hdr->m_size) >= block_count)
+ break;
+
+ const overflow_policy oflow_policy = m_overflow_policy;
+ if (oflow_policy == fail_on_overflow)
+ return no_space;
+ else if (BOOST_UNLIKELY(oflow_policy == throw_on_overflow))
+ BOOST_LOG_THROW_DESCR(capacity_limit_reached, "Interprocess queue is full");
+
+ hdr->m_nonfull_queue.wait(hdr->m_mutex);
+ }
+
+ enqueue_message(message_data, message_size, block_count);
+
+ return succeeded;
+ }
+
+ bool try_send(void const* message_data, size_type message_size)
+ {
+ const uint32_t block_count = estimate_block_count(message_size);
+
+ header* const hdr = get_header();
+
+ if (BOOST_UNLIKELY(block_count > hdr->m_capacity))
+ BOOST_LOG_THROW_DESCR(logic_error, "Message size exceeds the interprocess queue capacity");
+
+ if (m_stop)
+ return false;
+
+ lock_queue();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex);
+
+ if (m_stop)
+ return false;
+
+ if ((hdr->m_capacity - hdr->m_size) < block_count)
+ return false;
+
+ enqueue_message(message_data, message_size, block_count);
+
+ return true;
+ }
+
+ operation_result receive(receive_handler handler, void* state)
+ {
+ if (m_stop)
+ return aborted;
+
+ lock_queue();
+ header* const hdr = get_header();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex);
+
+ while (true)
+ {
+ if (m_stop)
+ return aborted;
+
+ if (hdr->m_size > 0u)
+ break;
+
+ hdr->m_nonempty_queue.wait(hdr->m_mutex);
+ }
+
+ dequeue_message(handler, state);
+
+ return succeeded;
+ }
+
+ bool try_receive(receive_handler handler, void* state)
+ {
+ if (m_stop)
+ return false;
+
+ lock_queue();
+ header* const hdr = get_header();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex);
+
+ if (hdr->m_size == 0u)
+ return false;
+
+ dequeue_message(handler, state);
+
+ return true;
+ }
+
+ void stop_local()
+ {
+ if (m_stop)
+ return;
+
+ lock_queue();
+ header* const hdr = get_header();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex);
+
+ m_stop = true;
+
+ hdr->m_nonempty_queue.notify_all();
+ hdr->m_nonfull_queue.notify_all();
+ }
+
+ void reset_local()
+ {
+ m_stop = false;
+ }
+
+ void clear()
+ {
+ lock_queue();
+ header* const hdr = get_header();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex);
+ clear_queue();
+ }
+
+private:
+ header* get_header() const BOOST_NOEXCEPT
+ {
+ return static_cast< header* >(m_region.get_address());
+ }
+
+ static std::size_t estimate_region_size(uint32_t capacity, size_type block_size) BOOST_NOEXCEPT
+ {
+ return boost::alignment::align_up(sizeof(header), BOOST_LOG_CPU_CACHE_LINE_SIZE) + static_cast< std::size_t >(capacity) * static_cast< std::size_t >(block_size);
+ }
+
+ void create_region(uint32_t capacity, size_type block_size)
+ {
+ const std::size_t shmem_size = estimate_region_size(capacity, block_size);
+ m_shared_memory.truncate(shmem_size);
+ boost::interprocess::mapped_region(m_shared_memory, boost::interprocess::read_write, 0u, shmem_size).swap(m_region);
+
+ new (m_region.get_address()) header(capacity, block_size);
+
+ init_block_size(block_size);
+ }
+
+ void adopt_region(std::size_t shmem_size)
+ {
+ if (shmem_size < sizeof(header))
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment size too small");
+
+ boost::interprocess::mapped_region(m_shared_memory, boost::interprocess::read_write, 0u, shmem_size).swap(m_region);
+
+ // Wait until the mapped region becomes initialized
+ header* const hdr = get_header();
+ BOOST_CONSTEXPR_OR_CONST unsigned int wait_loops = 200u, spin_loops = 16u, spins = 16u;
+ for (unsigned int i = 0; i < wait_loops; ++i)
+ {
+ uint32_t ref_count = hdr->m_ref_count.load(boost::memory_order_acquire);
+ while (ref_count > 0u)
+ {
+ if (hdr->m_ref_count.compare_exchange_weak(ref_count, ref_count + 1u, boost::memory_order_acq_rel, boost::memory_order_acquire))
+ goto done;
+ }
+
+ if (i < spin_loops)
+ {
+ for (unsigned int j = 0; j < spins; ++j)
+ {
+ boost::log::aux::pause();
+ }
+ }
+ else
+ {
+#if defined(BOOST_HAS_SCHED_YIELD)
+ sched_yield();
+#elif defined(BOOST_HAS_PTHREAD_YIELD)
+ pthread_yield();
+#elif defined(BOOST_HAS_NANOSLEEP)
+ timespec ts = {};
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000;
+ nanosleep(&ts, NULL);
+#else
+ usleep(1);
+#endif
+ }
+ }
+
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment is not initialized by creator for too long");
+
+ done:
+ try
+ {
+ // Check that the queue layout matches the current process ABI
+ if (hdr->m_abi_tag != header::get_abi_tag())
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: the queue ABI is incompatible");
+
+ if (!boost::log::aux::is_power_of_2(hdr->m_block_size))
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: the queue block size is not a power of 2");
+
+ init_block_size(hdr->m_block_size);
+ }
+ catch (...)
+ {
+ close_region();
+ throw;
+ }
+ }
+
+ void close_region() BOOST_NOEXCEPT
+ {
+ header* const hdr = get_header();
+
+ if (hdr->m_ref_count.fetch_sub(1u, boost::memory_order_acq_rel) == 1u)
+ {
+ boost::interprocess::shared_memory_object::remove(m_shared_memory.get_name());
+
+ hdr->~header();
+
+ boost::interprocess::mapped_region().swap(m_region);
+ boost::interprocess::shared_memory_object().swap(m_shared_memory);
+
+ m_block_size_mask = 0u;
+ m_block_size_log2 = 0u;
+ }
+ }
+
+ void init_block_size(size_type block_size)
+ {
+ m_block_size_mask = block_size - 1u;
+
+ uint32_t block_size_log2 = 0u;
+ if ((block_size & 0x0000ffff) == 0u)
+ {
+ block_size >>= 16u;
+ block_size_log2 += 16u;
+ }
+ if ((block_size & 0x000000ff) == 0u)
+ {
+ block_size >>= 8u;
+ block_size_log2 += 8u;
+ }
+ if ((block_size & 0x0000000f) == 0u)
+ {
+ block_size >>= 4u;
+ block_size_log2 += 4u;
+ }
+ if ((block_size & 0x00000003) == 0u)
+ {
+ block_size >>= 2u;
+ block_size_log2 += 2u;
+ }
+ if ((block_size & 0x00000001) == 0u)
+ {
+ ++block_size_log2;
+ }
+ m_block_size_log2 = block_size_log2;
+ }
+
+ void lock_queue()
+ {
+ header* const hdr = get_header();
+
+#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
+ try
+ {
+#endif
+ hdr->m_mutex.lock();
+#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
+ }
+ catch (boost::log::ipc::aux::lock_owner_dead&)
+ {
+ // The mutex is locked by the current thread, but the previous owner terminated without releasing the lock
+ try
+ {
+ clear_queue();
+ hdr->m_mutex.recover();
+ }
+ catch (...)
+ {
+ hdr->m_mutex.unlock();
+ throw;
+ }
+ }
+#endif
+ }
+
+ void clear_queue()
+ {
+ header* const hdr = get_header();
+ hdr->m_size = 0u;
+ hdr->m_put_pos = 0u;
+ hdr->m_get_pos = 0u;
+ hdr->m_nonfull_queue.notify_all();
+ }
+
+ //! Returns the number of allocation blocks that are required to store user's payload of the specified size
+ uint32_t estimate_block_count(size_type size) const BOOST_NOEXCEPT
+ {
+ // ceil((size + get_header_overhead()) / block_size)
+ return static_cast< uint32_t >((size + block_header::get_header_overhead() + m_block_size_mask) >> m_block_size_log2);
+ }
+
+ //! Puts the message to the back of the queue
+ void enqueue_message(void const* message_data, size_type message_size, uint32_t block_count)
+ {
+ header* const hdr = get_header();
+
+ const uint32_t capacity = hdr->m_capacity;
+ const size_type block_size = hdr->m_block_size;
+ uint32_t pos = hdr->m_put_pos;
+
+ block_header* block = hdr->get_block(pos);
+ block->m_size = message_size;
+
+ size_type write_size = (std::min)(static_cast< size_type >((capacity - pos) * block_size - block_header::get_header_overhead()), message_size);
+ std::memcpy(block->get_data(), message_data, write_size);
+
+ pos += block_count;
+ if (BOOST_UNLIKELY(pos >= capacity))
+ {
+ // Write the rest of the message at the beginning of the queue
+ pos -= capacity;
+ message_data = static_cast< const unsigned char* >(message_data) + write_size;
+ write_size = message_size - write_size;
+ if (write_size > 0u)
+ std::memcpy(hdr->get_block(0u), message_data, write_size);
+ }
+
+ hdr->m_put_pos = pos;
+
+ const uint32_t old_queue_size = hdr->m_size;
+ hdr->m_size = old_queue_size + block_count;
+ if (old_queue_size == 0u)
+ hdr->m_nonempty_queue.notify_one();
+ }
+
+ //! Retrieves the next message and invokes the handler to store the message contents
+ void dequeue_message(receive_handler handler, void* state)
+ {
+ header* const hdr = get_header();
+
+ const uint32_t capacity = hdr->m_capacity;
+ const size_type block_size = hdr->m_block_size;
+ uint32_t pos = hdr->m_get_pos;
+
+ block_header* block = hdr->get_block(pos);
+ size_type message_size = block->m_size;
+ uint32_t block_count = estimate_block_count(message_size);
+
+ BOOST_ASSERT(block_count <= hdr->m_size);
+
+ size_type read_size = (std::min)(static_cast< size_type >((capacity - pos) * block_size - block_header::get_header_overhead()), message_size);
+ handler(state, block->get_data(), read_size);
+
+ pos += block_count;
+ if (BOOST_UNLIKELY(pos >= capacity))
+ {
+ // Read the tail of the message
+ pos -= capacity;
+ read_size = message_size - read_size;
+ if (read_size > 0u)
+ handler(state, hdr->get_block(0u), read_size);
+ }
+
+ hdr->m_get_pos = pos;
+ hdr->m_size -= block_count;
+
+ hdr->m_nonfull_queue.notify_all();
+ }
+};
+
+BOOST_LOG_API void reliable_message_queue::create(object_name const& name, uint32_t capacity, size_type block_size, overflow_policy oflow_policy, permissions const& perms)
+{
+ BOOST_ASSERT(m_impl == NULL);
+ if (!boost::log::aux::is_power_of_2(block_size))
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Interprocess message queue block size is not a power of 2"));
+ try
+ {
+ m_impl = new implementation(open_mode::create_only, name, capacity, static_cast< size_type >(boost::alignment::align_up(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE)), oflow_policy, perms);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(name);
+ throw;
+ }
+ catch (boost::interprocess::interprocess_exception& e)
+ {
+ BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::ipc::object_name_info(name));
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::open_or_create(object_name const& name, uint32_t capacity, size_type block_size, overflow_policy oflow_policy, permissions const& perms)
+{
+ BOOST_ASSERT(m_impl == NULL);
+ if (!boost::log::aux::is_power_of_2(block_size))
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Interprocess message queue block size is not a power of 2"));
+ try
+ {
+ m_impl = new implementation(open_mode::open_or_create, name, capacity, static_cast< size_type >(boost::alignment::align_up(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE)), oflow_policy, perms);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(name);
+ throw;
+ }
+ catch (boost::interprocess::interprocess_exception& e)
+ {
+ BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::ipc::object_name_info(name));
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::open(object_name const& name, overflow_policy oflow_policy, permissions const&)
+{
+ BOOST_ASSERT(m_impl == NULL);
+ try
+ {
+ m_impl = new implementation(open_mode::open_only, name, oflow_policy);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(name);
+ throw;
+ }
+ catch (boost::interprocess::interprocess_exception& e)
+ {
+ BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::ipc::object_name_info(name));
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::clear()
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ m_impl->clear();
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API object_name const& reliable_message_queue::name() const
+{
+ BOOST_ASSERT(m_impl != NULL);
+ return m_impl->name();
+}
+
+BOOST_LOG_API uint32_t reliable_message_queue::capacity() const
+{
+ BOOST_ASSERT(m_impl != NULL);
+ return m_impl->capacity();
+}
+
+BOOST_LOG_API reliable_message_queue::size_type reliable_message_queue::block_size() const
+{
+ BOOST_ASSERT(m_impl != NULL);
+ return m_impl->block_size();
+}
+
+BOOST_LOG_API void reliable_message_queue::stop_local()
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ m_impl->stop_local();
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::reset_local()
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ m_impl->reset_local();
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::do_close() BOOST_NOEXCEPT
+{
+ delete m_impl;
+ m_impl = NULL;
+}
+
+BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::send(void const* message_data, size_type message_size)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->send(message_data, message_size);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API bool reliable_message_queue::try_send(void const* message_data, size_type message_size)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->try_send(message_data, message_size);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::do_receive(receive_handler handler, void* state)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->receive(handler, state);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API bool reliable_message_queue::do_try_receive(receive_handler handler, void* state)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->try_receive(handler, state);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+//! Fixed buffer receive handler
+BOOST_LOG_API void reliable_message_queue::fixed_buffer_receive_handler(void* state, const void* data, size_type size)
+{
+ fixed_buffer_state* p = static_cast< fixed_buffer_state* >(state);
+ if (BOOST_UNLIKELY(size > p->size))
+ BOOST_THROW_EXCEPTION(bad_alloc("Buffer too small to receive the message"));
+
+ std::memcpy(p->data, data, size);
+ p->data += size;
+ p->size -= size;
+}
+
+BOOST_LOG_API void reliable_message_queue::remove(object_name const& name)
+{
+ boost::interprocess::shared_memory_object::remove(name.c_str());
+}
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/posix/ipc_sync_wrappers.hpp b/src/boost/libs/log/src/posix/ipc_sync_wrappers.hpp
new file mode 100644
index 000000000..b32acba22
--- /dev/null
+++ b/src/boost/libs/log/src/posix/ipc_sync_wrappers.hpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file posix/ipc_sync_wrappers.hpp
+ * \author Andrey Semashev
+ * \date 05.01.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_POSIX_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
+#define BOOST_LOG_POSIX_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <pthread.h>
+#include <cerrno>
+#include <cstddef>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+// Use Boost.Interprocess to detect if process-shared pthread primitives are supported
+#include <boost/interprocess/detail/workaround.hpp>
+#if !defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+#include <boost/core/explicit_operator_bool.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/sync/interprocess_condition.hpp>
+#undef BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST
+#endif
+#include <boost/log/exceptions.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+namespace aux {
+
+#if defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+
+#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
+struct BOOST_SYMBOL_VISIBLE lock_owner_dead {};
+#endif
+
+//! Pthread mutex attributes
+struct pthread_mutex_attributes
+{
+ pthread_mutexattr_t attrs;
+
+ pthread_mutex_attributes()
+ {
+ int err = pthread_mutexattr_init(&this->attrs);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread mutex attributes", (err));
+ }
+
+ ~pthread_mutex_attributes()
+ {
+ BOOST_VERIFY(pthread_mutexattr_destroy(&this->attrs) == 0);
+ }
+
+ BOOST_DELETED_FUNCTION(pthread_mutex_attributes(pthread_mutex_attributes const&))
+ BOOST_DELETED_FUNCTION(pthread_mutex_attributes& operator=(pthread_mutex_attributes const&))
+};
+
+//! Pthread condifion variable attributes
+struct pthread_condition_variable_attributes
+{
+ pthread_condattr_t attrs;
+
+ pthread_condition_variable_attributes()
+ {
+ int err = pthread_condattr_init(&this->attrs);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread condition variable attributes", (err));
+ }
+
+ ~pthread_condition_variable_attributes()
+ {
+ BOOST_VERIFY(pthread_condattr_destroy(&this->attrs) == 0);
+ }
+
+ BOOST_DELETED_FUNCTION(pthread_condition_variable_attributes(pthread_condition_variable_attributes const&))
+ BOOST_DELETED_FUNCTION(pthread_condition_variable_attributes& operator=(pthread_condition_variable_attributes const&))
+};
+
+//! Interprocess mutex wrapper
+struct interprocess_mutex
+{
+ struct auto_unlock
+ {
+ explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
+ ~auto_unlock() { m_mutex.unlock(); }
+
+ BOOST_DELETED_FUNCTION(auto_unlock(auto_unlock const&))
+ BOOST_DELETED_FUNCTION(auto_unlock& operator=(auto_unlock const&))
+
+ private:
+ interprocess_mutex& m_mutex;
+ };
+
+ pthread_mutex_t mutex;
+
+ interprocess_mutex()
+ {
+ pthread_mutex_attributes attrs;
+ int err = pthread_mutexattr_settype(&attrs.attrs, PTHREAD_MUTEX_NORMAL);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to set pthread mutex type", (err));
+ err = pthread_mutexattr_setpshared(&attrs.attrs, PTHREAD_PROCESS_SHARED);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread mutex process-shared", (err));
+#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
+ err = pthread_mutexattr_setrobust(&attrs.attrs, PTHREAD_MUTEX_ROBUST);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread mutex robust", (err));
+#endif
+
+ err = pthread_mutex_init(&this->mutex, &attrs.attrs);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread mutex", (err));
+ }
+
+ ~interprocess_mutex()
+ {
+ BOOST_VERIFY(pthread_mutex_destroy(&this->mutex) == 0);
+ }
+
+ void lock()
+ {
+ int err = pthread_mutex_lock(&this->mutex);
+#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
+ if (BOOST_UNLIKELY(err == EOWNERDEAD))
+ throw lock_owner_dead();
+#endif
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to lock pthread mutex", (err));
+ }
+
+ void unlock() BOOST_NOEXCEPT
+ {
+ BOOST_VERIFY(pthread_mutex_unlock(&this->mutex) == 0);
+ }
+
+#if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST)
+ void recover()
+ {
+ int err = pthread_mutex_consistent(&this->mutex);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to recover pthread mutex from a crashed thread", (err));
+ }
+#endif
+
+ BOOST_DELETED_FUNCTION(interprocess_mutex(interprocess_mutex const&))
+ BOOST_DELETED_FUNCTION(interprocess_mutex& operator=(interprocess_mutex const&))
+};
+
+//! Interprocess condition variable wrapper
+struct interprocess_condition_variable
+{
+ pthread_cond_t cond;
+
+ interprocess_condition_variable()
+ {
+ pthread_condition_variable_attributes attrs;
+ int err = pthread_condattr_setpshared(&attrs.attrs, PTHREAD_PROCESS_SHARED);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread condition variable process-shared", (err));
+
+ err = pthread_cond_init(&this->cond, &attrs.attrs);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread condition variable", (err));
+ }
+
+ ~interprocess_condition_variable()
+ {
+ BOOST_VERIFY(pthread_cond_destroy(&this->cond) == 0);
+ }
+
+ void notify_one()
+ {
+ int err = pthread_cond_signal(&this->cond);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to notify one thread on a pthread condition variable", (err));
+ }
+
+ void notify_all()
+ {
+ int err = pthread_cond_broadcast(&this->cond);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to notify all threads on a pthread condition variable", (err));
+ }
+
+ void wait(interprocess_mutex& mutex)
+ {
+ int err = pthread_cond_wait(&this->cond, &mutex.mutex);
+ if (BOOST_UNLIKELY(err != 0))
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to wait on a pthread condition variable", (err));
+ }
+
+ BOOST_DELETED_FUNCTION(interprocess_condition_variable(interprocess_condition_variable const&))
+ BOOST_DELETED_FUNCTION(interprocess_condition_variable& operator=(interprocess_condition_variable const&))
+};
+
+#else // defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+
+// If there are no process-shared pthread primitives, use whatever emulation Boost.Interprocess implements
+struct interprocess_mutex
+{
+ struct auto_unlock
+ {
+ explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
+ ~auto_unlock() { m_mutex.unlock(); }
+
+ BOOST_DELETED_FUNCTION(auto_unlock(auto_unlock const&))
+ BOOST_DELETED_FUNCTION(auto_unlock& operator=(auto_unlock const&))
+
+ private:
+ interprocess_mutex& m_mutex;
+ };
+
+ BOOST_DEFAULTED_FUNCTION(interprocess_mutex(), {})
+
+ // Members to emulate a lock interface
+ typedef boost::interprocess::interprocess_mutex mutex_type;
+
+ BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
+ bool operator! () const BOOST_NOEXCEPT { return false; }
+ mutex_type* mutex() BOOST_NOEXCEPT { return &m_mutex; }
+
+ void lock()
+ {
+ m_mutex.lock();
+ }
+
+ void unlock() BOOST_NOEXCEPT
+ {
+ m_mutex.unlock();
+ }
+
+ mutex_type m_mutex;
+
+ BOOST_DELETED_FUNCTION(interprocess_mutex(interprocess_mutex const&))
+ BOOST_DELETED_FUNCTION(interprocess_mutex& operator=(interprocess_mutex const&))
+};
+
+
+typedef boost::interprocess::interprocess_condition interprocess_condition_variable;
+
+#endif // defined(BOOST_INTERPROCESS_POSIX_PROCESS_SHARED)
+
+} // namespace aux
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_POSIX_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/posix/object_name.cpp b/src/boost/libs/log/src/posix/object_name.cpp
new file mode 100644
index 000000000..d0238341a
--- /dev/null
+++ b/src/boost/libs/log/src/posix/object_name.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file posix/object_name.cpp
+ * \author Andrey Semashev
+ * \date 06.03.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <unistd.h>
+#include <sys/types.h>
+#if defined(__ANDROID__) && (__ANDROID_API__+0) < 21
+#include <sys/syscall.h>
+#endif
+#if !defined(BOOST_LOG_NO_GETPWUID_R)
+#include <pwd.h>
+#endif
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <vector>
+#include <boost/move/utility_core.hpp>
+#include <boost/type_traits/make_unsigned.hpp>
+#include <boost/spirit/include/karma_uint.hpp>
+#include <boost/spirit/include/karma_generate.hpp>
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace karma = boost::spirit::karma;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+#if defined(__ANDROID__) && (__ANDROID_API__+0) < 21
+// Until Android API version 21 NDK does not define getsid wrapper in libc, although there is the corresponding syscall
+inline pid_t getsid(pid_t pid) BOOST_NOEXCEPT
+{
+ return static_cast< pid_t >(::syscall(__NR_getsid, pid));
+}
+#endif
+
+//! Formats an integer identifier into the string
+template< typename Identifier >
+inline void format_id(Identifier id, std::string& str)
+{
+ // Note: in the code below, avoid involving locale for string formatting to make sure the names are as stable as possible
+ typedef typename boost::make_unsigned< Identifier >::type unsigned_id_t;
+ char buf[std::numeric_limits< unsigned_id_t >::digits10 + 2];
+ char* p = buf;
+
+ typedef karma::uint_generator< unsigned_id_t, 10 > unsigned_id_gen;
+ karma::generate(p, unsigned_id_gen(), static_cast< unsigned_id_t >(id));
+ str.append(buf, p);
+}
+
+//! Returns a prefix string for a shared resource according to the scope
+std::string get_scope_prefix(object_name::scope ns)
+{
+ std::string prefix = "/boost.log.";
+ switch (ns)
+ {
+ case object_name::process_group:
+ {
+ prefix.append("pgid.");
+#if !defined(BOOST_LOG_NO_GETPGRP)
+ format_id(getpgrp(), prefix);
+#else
+ format_id(getuid(), prefix);
+#endif
+ }
+ break;
+
+ case object_name::session:
+ {
+ prefix.append("sid.");
+#if !defined(BOOST_LOG_NO_GETSID)
+ format_id(getsid(0), prefix);
+#else
+ format_id(getuid(), prefix);
+#endif
+ }
+ break;
+
+ case object_name::user:
+ {
+ const uid_t uid = getuid();
+
+#if !defined(BOOST_LOG_NO_GETPWUID_R)
+ long limit = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (limit <= 0)
+ limit = 65536;
+ std::vector< char > string_storage;
+ string_storage.resize(static_cast< std::size_t >(limit));
+ passwd pwd = {}, *result = NULL;
+
+ try
+ {
+ const int err = getpwuid_r(uid, &pwd, &string_storage[0], string_storage.size(), &result);
+ if (err == 0 && result && result->pw_name)
+ {
+ prefix += "user.";
+ prefix += result->pw_name;
+ }
+ else
+ {
+ prefix += "uid.";
+ format_id(uid, prefix);
+ }
+
+ // Avoid leaving sensitive data in memory, if there is any
+ std::memset(&pwd, 0, sizeof(pwd));
+ std::memset(&string_storage[0], 0, string_storage.size());
+ }
+ catch (...)
+ {
+ std::memset(&pwd, 0, sizeof(pwd));
+ std::memset(&string_storage[0], 0, string_storage.size());
+ throw;
+ }
+#else
+ prefix += "uid.";
+ format_id(uid, prefix);
+#endif
+ }
+ break;
+
+ default:
+ prefix += "global";
+ break;
+ }
+
+ prefix.push_back('.');
+
+ return BOOST_LOG_NRVO_RESULT(prefix);
+}
+
+} // namespace
+
+//! Constructor from the object name
+BOOST_LOG_API object_name::object_name(scope ns, const char* str) :
+ m_name(get_scope_prefix(ns) + str)
+{
+}
+
+//! Constructor from the object name
+BOOST_LOG_API object_name::object_name(scope ns, std::string const& str) :
+ m_name(get_scope_prefix(ns) + str)
+{
+}
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/process_id.cpp b/src/boost/libs/log/src/process_id.cpp
new file mode 100644
index 000000000..e5dfd77b9
--- /dev/null
+++ b/src/boost/libs/log/src/process_id.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file process_id.cpp
+ * \author Andrey Semashev
+ * \date 12.09.2009
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <iostream>
+#include <boost/log/detail/process_id.hpp>
+#include "id_formatting.hpp"
+
+#if defined(BOOST_WINDOWS)
+
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+enum { pid_size = sizeof(GetCurrentProcessId()) };
+
+namespace this_process {
+
+ //! The function returns current process identifier
+ BOOST_LOG_API process::id get_id()
+ {
+ return process::id(GetCurrentProcessId());
+ }
+
+} // namespace this_process
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#else // defined(BOOST_WINDOWS)
+
+#include <unistd.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+namespace this_process {
+
+ //! The function returns current process identifier
+ BOOST_LOG_API process::id get_id()
+ {
+ // According to POSIX, pid_t should always be an integer type:
+ // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
+ return process::id(getpid());
+ }
+
+} // namespace this_process
+
+enum { pid_size = sizeof(pid_t) };
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS)
+
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+template< typename CharT, typename TraitsT >
+BOOST_LOG_API std::basic_ostream< CharT, TraitsT >&
+operator<< (std::basic_ostream< CharT, TraitsT >& strm, process::id const& pid)
+{
+ if (strm.good())
+ {
+ CharT buf[pid_size * 2 + 3]; // 2 chars per byte + 3 chars for the leading 0x and terminating zero
+ format_id< pid_size >(buf, sizeof(buf) / sizeof(*buf), pid.native_id(), (strm.flags() & std::ios_base::uppercase) != 0);
+
+ strm << buf;
+ }
+
+ return strm;
+}
+
+#if defined(BOOST_LOG_USE_CHAR)
+template BOOST_LOG_API
+std::basic_ostream< char, std::char_traits< char > >&
+operator<< (std::basic_ostream< char, std::char_traits< char > >& strm, process::id const& pid);
+#endif // defined(BOOST_LOG_USE_CHAR)
+
+#if defined(BOOST_LOG_USE_WCHAR_T)
+template BOOST_LOG_API
+std::basic_ostream< wchar_t, std::char_traits< wchar_t > >&
+operator<< (std::basic_ostream< wchar_t, std::char_traits< wchar_t > >& strm, process::id const& pid);
+#endif // defined(BOOST_LOG_USE_WCHAR_T)
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/process_name.cpp b/src/boost/libs/log/src/process_name.cpp
new file mode 100644
index 000000000..864defaca
--- /dev/null
+++ b/src/boost/libs/log/src/process_name.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file process_name.cpp
+ * \author Andrey Semashev
+ * \date 29.07.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ *
+ * The code in this file is based on information on this page:
+ *
+ * http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <climits> // PATH_MAX
+#include <boost/log/attributes/current_process_name.hpp>
+#include <boost/filesystem/path.hpp>
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#if defined(BOOST_WINDOWS)
+
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! The function returns the current process name
+BOOST_LOG_API std::string get_process_name()
+{
+ std::wstring buf;
+ buf.resize(PATH_MAX);
+ do
+ {
+ unsigned int len = GetModuleFileNameW(NULL, &buf[0], static_cast< unsigned int >(buf.size()));
+ if (len < buf.size())
+ {
+ buf.resize(len);
+ break;
+ }
+
+ buf.resize(buf.size() * 2);
+ }
+ while (buf.size() < 65536);
+
+ return filesystem::path(buf).filename().string();
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+
+#include <cstring>
+#include <mach-o/dyld.h>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! The function returns the current process name
+BOOST_LOG_API std::string get_process_name()
+{
+ std::string buf;
+ buf.resize(PATH_MAX);
+ while (true)
+ {
+ uint32_t size = static_cast< uint32_t >(buf.size());
+ if (_NSGetExecutablePath(&buf[0], &size) == 0)
+ {
+ buf.resize(std::strlen(&buf[0]));
+ break;
+ }
+
+ buf.resize(size);
+ }
+
+ return filesystem::path(buf).filename().string();
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#elif defined(__FreeBSD__)
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! The function returns the current process name
+BOOST_LOG_API std::string get_process_name()
+{
+#if defined(KERN_PROC_PATHNAME)
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ char buf[PATH_MAX] = {};
+ size_t cb = sizeof(buf);
+ if (sysctl(mib, 4, buf, &cb, NULL, 0) == 0)
+ return filesystem::path(buf).filename().string();
+#endif
+
+ if (filesystem::exists("/proc/curproc/file"))
+ return filesystem::read_symlink("/proc/curproc/file").filename().string();
+
+ return boost::lexical_cast< std::string >(getpid());
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#else
+
+#include <unistd.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! The function returns the current process name
+BOOST_LOG_API std::string get_process_name()
+{
+ if (filesystem::exists("/proc/self/exe"))
+ return filesystem::read_symlink("/proc/self/exe").filename().string();
+
+ if (filesystem::exists("/proc/curproc/file"))
+ return filesystem::read_symlink("/proc/curproc/file").filename().string();
+
+ if (filesystem::exists("/proc/curproc/exe"))
+ return filesystem::read_symlink("/proc/curproc/exe").filename().string();
+
+ return boost::lexical_cast< std::string >(getpid());
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif
diff --git a/src/boost/libs/log/src/record_ostream.cpp b/src/boost/libs/log/src/record_ostream.cpp
new file mode 100644
index 000000000..27ed3d09b
--- /dev/null
+++ b/src/boost/libs/log/src/record_ostream.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file record_ostream.cpp
+ * \author Andrey Semashev
+ * \date 17.04.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <locale>
+#include <utility>
+#include <boost/log/sources/record_ostream.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/attributes/attribute_value_impl.hpp>
+#include <boost/log/expressions/message.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/tss.hpp>
+#endif
+#include "unique_ptr.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+//! The function initializes the stream and the stream buffer
+template< typename CharT >
+BOOST_LOG_API void basic_record_ostream< CharT >::init_stream()
+{
+ base_type::init_stream();
+ base_type::imbue(std::locale());
+ if (m_record)
+ {
+ typedef attributes::attribute_value_impl< string_type > message_impl_type;
+ intrusive_ptr< message_impl_type > p = new message_impl_type(string_type());
+ attribute_value value(p);
+
+ // This may fail if the record already has Message attribute
+ std::pair< attribute_value_set::const_iterator, bool > res =
+ m_record->attribute_values().insert(expressions::tag::message::get_name(), value);
+ if (!res.second)
+ const_cast< attribute_value& >(res.first->second).swap(value);
+
+ base_type::attach(const_cast< string_type& >(p->get()));
+ }
+}
+//! The function resets the stream into a detached (default initialized) state
+template< typename CharT >
+BOOST_LOG_API void basic_record_ostream< CharT >::detach_from_record() BOOST_NOEXCEPT
+{
+ if (m_record)
+ {
+ base_type::detach();
+ m_record = NULL;
+ base_type::exceptions(base_type::goodbit);
+ }
+}
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! The pool of stream compounds
+template< typename CharT >
+class stream_compound_pool :
+ public log::aux::lazy_singleton<
+ stream_compound_pool< CharT >,
+#if !defined(BOOST_LOG_NO_THREADS)
+ thread_specific_ptr< stream_compound_pool< CharT > >
+#else
+ log::aux::unique_ptr< stream_compound_pool< CharT > >
+#endif
+ >
+{
+ //! Self type
+ typedef stream_compound_pool< CharT > this_type;
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Thread-specific pointer type
+ typedef thread_specific_ptr< this_type > tls_ptr_type;
+#else
+ //! Thread-specific pointer type
+ typedef log::aux::unique_ptr< this_type > tls_ptr_type;
+#endif
+ //! Singleton base type
+ typedef log::aux::lazy_singleton<
+ this_type,
+ tls_ptr_type
+ > base_type;
+ //! Stream compound type
+ typedef typename stream_provider< CharT >::stream_compound stream_compound_t;
+
+public:
+ //! Pooled stream compounds
+ stream_compound_t* m_Top;
+
+ ~stream_compound_pool()
+ {
+ stream_compound_t* p = NULL;
+ while ((p = m_Top) != NULL)
+ {
+ m_Top = p->next;
+ delete p;
+ }
+ }
+
+ //! The method returns pool instance
+ static stream_compound_pool& get()
+ {
+ tls_ptr_type& ptr = base_type::get();
+ this_type* p = ptr.get();
+ if (!p)
+ {
+ log::aux::unique_ptr< this_type > pNew(new this_type());
+ ptr.reset(pNew.get());
+ p = pNew.release();
+ }
+ return *p;
+ }
+
+private:
+ stream_compound_pool() : m_Top(NULL) {}
+};
+
+} // namespace
+
+//! The method returns an allocated stream compound
+template< typename CharT >
+BOOST_LOG_API typename stream_provider< CharT >::stream_compound*
+stream_provider< CharT >::allocate_compound(record& rec)
+{
+ stream_compound_pool< char_type >& pool = stream_compound_pool< char_type >::get();
+ if (pool.m_Top)
+ {
+ stream_compound* p = pool.m_Top;
+ pool.m_Top = p->next;
+ p->next = NULL;
+ p->stream.attach_record(rec);
+ return p;
+ }
+ else
+ return new stream_compound(rec);
+}
+
+//! The method releases a compound
+template< typename CharT >
+BOOST_LOG_API void stream_provider< CharT >::release_compound(stream_compound* compound) BOOST_NOEXCEPT
+{
+ stream_compound_pool< char_type >& pool = stream_compound_pool< char_type >::get();
+ compound->next = pool.m_Top;
+ pool.m_Top = compound;
+ compound->stream.detach_from_record();
+}
+
+//! Explicitly instantiate stream_provider implementation
+#ifdef BOOST_LOG_USE_CHAR
+template struct stream_provider< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template struct stream_provider< wchar_t >;
+#endif
+
+} // namespace aux
+
+//! Explicitly instantiate basic_record_ostream implementation
+#ifdef BOOST_LOG_USE_CHAR
+template class basic_record_ostream< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template class basic_record_ostream< wchar_t >;
+#endif
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/setup/default_filter_factory.cpp b/src/boost/libs/log/src/setup/default_filter_factory.cpp
new file mode 100644
index 000000000..ff9106efc
--- /dev/null
+++ b/src/boost/libs/log/src/setup/default_filter_factory.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_filter_factory.hpp
+ * \author Andrey Semashev
+ * \date 29.05.2010
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/log/detail/setup_config.hpp>
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/preprocessor/seq/enum.hpp>
+#include <boost/spirit/include/qi_core.hpp>
+#include <boost/log/trivial.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/expressions/predicates/has_attr.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/functional/logical.hpp>
+#include <boost/log/utility/functional/begins_with.hpp>
+#include <boost/log/utility/functional/ends_with.hpp>
+#include <boost/log/utility/functional/contains.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/detail/default_attribute_names.hpp>
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+#include <boost/fusion/container/set.hpp>
+#include <boost/fusion/sequence/intrinsic/at_key.hpp>
+#include <boost/fusion/algorithm/iteration/for_each.hpp>
+#endif
+#include "default_filter_factory.hpp"
+#include "parser_utils.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace qi = boost::spirit::qi;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+//! A special filtering predicate that adopts the string operand to the attribute value character type
+template< typename RelationT >
+class string_predicate :
+ public RelationT
+{
+private:
+ template< typename StringT >
+ struct initializer
+ {
+ typedef void result_type;
+
+ explicit initializer(StringT const& val) : m_initializer(val)
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T& val) const
+ {
+ try
+ {
+ log::aux::code_convert(m_initializer, val);
+ }
+ catch (...)
+ {
+ val.clear();
+ }
+ }
+
+ private:
+ StringT const& m_initializer;
+ };
+
+public:
+ typedef RelationT relation_type;
+ typedef typename relation_type::result_type result_type;
+
+ template< typename StringT >
+ string_predicate(relation_type const& rel, StringT const& operand) : relation_type(rel)
+ {
+ fusion::for_each(m_operands, initializer< StringT >(operand));
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ typedef std::basic_string< typename T::value_type > operand_type;
+ return relation_type::operator() (val, fusion::at_key< operand_type >(m_operands));
+ }
+
+private:
+ fusion::set< std::string, std::wstring > m_operands;
+};
+
+#else // defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+//! A special filtering predicate that adopts the string operand to the attribute value character type
+template< typename RelationT >
+class string_predicate :
+ public RelationT
+{
+private:
+#if defined(BOOST_LOG_USE_CHAR)
+ typedef std::basic_string< char > string_type;
+#elif defined(BOOST_LOG_USE_WCHAR_T)
+ typedef std::basic_string< wchar_t > string_type;
+#else
+#error Boost.Log: Inconsistent character configuration
+#endif
+
+public:
+ typedef RelationT relation_type;
+ typedef typename relation_type::result_type result_type;
+
+public:
+ string_predicate(relation_type const& rel, string_type const& operand) : relation_type(rel), m_operand(operand)
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ return relation_type::operator() (val, m_operand);
+ }
+
+private:
+ const string_type m_operand;
+};
+
+#endif // defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+//! A special filtering predicate that adopts the severity level or string operand to the attribute value character type
+template< typename RelationT >
+class severity_or_string_predicate :
+ public string_predicate< RelationT >
+{
+private:
+ typedef string_predicate< RelationT > base_type;
+
+public:
+ typedef typename base_type::relation_type relation_type;
+ typedef typename base_type::result_type result_type;
+
+public:
+ template< typename StringT >
+ severity_or_string_predicate(relation_type const& rel, StringT const& string_operand, boost::log::trivial::severity_level severity_operand) :
+ base_type(rel, string_operand),
+ m_severity_operand(severity_operand)
+ {
+ }
+
+ using base_type::operator();
+
+ result_type operator() (boost::log::trivial::severity_level val) const
+ {
+ return relation_type::operator() (val, m_severity_operand);
+ }
+
+private:
+ const boost::log::trivial::severity_level m_severity_operand;
+};
+
+//! A filtering predicate for numeric relations
+template< typename NumericT, typename RelationT >
+class numeric_predicate :
+ public string_predicate< RelationT >
+{
+ typedef string_predicate< RelationT > base_type;
+
+public:
+ typedef NumericT numeric_type;
+ typedef typename base_type::relation_type relation_type;
+ typedef typename base_type::result_type result_type;
+
+public:
+ template< typename StringT >
+ numeric_predicate(relation_type const& rel, StringT const& string_operand, numeric_type numeric_operand) :
+ base_type(rel, string_operand),
+ m_numeric_operand(numeric_operand)
+ {
+ }
+
+ template< typename CharT, typename TraitsT, typename AllocatorT >
+ result_type operator() (std::basic_string< CharT, TraitsT, AllocatorT > const& val) const
+ {
+ return base_type::operator() (val);
+ }
+
+ template< typename CharT, typename TraitsT >
+ result_type operator() (basic_string_literal< CharT, TraitsT > const& val) const
+ {
+ return base_type::operator() (val);
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ return relation_type::operator() (val, m_numeric_operand);
+ }
+
+private:
+ const numeric_type m_numeric_operand;
+};
+
+typedef mpl::vector<
+ BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_FLOATING_POINT_TYPES()BOOST_LOG_STANDARD_STRING_TYPES())
+> floating_point_and_string_types;
+
+} // namespace
+
+//! The callback for equality relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_equality_relation(attribute_name const& name, string_type const& arg)
+{
+ return parse_argument< equal_to >(name, arg);
+}
+
+//! The callback for inequality relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_inequality_relation(attribute_name const& name, string_type const& arg)
+{
+ return parse_argument< not_equal_to >(name, arg);
+}
+
+//! The callback for less relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_less_relation(attribute_name const& name, string_type const& arg)
+{
+ return parse_argument< less >(name, arg);
+}
+
+//! The callback for greater relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_greater_relation(attribute_name const& name, string_type const& arg)
+{
+ return parse_argument< greater >(name, arg);
+}
+
+//! The callback for less or equal relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_less_or_equal_relation(attribute_name const& name, string_type const& arg)
+{
+ return parse_argument< less_equal >(name, arg);
+}
+
+//! The callback for greater or equal relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_greater_or_equal_relation(attribute_name const& name, string_type const& arg)
+{
+ return parse_argument< greater_equal >(name, arg);
+}
+
+//! The callback for custom relation filter
+template< typename CharT >
+filter default_filter_factory< CharT >::on_custom_relation(attribute_name const& name, string_type const& rel, string_type const& arg)
+{
+ typedef log::aux::char_constants< char_type > constants;
+
+ if (rel == constants::begins_with_keyword())
+ {
+ typedef string_predicate< begins_with_fun > predicate;
+ return predicate_wrapper< log::string_types, predicate >(name, predicate(begins_with_fun(), arg));
+ }
+ else if (rel == constants::ends_with_keyword())
+ {
+ typedef string_predicate< ends_with_fun > predicate;
+ return predicate_wrapper< log::string_types, predicate >(name, predicate(ends_with_fun(), arg));
+ }
+ else if (rel == constants::contains_keyword())
+ {
+ typedef string_predicate< contains_fun > predicate;
+ return predicate_wrapper< log::string_types, predicate >(name, predicate(contains_fun(), arg));
+ }
+ else if (rel != constants::matches_keyword())
+ {
+ BOOST_LOG_THROW_DESCR(parse_error, "The custom attribute relation \"" + log::aux::to_narrow(rel) + "\" is not supported");
+ }
+
+ return parse_matches_relation(name, arg);
+}
+
+
+//! The function parses the argument value for a binary relation and constructs the corresponding filter
+template< typename CharT >
+template< typename RelationT >
+filter default_filter_factory< CharT >::parse_argument(attribute_name const& name, string_type const& arg)
+{
+ const char_type* begin = arg.c_str();
+ const char_type* const end = begin + arg.size();
+
+ double real_val = 0.0;
+ const qi::real_parser< double, qi::strict_real_policies< double > > real_;
+ if (qi::parse(begin, end, real_, real_val) && begin == end)
+ {
+ typedef numeric_predicate< double, RelationT > predicate;
+ typedef floating_point_and_string_types value_types;
+ return predicate_wrapper< value_types, predicate >(name, predicate(RelationT(), arg, real_val));
+ }
+ else
+ {
+ begin = arg.c_str();
+ long int_val = 0;
+ if (qi::parse(begin, end, qi::long_, int_val) && begin == end)
+ {
+ typedef numeric_predicate< long, RelationT > predicate;
+ typedef default_attribute_value_types value_types;
+ return predicate_wrapper< value_types, predicate >(name, predicate(RelationT(), arg, int_val));
+ }
+ else
+ {
+ boost::log::trivial::severity_level lvl;
+ if (name == boost::log::aux::default_attribute_names::severity() && boost::log::trivial::from_string(arg.data(), arg.size(), lvl))
+ {
+ typedef severity_or_string_predicate< RelationT > predicate;
+ typedef mpl::vector< boost::log::trivial::severity_level, BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_STRING_TYPES()) > value_types;
+ return predicate_wrapper< value_types, predicate >(name, predicate(RelationT(), arg, lvl));
+ }
+ else
+ {
+ typedef string_predicate< RelationT > predicate;
+ return predicate_wrapper< log::string_types, predicate >(name, predicate(RelationT(), arg));
+ }
+ }
+ }
+}
+
+// Explicitly instantiate factory implementation
+#ifdef BOOST_LOG_USE_CHAR
+template class default_filter_factory< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template class default_filter_factory< wchar_t >;
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/src/setup/default_filter_factory.hpp b/src/boost/libs/log/src/setup/default_filter_factory.hpp
new file mode 100644
index 000000000..455eb4243
--- /dev/null
+++ b/src/boost/libs/log/src/setup/default_filter_factory.hpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_filter_factory.hpp
+ * \author Andrey Semashev
+ * \date 29.05.2010
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_DEFAULT_FILTER_FACTORY_HPP_INCLUDED_
+#define BOOST_DEFAULT_FILTER_FACTORY_HPP_INCLUDED_
+
+#include <boost/log/detail/setup_config.hpp>
+#include <cstddef>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/setup/filter_parser.hpp>
+#include <boost/log/utility/functional/save_result.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Relation predicate wrapper
+template< typename ValueT, typename PredicateT >
+struct predicate_wrapper
+{
+ typedef typename PredicateT::result_type result_type;
+
+ explicit predicate_wrapper(attribute_name const& name, PredicateT const& pred) : m_name(name), m_visitor(pred)
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T const& arg) const
+ {
+ bool res = false;
+ boost::log::visit< ValueT >(m_name, arg, save_result_wrapper< PredicateT const&, bool >(m_visitor, res));
+ return res;
+ }
+
+private:
+ attribute_name m_name;
+ const PredicateT m_visitor;
+};
+
+//! The default filter factory that supports creating filters for the standard types (see utility/type_dispatch/standard_types.hpp)
+template< typename CharT >
+class default_filter_factory :
+ public filter_factory< CharT >
+{
+private:
+ //! Base type
+ typedef filter_factory< CharT > base_type;
+ //! Self type
+ typedef default_filter_factory< CharT > this_type;
+
+public:
+ // Type imports
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+
+ //! The callback for equality relation filter
+ virtual filter on_equality_relation(attribute_name const& name, string_type const& arg);
+ //! The callback for inequality relation filter
+ virtual filter on_inequality_relation(attribute_name const& name, string_type const& arg);
+ //! The callback for less relation filter
+ virtual filter on_less_relation(attribute_name const& name, string_type const& arg);
+ //! The callback for greater relation filter
+ virtual filter on_greater_relation(attribute_name const& name, string_type const& arg);
+ //! The callback for less or equal relation filter
+ virtual filter on_less_or_equal_relation(attribute_name const& name, string_type const& arg);
+ //! The callback for greater or equal relation filter
+ virtual filter on_greater_or_equal_relation(attribute_name const& name, string_type const& arg);
+
+ //! The callback for custom relation filter
+ virtual filter on_custom_relation(attribute_name const& name, string_type const& rel, string_type const& arg);
+
+private:
+ //! The function parses the argument value for a binary relation and constructs the corresponding filter
+ template< typename RelationT >
+ static filter parse_argument(attribute_name const& name, string_type const& arg);
+};
+
+//! The function parses the "matches" relation
+template< typename CharT >
+filter parse_matches_relation(attribute_name const& name, std::basic_string< CharT > const& operand);
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_DEFAULT_FILTER_FACTORY_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/setup/default_formatter_factory.cpp b/src/boost/libs/log/src/setup/default_formatter_factory.cpp
new file mode 100644
index 000000000..15a0b8384
--- /dev/null
+++ b/src/boost/libs/log/src/setup/default_formatter_factory.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_formatter_factory.cpp
+ * \author Andrey Semashev
+ * \date 14.07.2013
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/log/detail/setup_config.hpp>
+#include <cstddef>
+#include <ctime>
+#include <boost/mpl/vector.hpp>
+#include <boost/mpl/vector/vector40.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/seq/enum.hpp>
+#include <boost/preprocessor/seq/size.hpp>
+#include <boost/date_time/special_defs.hpp>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+#include <boost/date_time/local_time/local_time_types.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/log/trivial.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/type_dispatch/date_time_types.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/detail/snprintf.hpp>
+#include <boost/log/detail/process_id.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/log/detail/thread_id.hpp>
+#endif
+#include <boost/log/attributes/named_scope.hpp>
+#include "default_formatter_factory.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#if !defined(BOOST_LOG_NO_THREADS)
+#define BOOST_LOG_AUX_THREAD_ID_TYPE() (boost::log::aux::thread::id)
+#else
+#define BOOST_LOG_AUX_THREAD_ID_TYPE()
+#endif
+
+#define BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()\
+ (boost::log::trivial::severity_level)\
+ (boost::log::attributes::named_scope_list)\
+ (boost::log::aux::process::id)\
+ BOOST_LOG_AUX_THREAD_ID_TYPE()
+
+// The list of the attribute value types supported by the default formatter. Note that we have to exclude std::time_t
+// as it is an integral type, as well as double from the native time duration types - these are part of arithmetic types already.
+#define BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES()\
+ BOOST_LOG_DEFAULT_ATTRIBUTE_VALUE_TYPES()\
+ (std::tm)\
+ BOOST_LOG_BOOST_DATE_TYPES()\
+ BOOST_LOG_BOOST_TIME_DURATION_TYPES()\
+ BOOST_LOG_BOOST_TIME_PERIOD_TYPES()\
+ BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! The default formatter generated by the default formatter factory
+template< typename CharT >
+class default_formatter
+{
+public:
+ typedef void result_type;
+
+private:
+ //! Attribute value visitor
+ struct visitor
+ {
+ typedef void result_type;
+
+ explicit visitor(basic_formatting_ostream< CharT >& strm) : m_strm(strm)
+ {
+ }
+
+ template< typename T >
+ void operator() (T const& value) const
+ {
+ m_strm << value;
+ }
+
+ void operator() (std::tm const& value) const
+ {
+ char buf[32];
+ std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &value);
+ m_strm.write(buf, len);
+ }
+
+ void operator() (boost::posix_time::ptime const& value) const
+ {
+ if (!value.is_special())
+ {
+ std::tm t = boost::posix_time::to_tm(value);
+ char buf[32];
+ std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
+ std::size_t size = sizeof(buf) - len;
+ int res = boost::log::aux::snprintf(buf + len, size, ".%.6u", static_cast< unsigned int >(value.time_of_day().total_microseconds() % 1000000));
+ if (res < 0)
+ buf[len] = '\0';
+ else if (static_cast< std::size_t >(res) >= size)
+ len += size - 1;
+ else
+ len += res;
+
+ m_strm.write(buf, len);
+ }
+ else
+ {
+ format_special_date_time(value);
+ }
+ }
+
+ void operator() (boost::local_time::local_date_time const& value) const
+ {
+ if (!value.is_special())
+ {
+ this->operator()(value.local_time());
+ m_strm << ' ' << value.zone_as_posix_string();
+ }
+ else
+ {
+ format_special_date_time(value);
+ }
+ }
+
+ void operator() (boost::gregorian::date const& value) const
+ {
+ if (!value.is_special())
+ {
+ std::tm t = boost::gregorian::to_tm(value);
+ char buf[32];
+ std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d", &t);
+ m_strm.write(buf, len);
+ }
+ else
+ {
+ format_special_date_time(value.as_special());
+ }
+ }
+
+ void operator() (boost::posix_time::time_duration const& value) const
+ {
+ if (!value.is_special())
+ {
+ boost::posix_time::time_duration val = value;
+ if (val.is_negative())
+ {
+ m_strm << '-';
+ val = -val;
+ }
+ unsigned long long total_useconds = value.total_microseconds();
+ unsigned long long hours = total_useconds / (3600ull * 1000000ull);
+ unsigned int minutes = static_cast< unsigned int >(total_useconds / (60ull * 1000000ull) % 60ull);
+ unsigned int seconds = static_cast< unsigned int >(total_useconds / 1000000ull % 60ull);
+ unsigned int useconds = static_cast< unsigned int >(total_useconds % 1000000ull);
+ char buf[64];
+ int len = boost::log::aux::snprintf(buf, sizeof(buf), "%.2llu:%.2u:%.2u.%.6u", hours, minutes, seconds, useconds);
+ if (len > 0)
+ {
+ unsigned int size = static_cast< unsigned int >(len) >= sizeof(buf) ? static_cast< unsigned int >(sizeof(buf)) : static_cast< unsigned int >(len);
+ m_strm.write(buf, size);
+ }
+ }
+ else
+ {
+ format_special_date_time(value);
+ }
+ }
+
+ void operator() (boost::gregorian::date_duration const& value) const
+ {
+ if (!value.is_special())
+ {
+ m_strm << value.get_rep().as_number();
+ }
+ else
+ {
+ format_special_date_time(value.get_rep().as_special());
+ }
+ }
+
+ template< typename PointRepT, typename DurationRepT >
+ void operator() (boost::date_time::period< PointRepT, DurationRepT > const& value) const
+ {
+ m_strm << '[';
+ this->operator()(value.begin());
+ m_strm << '/';
+ this->operator()(value.last());
+ m_strm << ']';
+ }
+
+ private:
+ template< typename T >
+ void format_special_date_time(T const& value) const
+ {
+ if (value.is_not_a_date_time())
+ m_strm << "not-a-date-time";
+ else if (value.is_pos_infinity())
+ m_strm << "+infinity";
+ else if (value.is_neg_infinity())
+ m_strm << "-infinity";
+ }
+
+ void format_special_date_time(boost::date_time::special_values value) const
+ {
+ switch (value)
+ {
+ case boost::date_time::not_a_date_time:
+ m_strm << "not-a-date-time";
+ break;
+ case boost::date_time::pos_infin:
+ m_strm << "+infinity";
+ break;
+ case boost::date_time::neg_infin:
+ m_strm << "-infinity";
+ break;
+ default:
+ break;
+ }
+ }
+
+ private:
+ basic_formatting_ostream< CharT >& m_strm;
+ };
+
+public:
+ explicit default_formatter(attribute_name name) : m_attribute_name(name)
+ {
+ }
+
+ result_type operator() (record_view const& rec, basic_formatting_ostream< CharT >& strm) const
+ {
+ typedef BOOST_PP_CAT(mpl::vector, BOOST_PP_SEQ_SIZE(BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES()))<
+ BOOST_PP_SEQ_ENUM(BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES())
+ > value_types;
+
+ boost::log::visit< value_types >(m_attribute_name, rec, visitor(strm));
+ }
+
+private:
+ const attribute_name m_attribute_name;
+};
+
+} // namespace
+
+//! The callback for equality relation filter
+template< typename CharT >
+typename default_formatter_factory< CharT >::formatter_type
+default_formatter_factory< CharT >::create_formatter(attribute_name const& name, args_map const& args)
+{
+ // No user-defined factory, shall use the most generic formatter we can ever imagine at this point
+ return formatter_type(default_formatter< CharT >(name));
+}
+
+// Explicitly instantiate factory implementation
+#ifdef BOOST_LOG_USE_CHAR
+template class default_formatter_factory< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template class default_formatter_factory< wchar_t >;
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/src/setup/default_formatter_factory.hpp b/src/boost/libs/log/src/setup/default_formatter_factory.hpp
new file mode 100644
index 000000000..6359b3be8
--- /dev/null
+++ b/src/boost/libs/log/src/setup/default_formatter_factory.hpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file default_formatter_factory.hpp
+ * \author Andrey Semashev
+ * \date 14.07.2013
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_DEFAULT_FORMATTER_FACTORY_HPP_INCLUDED_
+#define BOOST_DEFAULT_FORMATTER_FACTORY_HPP_INCLUDED_
+
+#include <boost/log/detail/setup_config.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/utility/setup/formatter_parser.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! The default filter factory that supports creating filters for the standard types (see utility/type_dispatch/standard_types.hpp)
+template< typename CharT >
+class default_formatter_factory :
+ public formatter_factory< CharT >
+{
+ //! Base type
+ typedef formatter_factory< CharT > base_type;
+ //! Self type
+ typedef default_formatter_factory< CharT > this_type;
+
+public:
+ // Type imports
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::formatter_type formatter_type;
+ typedef typename base_type::args_map args_map;
+
+ //! The function creates a formatter for the specified attribute.
+ virtual formatter_type create_formatter(attribute_name const& name, args_map const& args);
+};
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_DEFAULT_FORMATTER_FACTORY_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/setup/filter_parser.cpp b/src/boost/libs/log/src/setup/filter_parser.cpp
new file mode 100644
index 000000000..cf41bca02
--- /dev/null
+++ b/src/boost/libs/log/src/setup/filter_parser.cpp
@@ -0,0 +1,531 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filter_parser.cpp
+ * \author Andrey Semashev
+ * \date 31.03.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
+
+#include <boost/log/detail/setup_config.hpp>
+#include <cstddef>
+#include <map>
+#include <stack>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <utility>
+#include <boost/assert.hpp>
+#include <boost/none.hpp>
+#include <boost/move/core.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/phoenix/core.hpp>
+#include <boost/phoenix/bind/bind_function_object.hpp>
+#include <boost/phoenix/operator/logical.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/setup/filter_parser.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/log/detail/locks.hpp>
+#include <boost/log/detail/light_rw_mutex.hpp>
+#endif // !defined(BOOST_LOG_NO_THREADS)
+#include "parser_utils.hpp"
+#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+#include "default_filter_factory.hpp"
+#endif
+#include "spirit_encoding.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! Filter factories repository
+template< typename CharT >
+struct filters_repository :
+ public log::aux::lazy_singleton< filters_repository< CharT > >
+{
+ typedef CharT char_type;
+ typedef log::aux::lazy_singleton< filters_repository< char_type > > base_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef filter_factory< char_type > filter_factory_type;
+
+ //! Attribute name ordering predicate
+ struct attribute_name_order
+ {
+ typedef bool result_type;
+ result_type operator() (attribute_name const& left, attribute_name const& right) const
+ {
+ return left.id() < right.id();
+ }
+ };
+
+ typedef std::map< attribute_name, shared_ptr< filter_factory_type >, attribute_name_order > factories_map;
+
+#if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
+ friend class log::aux::lazy_singleton< filters_repository< char_type > >;
+#else
+ friend class base_type;
+#endif
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex
+ mutable log::aux::light_rw_mutex m_Mutex;
+#endif
+ //! The map of filter factories
+ factories_map m_Map;
+#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+ //! Default factory
+ mutable aux::default_filter_factory< char_type > m_DefaultFactory;
+#endif
+
+ //! The method returns the filter factory for the specified attribute name
+ filter_factory_type& get_factory(attribute_name const& name) const
+ {
+ typename factories_map::const_iterator it = m_Map.find(name);
+ if (it != m_Map.end())
+ {
+ return *it->second;
+ }
+ else
+ {
+#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+ return m_DefaultFactory;
+#else
+ BOOST_LOG_THROW_DESCR(setup_error, "No filter factory registered for attribute " + name.string());
+#endif
+ }
+ }
+
+private:
+ filters_repository()
+ {
+ }
+};
+
+//! Filter parser
+template< typename CharT >
+class filter_parser
+{
+private:
+ typedef CharT char_type;
+ typedef const char_type* iterator_type;
+ typedef typename log::aux::encoding< char_type >::type encoding;
+ typedef log::aux::encoding_specific< encoding > encoding_specific;
+ typedef std::basic_string< char_type > string_type;
+ typedef log::aux::char_constants< char_type > constants;
+ typedef filter_factory< char_type > filter_factory_type;
+
+ typedef filter (filter_factory_type::*comparison_relation_handler_t)(attribute_name const&, string_type const&);
+
+private:
+ //! Parsed attribute name
+ mutable attribute_name m_AttributeName;
+ //! The second operand of a relation
+ mutable optional< string_type > m_Operand;
+ //! Comparison relation handler
+ comparison_relation_handler_t m_ComparisonRelation;
+ //! The custom relation string
+ mutable string_type m_CustomRelation;
+
+ //! Filter subexpressions as they are parsed
+ mutable std::stack< filter > m_Subexpressions;
+
+public:
+ //! Constructor
+ filter_parser() :
+ m_ComparisonRelation(NULL)
+ {
+ }
+
+ //! The method returns the constructed filter
+ filter get_filter()
+ {
+ if (m_Subexpressions.empty())
+ return filter();
+ return boost::move(m_Subexpressions.top());
+ }
+
+ //! The pethod parses filter from the string
+ void parse(iterator_type& begin, iterator_type end, unsigned int depth = 0)
+ {
+ typedef void (filter_parser::*logical_op_t)();
+ logical_op_t logical_op = NULL;
+ iterator_type p = constants::trim_spaces_left(begin, end);
+ while (p != end)
+ {
+ // Parse subexpression
+ parse_subexpression(p, end, depth);
+ if (logical_op)
+ {
+ // This was the right-hand subexpression. Compose the two top subexpressions into a single filter.
+ (this->*logical_op)();
+ logical_op = NULL;
+ }
+
+ p = constants::trim_spaces_left(p, end);
+ if (p != end)
+ {
+ char_type c = *p;
+ iterator_type next = p + 1;
+ if (c == constants::char_paren_bracket_right)
+ {
+ // The subexpression has ended
+ if (depth == 0)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unmatched closing parenthesis");
+
+ p = next;
+ --depth;
+ break;
+ }
+ else if (c == constants::char_and || scan_keyword(p, end, next, constants::and_keyword()))
+ {
+ logical_op = &filter_parser::on_and;
+ }
+ else if (c == constants::char_or || scan_keyword(p, end, next, constants::or_keyword()))
+ {
+ logical_op = &filter_parser::on_or;
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unexpected character encountered");
+ }
+
+ p = constants::trim_spaces_left(next, end);
+ }
+ else
+ break;
+ }
+
+ if (logical_op)
+ {
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: logical operation without the right-hand subexpression");
+ }
+
+ if (p == end && depth > 0)
+ {
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unterminated parenthesis");
+ }
+
+ begin = p;
+ }
+
+private:
+ //! The method parses a single subexpression
+ void parse_subexpression(iterator_type& begin, iterator_type end, unsigned int depth)
+ {
+ bool negated = false, negation_present = false, done = false;
+ iterator_type p = begin;
+
+ while (p != end)
+ {
+ char_type c = *p;
+ iterator_type next = p + 1;
+ if (c == constants::char_percent)
+ {
+ // We found an attribute placeholder
+ iterator_type start = constants::trim_spaces_left(next, end);
+ p = constants::scan_attr_placeholder(start, end);
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the filter string");
+
+ on_attribute_name(start, p);
+
+ p = constants::trim_spaces_left(p, end);
+ if (p == end || *p != constants::char_percent)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the filter string");
+
+ // Skip the closing char_percent
+ p = constants::trim_spaces_left(++p, end);
+
+ // If the filter has negation operator, do not expect a relation (i.e. "!%attr% > 1" is not valid because "!%attr%" is interpreted as an attribute presence test)
+ if (!negation_present)
+ p = parse_relation(p, end);
+ else
+ on_relation_complete();
+ }
+ else if (c == constants::char_exclamation || scan_keyword(p, end, next, constants::not_keyword()))
+ {
+ // We found negation operation. Parse the subexpression to be negated.
+ negated ^= true;
+ negation_present = true;
+ p = constants::trim_spaces_left(next, end);
+ continue;
+ }
+ else if (c == constants::char_paren_bracket_left)
+ {
+ // We found a nested subexpression
+ parse(next, end, depth + 1);
+ p = next;
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unexpected character");
+ }
+
+ if (negated)
+ on_negation();
+
+ done = true;
+
+ break;
+ }
+
+ if (negation_present && !done)
+ {
+ // This would happen if a filter consists of a single '!'
+ BOOST_LOG_THROW_DESCR(parse_error, "Filter parsing error: negation operator applied to nothingness");
+ }
+
+ begin = p;
+ }
+
+ //! Parses filtering relation
+ iterator_type parse_relation(iterator_type begin, iterator_type end)
+ {
+ iterator_type p = begin;
+ if (p != end)
+ {
+ iterator_type next = p;
+ if (scan_keyword(p, end, next, constants::equal_keyword()))
+ m_ComparisonRelation = &filter_factory_type::on_equality_relation;
+ else if (scan_keyword(p, end, next, constants::not_equal_keyword()))
+ m_ComparisonRelation = &filter_factory_type::on_inequality_relation;
+ else if (scan_keyword(p, end, next, constants::greater_keyword()))
+ m_ComparisonRelation = &filter_factory_type::on_greater_relation;
+ else if (scan_keyword(p, end, next, constants::less_keyword()))
+ m_ComparisonRelation = &filter_factory_type::on_less_relation;
+ else if (scan_keyword(p, end, next, constants::greater_or_equal_keyword()))
+ m_ComparisonRelation = &filter_factory_type::on_greater_or_equal_relation;
+ else if (scan_keyword(p, end, next, constants::less_or_equal_keyword()))
+ m_ComparisonRelation = &filter_factory_type::on_less_or_equal_relation;
+ else
+ {
+ // Check for custom relation
+ while (next != end && (encoding::isalnum(*next) || *next == constants::char_underline))
+ ++next;
+ if (p == next)
+ goto DoneL;
+ m_CustomRelation.assign(p, next);
+ }
+
+ // We have parsed a relation operator, there must be an operand
+ next = constants::trim_spaces_left(next, end);
+ string_type operand;
+ p = constants::parse_operand(next, end, operand);
+ if (next == p)
+ BOOST_LOG_THROW_DESCR(parse_error, "Missing operand for a relation in the filter string");
+
+ m_Operand = boost::in_place(operand);
+ }
+
+ DoneL:
+ // The relation can be as simple as a sole attribute placeholder (which means that only attribute presence has to be checked).
+ // So regardless how we get here, the relation is parsed completely.
+ on_relation_complete();
+
+ return p;
+ }
+
+ //! Checks if the string contains a keyword
+ static bool scan_keyword(iterator_type begin, iterator_type end, iterator_type& next, iterator_type keyword)
+ {
+ for (iterator_type p = begin; p != end; ++p, ++keyword)
+ {
+ char_type c1 = *p, c2 = *keyword;
+ if (c2 == 0)
+ {
+ if (encoding::isspace(c1))
+ {
+ next = p;
+ return true;
+ }
+ break;
+ }
+ if (c1 != c2)
+ break;
+ }
+
+ return false;
+ }
+
+ //! The attribute name handler
+ void on_attribute_name(iterator_type begin, iterator_type end)
+ {
+ if (begin == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Empty attribute name encountered");
+ m_AttributeName = attribute_name(log::aux::to_narrow(string_type(begin, end)));
+ }
+
+ //! The comparison relation handler
+ void on_relation_complete()
+ {
+ if (!!m_AttributeName)
+ {
+ filters_repository< char_type > const& repo = filters_repository< char_type >::get();
+ filter_factory_type& factory = repo.get_factory(m_AttributeName);
+
+ if (!!m_Operand)
+ {
+ if (!!m_ComparisonRelation)
+ {
+ m_Subexpressions.push((factory.*m_ComparisonRelation)(m_AttributeName, m_Operand.get()));
+ m_ComparisonRelation = NULL;
+ }
+ else if (!m_CustomRelation.empty())
+ {
+ m_Subexpressions.push(factory.on_custom_relation(m_AttributeName, m_CustomRelation, m_Operand.get()));
+ m_CustomRelation.clear();
+ }
+ else
+ {
+ // This should never happen
+ BOOST_ASSERT_MSG(false, "Filter parser internal error: the attribute name or subexpression operation is not set while trying to construct a relation");
+ BOOST_LOG_THROW_DESCR(parse_error, "Filter parser internal error: the attribute name or subexpression operation is not set while trying to construct a subexpression");
+ }
+
+ m_Operand = none;
+ }
+ else
+ {
+ // This branch is taken if the relation is a single attribute name, which is recognized as the attribute presence check
+ BOOST_ASSERT_MSG(!m_ComparisonRelation && m_CustomRelation.empty(), "Filter parser internal error: the relation operation is set while operand is not");
+ m_Subexpressions.push(factory.on_exists_test(m_AttributeName));
+ }
+
+ m_AttributeName = attribute_name();
+ }
+ else
+ {
+ // This should never happen
+ BOOST_ASSERT_MSG(false, "Filter parser internal error: the attribute name is not set while trying to construct a relation");
+ BOOST_LOG_THROW_DESCR(parse_error, "Filter parser internal error: the attribute name is not set while trying to construct a relation");
+ }
+ }
+
+ //! The negation operation handler
+ void on_negation()
+ {
+ if (!m_Subexpressions.empty())
+ {
+ m_Subexpressions.top() = !phoenix::bind(m_Subexpressions.top(), phoenix::placeholders::_1);
+ }
+ else
+ {
+ // This would happen if a filter consists of "!()"
+ BOOST_LOG_THROW_DESCR(parse_error, "Filter parsing error: negation operator applied to an empty subexpression");
+ }
+ }
+
+ //! The logical AND operation handler
+ void on_and()
+ {
+ if (!m_Subexpressions.empty())
+ {
+ filter right = boost::move(m_Subexpressions.top());
+ m_Subexpressions.pop();
+ if (!m_Subexpressions.empty())
+ {
+ filter const& left = m_Subexpressions.top();
+ m_Subexpressions.top() = phoenix::bind(left, phoenix::placeholders::_1) && phoenix::bind(right, phoenix::placeholders::_1);
+ return;
+ }
+ }
+
+ // This should never happen
+ BOOST_LOG_THROW_DESCR(parse_error, "Filter parser internal error: the subexpression is not set while trying to construct a filter");
+ }
+
+ //! The logical OR operation handler
+ void on_or()
+ {
+ if (!m_Subexpressions.empty())
+ {
+ filter right = boost::move(m_Subexpressions.top());
+ m_Subexpressions.pop();
+ if (!m_Subexpressions.empty())
+ {
+ filter const& left = m_Subexpressions.top();
+ m_Subexpressions.top() = phoenix::bind(left, phoenix::placeholders::_1) || phoenix::bind(right, phoenix::placeholders::_1);
+ return;
+ }
+ }
+
+ // This should never happen
+ BOOST_LOG_THROW_DESCR(parse_error, "Filter parser internal error: the subexpression is not set while trying to construct a filter");
+ }
+
+ // Assignment and copying are prohibited
+ BOOST_DELETED_FUNCTION(filter_parser(filter_parser const&))
+ BOOST_DELETED_FUNCTION(filter_parser& operator= (filter_parser const&))
+};
+
+} // namespace
+
+//! The function registers a filter factory object for the specified attribute name
+template< typename CharT >
+BOOST_LOG_SETUP_API void register_filter_factory(attribute_name const& name, shared_ptr< filter_factory< CharT > > const& factory)
+{
+ BOOST_ASSERT(!!name);
+ BOOST_ASSERT(!!factory);
+
+ filters_repository< CharT >& repo = filters_repository< CharT >::get();
+
+ BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
+ repo.m_Map[name] = factory;
+}
+
+//! The function parses a filter from the string
+template< typename CharT >
+BOOST_LOG_SETUP_API filter parse_filter(const CharT* begin, const CharT* end)
+{
+ typedef CharT char_type;
+
+ filter_parser< char_type > parser;
+ const char_type* p = begin;
+
+ BOOST_LOG_EXPR_IF_MT(filters_repository< CharT >& repo = filters_repository< CharT >::get();)
+ BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
+
+ parser.parse(p, end);
+
+ return parser.get_filter();
+}
+
+#ifdef BOOST_LOG_USE_CHAR
+
+template BOOST_LOG_SETUP_API
+void register_filter_factory< char >(attribute_name const& name, shared_ptr< filter_factory< char > > const& factory);
+template BOOST_LOG_SETUP_API
+filter parse_filter< char >(const char* begin, const char* end);
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+template BOOST_LOG_SETUP_API
+void register_filter_factory< wchar_t >(attribute_name const& name, shared_ptr< filter_factory< wchar_t > > const& factory);
+template BOOST_LOG_SETUP_API
+filter parse_filter< wchar_t >(const wchar_t* begin, const wchar_t* end);
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
diff --git a/src/boost/libs/log/src/setup/formatter_parser.cpp b/src/boost/libs/log/src/setup/formatter_parser.cpp
new file mode 100644
index 000000000..597b6ca7b
--- /dev/null
+++ b/src/boost/libs/log/src/setup/formatter_parser.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file formatter_parser.cpp
+ * \author Andrey Semashev
+ * \date 07.04.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
+
+#include <boost/log/detail/setup_config.hpp>
+#include <map>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <boost/assert.hpp>
+#include <boost/move/core.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/utility/in_place_factory.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/detail/default_attribute_names.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/functional/nop.hpp>
+#include <boost/log/utility/setup/formatter_parser.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/log/detail/locks.hpp>
+#include <boost/log/detail/light_rw_mutex.hpp>
+#endif
+#include "parser_utils.hpp"
+#include "spirit_encoding.hpp"
+#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+#include "default_formatter_factory.hpp"
+#endif
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! The structure contains formatter factories repository
+template< typename CharT >
+struct formatters_repository :
+ public log::aux::lazy_singleton< formatters_repository< CharT > >
+{
+ //! Base class type
+ typedef log::aux::lazy_singleton< formatters_repository< CharT > > base_type;
+
+#if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
+ friend class log::aux::lazy_singleton< formatters_repository< CharT > >;
+#else
+ friend class base_type;
+#endif
+
+ typedef CharT char_type;
+ typedef formatter_factory< char_type > formatter_factory_type;
+
+ //! Attribute name ordering predicate
+ struct attribute_name_order
+ {
+ typedef bool result_type;
+ result_type operator() (attribute_name const& left, attribute_name const& right) const
+ {
+ return left.id() < right.id();
+ }
+ };
+
+ //! Map of formatter factories
+ typedef std::map< attribute_name, shared_ptr< formatter_factory_type >, attribute_name_order > factories_map;
+
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex
+ mutable log::aux::light_rw_mutex m_Mutex;
+#endif
+ //! The map of formatter factories
+ factories_map m_Map;
+#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+ //! Default factory
+ mutable aux::default_formatter_factory< char_type > m_DefaultFactory;
+#endif
+
+ //! The method returns the filter factory for the specified attribute name
+ formatter_factory_type& get_factory(attribute_name const& name) const
+ {
+ typename factories_map::const_iterator it = m_Map.find(name);
+ if (it != m_Map.end())
+ {
+ return *it->second;
+ }
+ else
+ {
+#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+ return m_DefaultFactory;
+#else
+ BOOST_LOG_THROW_DESCR(setup_error, "No formatter factory registered for attribute " + name.string());
+#endif
+ }
+ }
+
+private:
+ formatters_repository()
+ {
+ }
+};
+
+//! Function object for formatter chaining
+template< typename CharT, typename SecondT >
+struct chained_formatter
+{
+ typedef void result_type;
+ typedef basic_formatter< CharT > formatter_type;
+ typedef typename formatter_type::stream_type stream_type;
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ explicit chained_formatter(formatter_type&& first, SecondT&& second) :
+#else
+ template< typename T >
+ explicit chained_formatter(BOOST_RV_REF(formatter_type) first, T const& second) :
+#endif
+ m_first(boost::move(first)), m_second(boost::move(second))
+ {
+ }
+
+ result_type operator() (record_view const& rec, stream_type& strm) const
+ {
+ m_first(rec, strm);
+ m_second(rec, strm);
+ }
+
+private:
+ formatter_type m_first;
+ SecondT m_second;
+};
+
+//! String literal formatter
+template< typename CharT >
+struct literal_formatter
+{
+ typedef void result_type;
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef basic_formatting_ostream< char_type > stream_type;
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ explicit literal_formatter(string_type&& str) : m_str(boost::move(str))
+#else
+ explicit literal_formatter(string_type const& str) : m_str(str)
+#endif
+ {
+ }
+
+ result_type operator() (record_view const& rec, stream_type& strm) const
+ {
+ strm << m_str;
+ }
+
+private:
+ const string_type m_str;
+};
+
+//! Formatter parsing grammar
+template< typename CharT >
+class formatter_parser
+{
+private:
+ typedef CharT char_type;
+ typedef const char_type* iterator_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef basic_formatter< char_type > formatter_type;
+ typedef boost::log::aux::char_constants< char_type > constants;
+ typedef typename log::aux::encoding< char_type >::type encoding;
+ typedef log::aux::encoding_specific< encoding > encoding_specific;
+ typedef formatter_factory< char_type > formatter_factory_type;
+ typedef typename formatter_factory_type::args_map args_map;
+
+private:
+ //! The formatter being constructed
+ optional< formatter_type > m_Formatter;
+
+ //! Attribute name
+ attribute_name m_AttrName;
+ //! Formatter factory arguments
+ args_map m_FactoryArgs;
+
+ //! Formatter argument name
+ mutable string_type m_ArgName;
+ //! Argument value
+ mutable string_type m_ArgValue;
+
+public:
+ //! Constructor
+ formatter_parser()
+ {
+ }
+
+ //! Parses formatter
+ void parse(iterator_type& begin, iterator_type end)
+ {
+ iterator_type p = begin;
+
+ while (p != end)
+ {
+ // Find the end of a string literal
+ iterator_type start = p;
+ for (; p != end; ++p)
+ {
+ char_type c = *p;
+ if (c == constants::char_backslash)
+ {
+ // We found an escaped character
+ ++p;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the formatter string");
+ }
+ else if (c == constants::char_percent)
+ {
+ // We found an attribute
+ break;
+ }
+ }
+
+ if (start != p)
+ push_string(start, p);
+
+ if (p != end)
+ {
+ // We found an attribute placeholder
+ iterator_type start = constants::trim_spaces_left(++p, end);
+ p = constants::scan_attr_placeholder(start, end);
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
+
+ on_attribute_name(start, p);
+
+ p = constants::trim_spaces_left(p, end);
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
+
+ if (*p == constants::char_paren_bracket_left)
+ {
+ // We found formatter arguments
+ p = parse_args(constants::trim_spaces_left(++p, end), end);
+ p = constants::trim_spaces_left(p, end);
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
+ }
+
+ if (*p != constants::char_percent)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
+
+ ++p;
+
+ push_attr();
+ }
+ }
+
+ begin = p;
+ }
+
+ //! Returns the parsed formatter
+ formatter_type get_formatter()
+ {
+ if (!m_Formatter)
+ {
+ // This may happen if parser input is an empty string
+ return formatter_type(nop());
+ }
+
+ return boost::move(m_Formatter.get());
+ }
+
+private:
+ //! The method parses formatter arguments
+ iterator_type parse_args(iterator_type begin, iterator_type end)
+ {
+ iterator_type p = begin;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
+ if (*p == constants::char_paren_bracket_right)
+ return ++p;
+
+ while (true)
+ {
+ char_type c = *p;
+
+ // Read argument name
+ iterator_type start = p;
+ if (!encoding::isalpha(*p))
+ BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
+ for (++p; p != end; ++p)
+ {
+ c = *p;
+ if (encoding::isspace(c) || c == constants::char_equal)
+ break;
+ if (!encoding::isalnum(c) && c != constants::char_underline)
+ BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
+ }
+
+ if (start == p)
+ BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is empty");
+
+ on_arg_name(start, p);
+
+ p = constants::trim_spaces_left(p, end);
+ if (p == end || *p != constants::char_equal)
+ BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument description is not valid");
+
+ // Read argument value
+ start = p = constants::trim_spaces_left(++p, end);
+ p = constants::parse_operand(p, end, m_ArgValue);
+ if (p == start)
+ BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument value is not specified");
+
+ push_arg();
+
+ p = constants::trim_spaces_left(p, end);
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
+
+ c = *p;
+ if (c == constants::char_paren_bracket_right)
+ {
+ break;
+ }
+ else if (c == constants::char_comma)
+ {
+ p = constants::trim_spaces_left(++p, end);
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
+ }
+ }
+
+ return ++p;
+ }
+
+ //! The method is called when an argument name is discovered
+ void on_arg_name(iterator_type begin, iterator_type end)
+ {
+ m_ArgName.assign(begin, end);
+ }
+
+ //! The method is called when an argument is filled
+ void push_arg()
+ {
+ m_FactoryArgs[m_ArgName] = m_ArgValue;
+ m_ArgName.clear();
+ m_ArgValue.clear();
+ }
+
+ //! The method is called when an attribute name is discovered
+ void on_attribute_name(iterator_type begin, iterator_type end)
+ {
+ if (begin == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Empty attribute name encountered");
+
+ // For compatibility with Boost.Log v1 we recognize %_% as the message attribute name
+ const std::size_t len = end - begin;
+ if (std::char_traits< char_type >::length(constants::message_text_keyword()) == len &&
+ std::char_traits< char_type >::compare(constants::message_text_keyword(), begin, len) == 0)
+ {
+ m_AttrName = log::aux::default_attribute_names::message();
+ }
+ else
+ {
+ m_AttrName = attribute_name(log::aux::to_narrow(string_type(begin, end)));
+ }
+ }
+ //! The method is called when an attribute is filled
+ void push_attr()
+ {
+ BOOST_ASSERT_MSG(!!m_AttrName, "Attribute name is not set");
+
+ if (m_AttrName == log::aux::default_attribute_names::message())
+ {
+ // We make a special treatment for the message text formatter
+ append_formatter(expressions::aux::message_formatter());
+ }
+ else
+ {
+ // Use the factory to create the formatter
+ formatters_repository< char_type > const& repo = formatters_repository< char_type >::get();
+ formatter_factory_type& factory = repo.get_factory(m_AttrName);
+ append_formatter(factory.create_formatter(m_AttrName, m_FactoryArgs));
+ }
+
+ // Eventually, clear all the auxiliary data
+ m_AttrName = attribute_name();
+ m_FactoryArgs.clear();
+ }
+
+ //! The method is called when a string literal is discovered
+ void push_string(iterator_type begin, iterator_type end)
+ {
+ string_type s(begin, end);
+ constants::translate_escape_sequences(s);
+ append_formatter(literal_formatter< char_type >(boost::move(s)));
+ }
+
+ //! The method appends a formatter part to the final formatter
+ template< typename FormatterT >
+ void append_formatter(FormatterT fmt)
+ {
+ if (!!m_Formatter)
+ m_Formatter = boost::in_place(chained_formatter< char_type, FormatterT >(boost::move(m_Formatter.get()), boost::move(fmt)));
+ else
+ m_Formatter = boost::in_place(boost::move(fmt));
+ }
+
+ // Assignment and copying are prohibited
+ BOOST_DELETED_FUNCTION(formatter_parser(formatter_parser const&))
+ BOOST_DELETED_FUNCTION(formatter_parser& operator= (formatter_parser const&))
+};
+
+} // namespace
+
+//! The function registers a user-defined formatter factory
+template< typename CharT >
+BOOST_LOG_SETUP_API void register_formatter_factory(attribute_name const& name, shared_ptr< formatter_factory< CharT > > const& factory)
+{
+ BOOST_ASSERT(!!name);
+ BOOST_ASSERT(!!factory);
+
+ formatters_repository< CharT >& repo = formatters_repository< CharT >::get();
+ BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
+ repo.m_Map[name] = factory;
+}
+
+//! The function parses a formatter from the string
+template< typename CharT >
+BOOST_LOG_SETUP_API basic_formatter< CharT > parse_formatter(const CharT* begin, const CharT* end)
+{
+ typedef CharT char_type;
+
+ formatter_parser< char_type > parser;
+ const char_type* p = begin;
+
+ BOOST_LOG_EXPR_IF_MT(formatters_repository< CharT >& repo = formatters_repository< CharT >::get();)
+ BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
+
+ parser.parse(p, end);
+
+ return parser.get_formatter();
+}
+
+#ifdef BOOST_LOG_USE_CHAR
+template BOOST_LOG_SETUP_API
+void register_formatter_factory< char >(
+ attribute_name const& attr_name, shared_ptr< formatter_factory< char > > const& factory);
+template BOOST_LOG_SETUP_API
+basic_formatter< char > parse_formatter< char >(const char* begin, const char* end);
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template BOOST_LOG_SETUP_API
+void register_formatter_factory< wchar_t >(
+ attribute_name const& attr_name, shared_ptr< formatter_factory< wchar_t > > const& factory);
+template BOOST_LOG_SETUP_API
+basic_formatter< wchar_t > parse_formatter< wchar_t >(const wchar_t* begin, const wchar_t* end);
+#endif // BOOST_LOG_USE_WCHAR_T
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
diff --git a/src/boost/libs/log/src/setup/init_from_settings.cpp b/src/boost/libs/log/src/setup/init_from_settings.cpp
new file mode 100644
index 000000000..7b5b6285a
--- /dev/null
+++ b/src/boost/libs/log/src/setup/init_from_settings.cpp
@@ -0,0 +1,887 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file init_from_settings.cpp
+ * \author Andrey Semashev
+ * \date 11.10.2009
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
+
+#if defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \
+ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 407
+// This warning is caused by a compiler bug which is exposed when boost::optional is used: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679
+// It has to be disabled here, before any code is included, since otherwise it doesn't help and the warning is still emitted.
+// '*((void*)& foo +2)' may be used uninitialized in this function
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
+#include <boost/log/detail/setup_config.hpp>
+#include <cstddef>
+#include <ios>
+#include <map>
+#include <vector>
+#include <string>
+#include <utility>
+#include <iostream>
+#include <typeinfo>
+#include <stdexcept>
+#include <algorithm>
+#include <boost/type.hpp>
+#include <boost/limits.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/core/null_deleter.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/date_time/date_defs.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/type_traits/conditional.hpp>
+#include <boost/type_traits/is_unsigned.hpp>
+#include <boost/type_traits/integral_constant.hpp>
+#include <boost/spirit/home/qi/numeric/numeric_utils.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/detail/default_attribute_names.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/sinks/auto_newline_mode.hpp>
+#include <boost/log/sinks/frontend_requirements.hpp>
+#include <boost/log/expressions/filter.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/functional/nop.hpp>
+#include <boost/log/utility/setup/from_settings.hpp>
+#include <boost/log/utility/setup/filter_parser.hpp>
+#include <boost/log/utility/setup/formatter_parser.hpp>
+#if !defined(BOOST_LOG_NO_ASIO)
+#include <boost/asio/ip/address.hpp>
+#endif
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/log/detail/locks.hpp>
+#include <boost/log/detail/light_rw_mutex.hpp>
+#endif
+#include "parser_utils.hpp"
+#include "spirit_encoding.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace qi = boost::spirit::qi;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! Throws an exception when a parameter value is not valid
+BOOST_LOG_NORETURN void throw_invalid_value(const char* param_name)
+{
+ std::string descr = std::string("Invalid parameter \"")
+ + param_name
+ + "\" value";
+ BOOST_LOG_THROW_DESCR(invalid_value, descr);
+}
+
+//! Extracts an integral value from parameter value
+template< typename IntT, typename CharT >
+inline IntT param_cast_to_int(const char* param_name, std::basic_string< CharT > const& value)
+{
+ IntT res = 0;
+ typedef typename conditional<
+ is_unsigned< IntT >::value,
+ qi::extract_uint< IntT, 10, 1, -1 >,
+ qi::extract_int< IntT, 10, 1, -1 >
+ >::type extract;
+ const CharT* begin = value.c_str(), *end = begin + value.size();
+ if (extract::call(begin, end, res) && begin == end)
+ return res;
+ else
+ throw_invalid_value(param_name);
+}
+
+//! Case-insensitive character comparison predicate
+struct is_case_insensitive_equal
+{
+ typedef bool result_type;
+
+ template< typename CharT >
+ result_type operator() (CharT left, CharT right) const BOOST_NOEXCEPT
+ {
+ typedef typename boost::log::aux::encoding< CharT >::type encoding;
+ return encoding::tolower(left) == encoding::tolower(right);
+ }
+};
+
+//! Extracts a boolean value from parameter value
+template< typename CharT >
+inline bool param_cast_to_bool(const char* param_name, std::basic_string< CharT > const& value)
+{
+ typedef CharT char_type;
+ typedef boost::log::aux::char_constants< char_type > constants;
+ typedef boost::log::basic_string_literal< char_type > literal_type;
+
+ const char_type* begin = value.c_str(), *end = begin + value.size();
+ std::size_t len = end - begin;
+
+ literal_type keyword = constants::true_keyword();
+ if (keyword.size() == len && std::equal(begin, end, keyword.c_str(), is_case_insensitive_equal()))
+ {
+ return true;
+ }
+ else
+ {
+ keyword = constants::false_keyword();
+ if (keyword.size() == len && std::equal(begin, end, keyword.c_str(), is_case_insensitive_equal()))
+ {
+ return false;
+ }
+ else
+ {
+ return param_cast_to_int< unsigned int >(param_name, value) != 0;
+ }
+ }
+}
+
+//! Extracts an \c auto_newline_mode value from parameter value
+template< typename CharT >
+inline sinks::auto_newline_mode param_cast_to_auto_newline_mode(const char* param_name, std::basic_string< CharT > const& value)
+{
+ typedef CharT char_type;
+ typedef boost::log::aux::char_constants< char_type > constants;
+
+ if (value == constants::auto_newline_mode_disabled())
+ return sinks::disabled_auto_newline;
+ else if (value == constants::auto_newline_mode_always_insert())
+ return sinks::always_insert;
+ else if (value == constants::auto_newline_mode_insert_if_missing())
+ return sinks::insert_if_missing;
+ else
+ {
+ BOOST_LOG_THROW_DESCR(invalid_value,
+ "Auto newline mode \"" + boost::log::aux::to_narrow(value) + "\" is not supported");
+ }
+}
+
+#if !defined(BOOST_LOG_NO_ASIO)
+//! Extracts a network address from parameter value
+template< typename CharT >
+inline std::string param_cast_to_address(const char* param_name, std::basic_string< CharT > const& value)
+{
+ return log::aux::to_narrow(value);
+}
+#endif // !defined(BOOST_LOG_NO_ASIO)
+
+template< typename CharT >
+inline bool is_weekday(const CharT* str, std::size_t len, boost::log::basic_string_literal< CharT > const& weekday, boost::log::basic_string_literal< CharT > const& short_weekday)
+{
+ return (len == weekday.size() && std::equal(weekday.begin(), weekday.end(), str)) ||
+ (len == short_weekday.size() && std::equal(short_weekday.begin(), short_weekday.end(), str));
+}
+
+//! The function extracts the file rotation time point predicate from the parameter
+template< typename CharT >
+sinks::file::rotation_at_time_point param_cast_to_rotation_time_point(const char* param_name, std::basic_string< CharT > const& value)
+{
+ typedef CharT char_type;
+ typedef boost::log::aux::char_constants< char_type > constants;
+ typedef typename boost::log::aux::encoding< char_type >::type encoding;
+ typedef qi::extract_uint< unsigned short, 10, 1, 2 > day_extract;
+ typedef qi::extract_uint< unsigned char, 10, 2, 2 > time_component_extract;
+
+ const char_type colon = static_cast< char_type >(':');
+ optional< date_time::weekdays > weekday;
+ optional< unsigned short > day;
+ unsigned char hour = 0, minute = 0, second = 0;
+ const char_type* begin = value.c_str(), *end = begin + value.size();
+
+ if (!encoding::isalnum(*begin)) // begin is null-terminated, so we also check that the string is not empty here
+ throw_invalid_value(param_name);
+
+ const char_type* p = begin + 1;
+ if (encoding::isalpha(*begin))
+ {
+ // This must be a weekday
+ while (encoding::isalpha(*p))
+ ++p;
+
+ std::size_t len = p - begin;
+ if (is_weekday(begin, len, constants::monday_keyword(), constants::short_monday_keyword()))
+ weekday = date_time::Monday;
+ else if (is_weekday(begin, len, constants::tuesday_keyword(), constants::short_tuesday_keyword()))
+ weekday = date_time::Tuesday;
+ else if (is_weekday(begin, len, constants::wednesday_keyword(), constants::short_wednesday_keyword()))
+ weekday = date_time::Wednesday;
+ else if (is_weekday(begin, len, constants::thursday_keyword(), constants::short_thursday_keyword()))
+ weekday = date_time::Thursday;
+ else if (is_weekday(begin, len, constants::friday_keyword(), constants::short_friday_keyword()))
+ weekday = date_time::Friday;
+ else if (is_weekday(begin, len, constants::saturday_keyword(), constants::short_saturday_keyword()))
+ weekday = date_time::Saturday;
+ else if (is_weekday(begin, len, constants::sunday_keyword(), constants::short_sunday_keyword()))
+ weekday = date_time::Sunday;
+ else
+ throw_invalid_value(param_name);
+ }
+ else
+ {
+ // This may be either a month day or an hour
+ while (encoding::isdigit(*p))
+ ++p;
+
+ if (encoding::isspace(*p))
+ {
+ // This is a month day
+ unsigned short mday = 0;
+ const char_type* b = begin;
+ if (!day_extract::call(b, p, mday) || b != p)
+ throw_invalid_value(param_name);
+
+ day = mday;
+ }
+ else if (*p == colon)
+ {
+ // This is an hour, reset the pointer
+ p = begin;
+ }
+ else
+ throw_invalid_value(param_name);
+ }
+
+ // Skip spaces
+ while (encoding::isspace(*p))
+ ++p;
+
+ // Parse hour
+ if (!time_component_extract::call(p, end, hour) || *p != colon)
+ throw_invalid_value(param_name);
+ ++p;
+
+ // Parse minute
+ if (!time_component_extract::call(p, end, minute) || *p != colon)
+ throw_invalid_value(param_name);
+ ++p;
+
+ // Parse second
+ if (!time_component_extract::call(p, end, second) || p != end)
+ throw_invalid_value(param_name);
+
+ // Construct the predicate
+ if (weekday)
+ return sinks::file::rotation_at_time_point(weekday.get(), hour, minute, second);
+ else if (day)
+ return sinks::file::rotation_at_time_point(gregorian::greg_day(day.get()), hour, minute, second);
+ else
+ return sinks::file::rotation_at_time_point(hour, minute, second);
+}
+
+//! Base class for default sink factories
+template< typename CharT >
+class basic_default_sink_factory :
+ public sink_factory< CharT >
+{
+public:
+ typedef sink_factory< CharT > base_type;
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::settings_section settings_section;
+ typedef boost::log::aux::char_constants< char_type > constants;
+
+protected:
+ //! Sink backend character selection function
+ template< typename InitializerT >
+ static shared_ptr< sinks::sink > select_backend_character_type(settings_section const& params, InitializerT initializer)
+ {
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+ if (optional< string_type > wide_param = params["Wide"])
+ {
+ if (param_cast_to_bool("Wide", wide_param.get()))
+ return initializer(params, type< wchar_t >());
+ }
+
+ return initializer(params, type< char >());
+#elif defined(BOOST_LOG_USE_CHAR)
+ return initializer(params, type< char >());
+#elif defined(BOOST_LOG_USE_WCHAR_T)
+ return initializer(params, type< wchar_t >());
+#endif
+ }
+
+ //! The function initializes common parameters of a formatting sink and returns the constructed sink
+ template< typename BackendT >
+ static shared_ptr< sinks::sink > init_sink(shared_ptr< BackendT > const& backend, settings_section const& params)
+ {
+ typedef BackendT backend_t;
+ typedef typename sinks::has_requirement<
+ typename backend_t::frontend_requirements,
+ sinks::formatted_records
+ >::type is_formatting_t;
+
+ // Filter
+ filter filt;
+ if (optional< string_type > filter_param = params["Filter"])
+ {
+ filt = parse_filter(filter_param.get());
+ }
+
+ shared_ptr< sinks::basic_sink_frontend > p;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ // Asynchronous. TODO: make it more flexible.
+ bool async = false;
+ if (optional< string_type > async_param = params["Asynchronous"])
+ {
+ async = param_cast_to_bool("Asynchronous", async_param.get());
+ }
+
+ // Construct the frontend, considering Asynchronous parameter
+ if (!async)
+ {
+ p = init_formatter(boost::make_shared< sinks::synchronous_sink< backend_t > >(backend), params, is_formatting_t());
+ }
+ else
+ {
+ p = init_formatter(boost::make_shared< sinks::asynchronous_sink< backend_t > >(backend), params, is_formatting_t());
+
+ // https://svn.boost.org/trac/boost/ticket/10638
+ // The user doesn't have a way to process excaptions from the dedicated thread anyway, so just suppress them instead of
+ // terminating the application.
+ p->set_exception_handler(nop());
+ }
+#else
+ // When multithreading is disabled we always use the unlocked sink frontend
+ p = init_formatter(boost::make_shared< sinks::unlocked_sink< backend_t > >(backend), params, is_formatting_t());
+#endif
+
+ p->set_filter(filt);
+
+ return p;
+ }
+
+private:
+ //! The function initializes formatter for the sinks that support formatting
+ template< typename SinkT >
+ static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, true_type)
+ {
+ // Formatter
+ if (optional< string_type > format_param = params["Format"])
+ {
+ typedef typename SinkT::char_type sink_char_type;
+ std::basic_string< sink_char_type > format_str;
+ log::aux::code_convert(format_param.get(), format_str);
+ sink->set_formatter(parse_formatter(format_str));
+ }
+ return sink;
+ }
+ template< typename SinkT >
+ static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, false_type)
+ {
+ return sink;
+ }
+};
+
+//! Default console sink factory
+template< typename CharT >
+class default_console_sink_factory :
+ public basic_default_sink_factory< CharT >
+{
+public:
+ typedef basic_default_sink_factory< CharT > base_type;
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::settings_section settings_section;
+ typedef typename base_type::constants constants;
+
+private:
+ struct impl;
+ friend struct impl;
+ struct impl
+ {
+ typedef shared_ptr< sinks::sink > result_type;
+
+ template< typename BackendCharT >
+ result_type operator() (settings_section const& params, type< BackendCharT >) const
+ {
+ // Construct the backend
+ typedef boost::log::aux::char_constants< BackendCharT > constants;
+ typedef sinks::basic_text_ostream_backend< BackendCharT > backend_t;
+ shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
+ backend->add_stream(shared_ptr< typename backend_t::stream_type >(&constants::get_console_log_stream(), boost::null_deleter()));
+
+ // Auto newline mode
+ if (optional< string_type > auto_newline_param = params["AutoNewline"])
+ {
+ backend->set_auto_newline_mode(param_cast_to_auto_newline_mode("AutoNewline", auto_newline_param.get()));
+ }
+
+ // Auto flush
+ if (optional< string_type > auto_flush_param = params["AutoFlush"])
+ {
+ backend->auto_flush(param_cast_to_bool("AutoFlush", auto_flush_param.get()));
+ }
+
+ return base_type::init_sink(backend, params);
+ }
+ };
+
+public:
+ //! The function constructs a sink that writes log records to the console
+ shared_ptr< sinks::sink > create_sink(settings_section const& params)
+ {
+ return base_type::select_backend_character_type(params, impl());
+ }
+};
+
+//! Default text file sink factory
+template< typename CharT >
+class default_text_file_sink_factory :
+ public basic_default_sink_factory< CharT >
+{
+public:
+ typedef basic_default_sink_factory< CharT > base_type;
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::settings_section settings_section;
+ typedef typename base_type::constants constants;
+
+public:
+ //! The function constructs a sink that writes log records to a text file
+ shared_ptr< sinks::sink > create_sink(settings_section const& params)
+ {
+ typedef sinks::text_file_backend backend_t;
+ shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
+
+ // FileName
+ if (optional< string_type > file_name_param = params["FileName"])
+ {
+ backend->set_file_name_pattern(filesystem::path(file_name_param.get()));
+ }
+ else
+ BOOST_LOG_THROW_DESCR(missing_value, "File name is not specified");
+
+ // Target file name
+ if (optional< string_type > target_file_name_param = params["TargetFileName"])
+ {
+ backend->set_target_file_name_pattern(filesystem::path(target_file_name_param.get()));
+ }
+
+ // File rotation size
+ if (optional< string_type > rotation_size_param = params["RotationSize"])
+ {
+ backend->set_rotation_size(param_cast_to_int< uintmax_t >("RotationSize", rotation_size_param.get()));
+ }
+
+ // File rotation interval
+ if (optional< string_type > rotation_interval_param = params["RotationInterval"])
+ {
+ backend->set_time_based_rotation(sinks::file::rotation_at_time_interval(
+ posix_time::seconds(param_cast_to_int< unsigned int >("RotationInterval", rotation_interval_param.get()))));
+ }
+ else if (optional< string_type > rotation_time_point_param = params["RotationTimePoint"])
+ {
+ // File rotation time point
+ backend->set_time_based_rotation(param_cast_to_rotation_time_point("RotationTimePoint", rotation_time_point_param.get()));
+ }
+
+ // Final rotation
+ if (optional< string_type > enable_final_rotation_param = params["EnableFinalRotation"])
+ {
+ backend->enable_final_rotation(param_cast_to_bool("EnableFinalRotation", enable_final_rotation_param.get()));
+ }
+
+ // Auto newline mode
+ if (optional< string_type > auto_newline_param = params["AutoNewline"])
+ {
+ backend->set_auto_newline_mode(param_cast_to_auto_newline_mode("AutoNewline", auto_newline_param.get()));
+ }
+
+ // Auto flush
+ if (optional< string_type > auto_flush_param = params["AutoFlush"])
+ {
+ backend->auto_flush(param_cast_to_bool("AutoFlush", auto_flush_param.get()));
+ }
+
+ // Append
+ if (optional< string_type > append_param = params["Append"])
+ {
+ if (param_cast_to_bool("Append", append_param.get()))
+ backend->set_open_mode(std::ios_base::out | std::ios_base::app);
+ }
+
+ // File collector parameters
+ // Target directory
+ if (optional< string_type > target_param = params["Target"])
+ {
+ filesystem::path target_dir(target_param.get());
+
+ // Max total size
+ uintmax_t max_size = (std::numeric_limits< uintmax_t >::max)();
+ if (optional< string_type > max_size_param = params["MaxSize"])
+ max_size = param_cast_to_int< uintmax_t >("MaxSize", max_size_param.get());
+
+ // Min free space
+ uintmax_t space = 0;
+ if (optional< string_type > min_space_param = params["MinFreeSpace"])
+ space = param_cast_to_int< uintmax_t >("MinFreeSpace", min_space_param.get());
+
+ // Max number of files
+ uintmax_t max_files = (std::numeric_limits< uintmax_t >::max)();
+ if (optional< string_type > max_files_param = params["MaxFiles"])
+ max_files = param_cast_to_int< uintmax_t >("MaxFiles", max_files_param.get());
+
+ backend->set_file_collector(sinks::file::make_collector(
+ keywords::target = target_dir,
+ keywords::max_size = max_size,
+ keywords::min_free_space = space,
+ keywords::max_files = max_files));
+
+ // Scan for log files
+ if (optional< string_type > scan_param = params["ScanForFiles"])
+ {
+ string_type const& value = scan_param.get();
+ if (value == constants::scan_method_all())
+ backend->scan_for_files(sinks::file::scan_all);
+ else if (value == constants::scan_method_matching())
+ backend->scan_for_files(sinks::file::scan_matching);
+ else
+ {
+ BOOST_LOG_THROW_DESCR(invalid_value,
+ "File scan method \"" + boost::log::aux::to_narrow(value) + "\" is not supported");
+ }
+ }
+ }
+
+ return base_type::init_sink(backend, params);
+ }
+};
+
+#ifndef BOOST_LOG_WITHOUT_SYSLOG
+
+//! Default syslog sink factory
+template< typename CharT >
+class default_syslog_sink_factory :
+ public basic_default_sink_factory< CharT >
+{
+public:
+ typedef basic_default_sink_factory< CharT > base_type;
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::settings_section settings_section;
+ typedef typename base_type::constants constants;
+
+public:
+ //! The function constructs a sink that writes log records to syslog
+ shared_ptr< sinks::sink > create_sink(settings_section const& params)
+ {
+ // Construct the backend
+ typedef sinks::syslog_backend backend_t;
+ shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
+
+ // For now we use only the default level mapping. Will add support for configuration later.
+ backend->set_severity_mapper(sinks::syslog::direct_severity_mapping< >(log::aux::default_attribute_names::severity()));
+
+#if !defined(BOOST_LOG_NO_ASIO)
+ // Setup local and remote addresses
+ if (optional< string_type > local_address_param = params["LocalAddress"])
+ backend->set_local_address(param_cast_to_address("LocalAddress", local_address_param.get()));
+
+ if (optional< string_type > target_address_param = params["TargetAddress"])
+ backend->set_target_address(param_cast_to_address("TargetAddress", target_address_param.get()));
+#endif // !defined(BOOST_LOG_NO_ASIO)
+
+ return base_type::init_sink(backend, params);
+ }
+};
+
+#endif // !defined(BOOST_LOG_WITHOUT_SYSLOG)
+
+#ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT
+
+//! Default debugger sink factory
+template< typename CharT >
+class default_debugger_sink_factory :
+ public basic_default_sink_factory< CharT >
+{
+public:
+ typedef basic_default_sink_factory< CharT > base_type;
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::settings_section settings_section;
+ typedef typename base_type::constants constants;
+
+private:
+ struct impl;
+ friend struct impl;
+ struct impl
+ {
+ typedef shared_ptr< sinks::sink > result_type;
+
+ template< typename BackendCharT >
+ result_type operator() (settings_section const& params, type< BackendCharT >) const
+ {
+ // Construct the backend
+ typedef sinks::basic_debug_output_backend< BackendCharT > backend_t;
+ shared_ptr< backend_t > backend = boost::make_shared< backend_t >();
+
+ return base_type::init_sink(backend, params);
+ }
+ };
+
+public:
+ //! The function constructs a sink that writes log records to the debugger
+ shared_ptr< sinks::sink > create_sink(settings_section const& params)
+ {
+ return base_type::select_backend_character_type(params, impl());
+ }
+};
+
+#endif // !defined(BOOST_LOG_WITHOUT_DEBUG_OUTPUT)
+
+#ifndef BOOST_LOG_WITHOUT_EVENT_LOG
+
+//! Default simple event log sink factory
+template< typename CharT >
+class default_simple_event_log_sink_factory :
+ public basic_default_sink_factory< CharT >
+{
+public:
+ typedef basic_default_sink_factory< CharT > base_type;
+ typedef typename base_type::char_type char_type;
+ typedef typename base_type::string_type string_type;
+ typedef typename base_type::settings_section settings_section;
+ typedef typename base_type::constants constants;
+
+private:
+ struct impl;
+ friend struct impl;
+ struct impl
+ {
+ typedef shared_ptr< sinks::sink > result_type;
+
+ template< typename BackendCharT >
+ result_type operator() (settings_section const& params, type< BackendCharT >) const
+ {
+ typedef sinks::basic_simple_event_log_backend< BackendCharT > backend_t;
+ typedef typename backend_t::string_type backend_string_type;
+
+ // Determine the log name
+ backend_string_type log_name;
+ if (optional< string_type > log_name_param = params["LogName"])
+ log::aux::code_convert(log_name_param.get(), log_name);
+ else
+ log_name = backend_t::get_default_log_name();
+
+ // Determine the log source name
+ backend_string_type source_name;
+ if (optional< string_type > log_source_param = params["LogSource"])
+ log::aux::code_convert(log_source_param.get(), source_name);
+ else
+ source_name = backend_t::get_default_source_name();
+
+ // Determine the registration mode
+ sinks::event_log::registration_mode reg_mode = sinks::event_log::on_demand;
+ if (optional< string_type > registration_param = params["Registration"])
+ {
+ string_type const& value = registration_param.get();
+ if (value == constants::registration_never())
+ reg_mode = sinks::event_log::never;
+ else if (value == constants::registration_on_demand())
+ reg_mode = sinks::event_log::on_demand;
+ else if (value == constants::registration_forced())
+ reg_mode = sinks::event_log::forced;
+ else
+ {
+ BOOST_LOG_THROW_DESCR(invalid_value,
+ "The registration mode \"" + log::aux::to_narrow(value) + "\" is not supported");
+ }
+ }
+
+ // Construct the backend
+ shared_ptr< backend_t > backend(boost::make_shared< backend_t >((
+ keywords::log_name = log_name,
+ keywords::log_source = source_name,
+ keywords::registration = reg_mode)));
+
+ // For now we use only the default event type mapping. Will add support for configuration later.
+ backend->set_event_type_mapper(sinks::event_log::direct_event_type_mapping< >(log::aux::default_attribute_names::severity()));
+
+ return base_type::init_sink(backend, params);
+ }
+ };
+
+public:
+ //! The function constructs a sink that writes log records to the Windows NT Event Log
+ shared_ptr< sinks::sink > create_sink(settings_section const& params)
+ {
+ return base_type::select_backend_character_type(params, impl());
+ }
+};
+
+#endif // !defined(BOOST_LOG_WITHOUT_EVENT_LOG)
+
+
+//! The supported sinks repository
+template< typename CharT >
+struct sinks_repository :
+ public log::aux::lazy_singleton< sinks_repository< CharT > >
+{
+ typedef log::aux::lazy_singleton< sinks_repository< CharT > > base_type;
+
+#if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
+ friend class log::aux::lazy_singleton< sinks_repository< CharT > >;
+#else
+ friend class base_type;
+#endif
+
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef basic_settings_section< char_type > settings_section;
+ typedef boost::log::aux::char_constants< char_type > constants;
+ typedef boost::shared_ptr< sink_factory< char_type > > sink_factory_ptr;
+ typedef std::map< std::string, sink_factory_ptr > sink_factories;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex
+ log::aux::light_rw_mutex m_Mutex;
+#endif
+ //! Map of the sink factories
+ sink_factories m_Factories;
+
+ //! The function constructs a sink from the settings
+ shared_ptr< sinks::sink > construct_sink_from_settings(settings_section const& params)
+ {
+ typedef typename settings_section::const_reference param_const_reference;
+ if (param_const_reference dest_node = params["Destination"])
+ {
+ std::string dest = log::aux::to_narrow(dest_node.get().get());
+
+ BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(m_Mutex);)
+ typename sink_factories::const_iterator it = m_Factories.find(dest);
+ if (it != m_Factories.end())
+ {
+ return it->second->create_sink(params);
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR(invalid_value, "The sink destination is not supported: " + dest);
+ }
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR(missing_value, "The sink destination is not set");
+ }
+ }
+
+ static void init_instance()
+ {
+ sinks_repository& instance = base_type::get_instance();
+ instance.m_Factories["TextFile"] = boost::make_shared< default_text_file_sink_factory< char_type > >();
+ instance.m_Factories["Console"] = boost::make_shared< default_console_sink_factory< char_type > >();
+#ifndef BOOST_LOG_WITHOUT_SYSLOG
+ instance.m_Factories["Syslog"] = boost::make_shared< default_syslog_sink_factory< char_type > >();
+#endif
+#ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT
+ instance.m_Factories["Debugger"] = boost::make_shared< default_debugger_sink_factory< char_type > >();
+#endif
+#ifndef BOOST_LOG_WITHOUT_EVENT_LOG
+ instance.m_Factories["SimpleEventLog"] = boost::make_shared< default_simple_event_log_sink_factory< char_type > >();
+#endif
+ }
+
+private:
+ sinks_repository() {}
+};
+
+//! The function applies the settings to the logging core
+template< typename CharT >
+void apply_core_settings(basic_settings_section< CharT > const& params)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+
+ core_ptr core = boost::log::core::get();
+
+ // Filter
+ if (optional< string_type > filter_param = params["Filter"])
+ core->set_filter(parse_filter(filter_param.get()));
+ else
+ core->reset_filter();
+
+ // DisableLogging
+ if (optional< string_type > disable_logging_param = params["DisableLogging"])
+ core->set_logging_enabled(!param_cast_to_bool("DisableLogging", disable_logging_param.get()));
+ else
+ core->set_logging_enabled(true);
+}
+
+} // namespace
+
+
+//! The function initializes the logging library from a settings container
+template< typename CharT >
+BOOST_LOG_SETUP_API void init_from_settings(basic_settings_section< CharT > const& setts)
+{
+ typedef basic_settings_section< CharT > section;
+ typedef typename section::char_type char_type;
+ typedef sinks_repository< char_type > sinks_repo_t;
+
+ // Apply core settings
+ if (section core_params = setts["Core"])
+ apply_core_settings(core_params);
+
+ // Construct and initialize sinks
+ if (section sink_params = setts["Sinks"])
+ {
+ sinks_repo_t& sinks_repo = sinks_repo_t::get();
+ std::vector< shared_ptr< sinks::sink > > new_sinks;
+
+ for (typename section::const_iterator it = sink_params.begin(), end = sink_params.end(); it != end; ++it)
+ {
+ section sink_params = *it;
+
+ // Ignore empty sections as they are most likely individual parameters (which should not be here anyway)
+ if (!sink_params.empty())
+ {
+ new_sinks.push_back(sinks_repo.construct_sink_from_settings(sink_params));
+ }
+ }
+
+ std::for_each(new_sinks.begin(), new_sinks.end(), boost::bind(&core::add_sink, core::get(), boost::placeholders::_1));
+ }
+}
+
+
+//! The function registers a factory for a sink
+template< typename CharT >
+BOOST_LOG_SETUP_API void register_sink_factory(const char* sink_name, shared_ptr< sink_factory< CharT > > const& factory)
+{
+ sinks_repository< CharT >& repo = sinks_repository< CharT >::get();
+ BOOST_LOG_EXPR_IF_MT(lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
+ repo.m_Factories[sink_name] = factory;
+}
+
+#ifdef BOOST_LOG_USE_CHAR
+template BOOST_LOG_SETUP_API void register_sink_factory< char >(const char* sink_name, shared_ptr< sink_factory< char > > const& factory);
+template BOOST_LOG_SETUP_API void init_from_settings< char >(basic_settings_section< char > const& setts);
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template BOOST_LOG_SETUP_API void register_sink_factory< wchar_t >(const char* sink_name, shared_ptr< sink_factory< wchar_t > > const& factory);
+template BOOST_LOG_SETUP_API void init_from_settings< wchar_t >(basic_settings_section< wchar_t > const& setts);
+#endif
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
diff --git a/src/boost/libs/log/src/setup/init_from_stream.cpp b/src/boost/libs/log/src/setup/init_from_stream.cpp
new file mode 100644
index 000000000..1bf518b75
--- /dev/null
+++ b/src/boost/libs/log/src/setup/init_from_stream.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file init_from_stream.cpp
+ * \author Andrey Semashev
+ * \date 22.03.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
+
+#include <boost/log/detail/setup_config.hpp>
+#include <boost/log/utility/setup/from_settings.hpp>
+#include <boost/log/utility/setup/settings_parser.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+//! The function initializes the logging library from a stream containing logging settings
+template< typename CharT >
+BOOST_LOG_SETUP_API void init_from_stream(std::basic_istream< CharT >& strm)
+{
+ init_from_settings(parse_settings(strm));
+}
+
+#ifdef BOOST_LOG_USE_CHAR
+template BOOST_LOG_SETUP_API void init_from_stream< char >(std::basic_istream< char >& strm);
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template BOOST_LOG_SETUP_API void init_from_stream< wchar_t >(std::basic_istream< wchar_t >& strm);
+#endif
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
diff --git a/src/boost/libs/log/src/setup/matches_relation_factory.cpp b/src/boost/libs/log/src/setup/matches_relation_factory.cpp
new file mode 100644
index 000000000..ba8abe269
--- /dev/null
+++ b/src/boost/libs/log/src/setup/matches_relation_factory.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file matches_relation_factory.hpp
+ * \author Andrey Semashev
+ * \date 03.08.2013
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/log/detail/setup_config.hpp>
+
+#if defined(BOOST_LOG_USE_STD_REGEX) && defined(BOOST_NO_CXX11_HDR_REGEX)
+#error "Boost.Log: Cannot use std::regex because it is not supported by the standard library."
+#endif
+
+#if !defined(BOOST_LOG_USE_BOOST_REGEX) && !defined(BOOST_LOG_USE_STD_REGEX) && !defined(BOOST_LOG_USE_BOOST_XPRESSIVE)
+// Use Boost.Regex backend by default. It produces smaller executables and also has the best performance for small string matching.
+// Note: This default has to be in sync with Boost.Log Jamfile.v2.
+#define BOOST_LOG_USE_BOOST_REGEX
+#endif
+
+#include <string>
+#if defined(BOOST_LOG_USE_STD_REGEX)
+#include <regex>
+#include <boost/log/support/std_regex.hpp>
+#elif defined(BOOST_LOG_USE_BOOST_REGEX)
+#include <boost/regex.hpp>
+#include <boost/log/support/regex.hpp>
+#else
+#include <boost/xpressive/xpressive_dynamic.hpp>
+#include <boost/log/support/xpressive.hpp>
+#endif
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/functional/matches.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+#include <boost/fusion/container/set.hpp>
+#include <boost/fusion/sequence/intrinsic/at_key.hpp>
+#include <boost/fusion/algorithm/iteration/for_each.hpp>
+#endif
+#include "default_filter_factory.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+#if defined(BOOST_LOG_USE_STD_REGEX) || defined(BOOST_LOG_USE_BOOST_REGEX)
+
+#if defined(BOOST_LOG_USE_STD_REGEX)
+namespace regex_namespace = std;
+#else
+namespace regex_namespace = boost;
+#endif
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+//! A special filtering predicate that adopts the string operand to the attribute value character type
+struct matches_predicate :
+ public matches_fun
+{
+ template< typename CharT >
+ struct initializer
+ {
+ typedef void result_type;
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+
+ explicit initializer(string_type const& val) : m_initializer(val)
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T& val) const
+ {
+ try
+ {
+ typedef typename T::value_type target_char_type;
+ std::basic_string< target_char_type > str;
+ log::aux::code_convert(m_initializer, str);
+ val.assign(str, T::ECMAScript | T::optimize);
+ }
+ catch (...)
+ {
+ }
+ }
+
+ private:
+ string_type const& m_initializer;
+ };
+
+ typedef matches_fun::result_type result_type;
+
+ template< typename CharT >
+ explicit matches_predicate(std::basic_string< CharT > const& operand)
+ {
+ fusion::for_each(m_operands, initializer< CharT >(operand));
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ typedef typename T::value_type char_type;
+ typedef regex_namespace::basic_regex< char_type > regex_type;
+ return matches_fun::operator() (val, fusion::at_key< regex_type >(m_operands));
+ }
+
+private:
+ fusion::set< regex_namespace::regex, regex_namespace::wregex > m_operands;
+};
+
+#else
+
+//! A special filtering predicate that adopts the string operand to the attribute value character type
+template< typename CharT >
+struct matches_predicate :
+ public matches_fun
+{
+ typedef typename matches_fun::result_type result_type;
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef regex_namespace::basic_regex< char_type > regex_type;
+
+ explicit matches_predicate(string_type const& operand) :
+ m_operand(operand, regex_type::ECMAScript | regex_type::optimize)
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ return matches_fun::operator() (val, m_operand);
+ }
+
+private:
+ regex_type m_operand;
+};
+
+#endif
+
+#else // defined(BOOST_LOG_USE_STD_REGEX) || defined(BOOST_LOG_USE_BOOST_REGEX)
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+//! A special filtering predicate that adopts the string operand to the attribute value character type
+struct matches_predicate :
+ public matches_fun
+{
+ template< typename CharT >
+ struct initializer
+ {
+ typedef void result_type;
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+
+ explicit initializer(string_type const& val) : m_initializer(val)
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T& val) const
+ {
+ try
+ {
+ typedef typename T::char_type target_char_type;
+ std::basic_string< target_char_type > str;
+ log::aux::code_convert(m_initializer, str);
+ val = T::compile(str.c_str(), str.size(), T::ECMAScript | T::optimize);
+ }
+ catch (...)
+ {
+ }
+ }
+
+ private:
+ string_type const& m_initializer;
+ };
+
+ typedef matches_fun::result_type result_type;
+
+ template< typename CharT >
+ explicit matches_predicate(std::basic_string< CharT > const& operand)
+ {
+ fusion::for_each(m_operands, initializer< CharT >(operand));
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ typedef typename T::value_type char_type;
+ typedef xpressive::basic_regex< const char_type* > regex_type;
+ return matches_fun::operator() (val, fusion::at_key< regex_type >(m_operands));
+ }
+
+private:
+ fusion::set< xpressive::cregex, xpressive::wcregex > m_operands;
+};
+
+#else
+
+//! A special filtering predicate that adopts the string operand to the attribute value character type
+template< typename CharT >
+struct matches_predicate :
+ public matches_fun
+{
+ typedef typename matches_fun::result_type result_type;
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef xpressive::basic_regex< const char_type* > regex_type;
+
+ explicit matches_predicate(string_type const& operand) :
+ m_operand(regex_type::compile(operand.c_str(), operand.size(), regex_type::ECMAScript | regex_type::optimize))
+ {
+ }
+
+ template< typename T >
+ result_type operator() (T const& val) const
+ {
+ return matches_fun::operator() (val, m_operand);
+ }
+
+private:
+ regex_type m_operand;
+};
+
+#endif
+
+#endif // defined(BOOST_LOG_USE_STD_REGEX) || defined(BOOST_LOG_USE_BOOST_REGEX)
+
+} // namespace
+
+//! The function parses the "matches" relation
+template< typename CharT >
+filter parse_matches_relation(attribute_name const& name, std::basic_string< CharT > const& operand)
+{
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+ return predicate_wrapper< log::string_types::type, matches_predicate >(name, matches_predicate(operand));
+#else
+ return predicate_wrapper< std::basic_string< CharT >, matches_predicate< CharT > >(name, matches_predicate< CharT >(operand));
+#endif
+}
+
+// Explicitly instantiate factory implementation
+#ifdef BOOST_LOG_USE_CHAR
+template
+filter parse_matches_relation< char >(attribute_name const& name, std::basic_string< char > const& operand);
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template
+filter parse_matches_relation< wchar_t >(attribute_name const& name, std::basic_string< wchar_t > const& operand);
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/src/setup/parser_utils.cpp b/src/boost/libs/log/src/setup/parser_utils.cpp
new file mode 100644
index 000000000..08a5de8b0
--- /dev/null
+++ b/src/boost/libs/log/src/setup/parser_utils.cpp
@@ -0,0 +1,431 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file parser_utils.cpp
+ * \author Andrey Semashev
+ * \date 31.03.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
+
+#include <boost/log/detail/setup_config.hpp>
+#include <cctype>
+#include <iterator>
+#include <algorithm>
+#include <boost/log/exceptions.hpp>
+#include "parser_utils.hpp"
+#include <boost/log/detail/header.hpp>
+#ifdef BOOST_LOG_USE_WCHAR_T
+#include <cwctype>
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#ifdef BOOST_LOG_USE_CHAR
+
+#ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+
+const char_constants< char >::char_type char_constants< char >::char_comment;
+const char_constants< char >::char_type char_constants< char >::char_comma;
+const char_constants< char >::char_type char_constants< char >::char_dot;
+const char_constants< char >::char_type char_constants< char >::char_quote;
+const char_constants< char >::char_type char_constants< char >::char_percent;
+const char_constants< char >::char_type char_constants< char >::char_exclamation;
+const char_constants< char >::char_type char_constants< char >::char_and;
+const char_constants< char >::char_type char_constants< char >::char_or;
+const char_constants< char >::char_type char_constants< char >::char_equal;
+const char_constants< char >::char_type char_constants< char >::char_greater;
+const char_constants< char >::char_type char_constants< char >::char_less;
+const char_constants< char >::char_type char_constants< char >::char_underline;
+const char_constants< char >::char_type char_constants< char >::char_backslash;
+const char_constants< char >::char_type char_constants< char >::char_section_bracket_left;
+const char_constants< char >::char_type char_constants< char >::char_section_bracket_right;
+const char_constants< char >::char_type char_constants< char >::char_paren_bracket_left;
+const char_constants< char >::char_type char_constants< char >::char_paren_bracket_right;
+
+#endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+
+//! Skips spaces in the beginning of the input
+const char* char_constants< char >::trim_spaces_left(const char_type* begin, const char_type* end)
+{
+ using namespace std;
+ while (begin != end && isspace(*begin))
+ ++begin;
+ return begin;
+}
+
+//! Skips spaces in the end of the input
+const char* char_constants< char >::trim_spaces_right(const char_type* begin, const char_type* end)
+{
+ using namespace std;
+ while (begin != end && isspace(*(end - 1)))
+ --end;
+ return end;
+}
+
+//! Scans for the attribute name placeholder in the input
+const char* char_constants< char >::scan_attr_placeholder(const char_type* begin, const char_type* end)
+{
+ using namespace std;
+ while (begin != end)
+ {
+ char_type c = *begin;
+ if (!isalnum(c) && c != char_underline)
+ break;
+ ++begin;
+ }
+
+ return begin;
+}
+
+//! Parses an operand string (possibly quoted) from the input
+const char* char_constants< char >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
+{
+ using namespace std; // to make sure we can use C functions unqualified
+
+ const char_type* p = begin;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
+
+ char_type c = *p;
+ if (c == char_quote)
+ {
+ // The value is specified as a quoted string
+ const char_type* start = ++p;
+ for (; p != end; ++p)
+ {
+ c = *p;
+ if (c == char_quote)
+ {
+ break;
+ }
+ else if (c == char_backslash)
+ {
+ ++p;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
+ }
+ }
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
+
+ operand.assign(start, p);
+ translate_escape_sequences(operand);
+
+ ++p; // skip the closing quote
+ }
+ else
+ {
+ // The value is specified as a single word
+ const char_type* start = p;
+ for (++p; p != end; ++p)
+ {
+ c = *p;
+ if (!isalnum(c) && c != '_' && c != '-' && c != '+' && c != '.')
+ break;
+ }
+
+ operand.assign(start, p);
+ }
+
+ return p;
+}
+
+//! Converts escape sequences to the corresponding characters
+void char_constants< char >::translate_escape_sequences(string_type& str)
+{
+ using namespace std; // to make sure we can use C functions unqualified
+
+ string_type::iterator it = str.begin();
+ while (it != str.end())
+ {
+ it = std::find(it, str.end(), '\\');
+ if (std::distance(it, str.end()) >= 2)
+ {
+ it = str.erase(it);
+ switch (*it)
+ {
+ case 'n':
+ *it = '\n'; break;
+ case 'r':
+ *it = '\r'; break;
+ case 'a':
+ *it = '\a'; break;
+ case '\\':
+ ++it; break;
+ case 't':
+ *it = '\t'; break;
+ case 'b':
+ *it = '\b'; break;
+ case 'x':
+ {
+ string_type::iterator b = it;
+ if (std::distance(++b, str.end()) >= 2)
+ {
+ char_type c1 = *b++, c2 = *b++;
+ if (isxdigit(c1) && isxdigit(c2))
+ {
+ *it++ = char_type((to_number(c1) << 4) | to_number(c2));
+ it = str.erase(it, b);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ if (*it >= '0' && *it <= '7')
+ {
+ string_type::iterator b = it;
+ int c = (*b++) - '0';
+ if (*b >= '0' && *b <= '7')
+ c = c * 8 + (*b++) - '0';
+ if (*b >= '0' && *b <= '7')
+ c = c * 8 + (*b++) - '0';
+
+ *it++ = char_type(c);
+ it = str.erase(it, b);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+#ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comment;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comma;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_dot;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_quote;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_percent;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_exclamation;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_and;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_or;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_equal;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_greater;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_less;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_underline;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_backslash;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_section_bracket_left;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_section_bracket_right;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_paren_bracket_left;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_paren_bracket_right;
+
+#endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+
+//! Skips spaces in the beginning of the input
+const wchar_t* char_constants< wchar_t >::trim_spaces_left(const char_type* begin, const char_type* end)
+{
+ using namespace std;
+ while (begin != end && iswspace(*begin))
+ ++begin;
+ return begin;
+}
+
+//! Skips spaces in the end of the input
+const wchar_t* char_constants< wchar_t >::trim_spaces_right(const char_type* begin, const char_type* end)
+{
+ using namespace std;
+ while (begin != end && iswspace(*(end - 1)))
+ --end;
+ return end;
+}
+
+//! Scans for the attribute name placeholder in the input
+const wchar_t* char_constants< wchar_t >::scan_attr_placeholder(const char_type* begin, const char_type* end)
+{
+ using namespace std;
+ while (begin != end)
+ {
+ char_type c = *begin;
+ if (!iswalnum(c) && c != char_underline)
+ break;
+ ++begin;
+ }
+
+ return begin;
+}
+
+//! Parses an operand string (possibly quoted) from the input
+const wchar_t* char_constants< wchar_t >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
+{
+ using namespace std; // to make sure we can use C functions unqualified
+
+ const char_type* p = begin;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
+
+ char_type c = *p;
+ if (c == char_quote)
+ {
+ // The value is specified as a quoted string
+ const char_type* start = ++p;
+ for (; p != end; ++p)
+ {
+ c = *p;
+ if (c == char_quote)
+ {
+ break;
+ }
+ else if (c == char_backslash)
+ {
+ ++p;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
+ }
+ }
+ if (p == end)
+ BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
+
+ operand.assign(start, p);
+ translate_escape_sequences(operand);
+
+ ++p; // skip the closing quote
+ }
+ else
+ {
+ // The value is specified as a single word
+ const char_type* start = p;
+ for (++p; p != end; ++p)
+ {
+ c = *p;
+ if (!iswalnum(c) && c != L'_' && c != L'-' && c != L'+' && c != L'.')
+ break;
+ }
+
+ operand.assign(start, p);
+ }
+
+ return p;
+}
+
+//! Converts escape sequences to the corresponding characters
+void char_constants< wchar_t >::translate_escape_sequences(string_type& str)
+{
+ using namespace std; // to make sure we can use C functions unqualified
+
+ string_type::iterator it = str.begin();
+ while (it != str.end())
+ {
+ it = std::find(it, str.end(), L'\\');
+ if (std::distance(it, str.end()) >= 2)
+ {
+ it = str.erase(it);
+ switch (*it)
+ {
+ case L'n':
+ *it = L'\n'; break;
+ case L'r':
+ *it = L'\r'; break;
+ case L'a':
+ *it = L'\a'; break;
+ case L'\\':
+ ++it; break;
+ case L't':
+ *it = L'\t'; break;
+ case L'b':
+ *it = L'\b'; break;
+ case L'x':
+ {
+ string_type::iterator b = it;
+ if (std::distance(++b, str.end()) >= 2)
+ {
+ char_type c1 = *b++, c2 = *b++;
+ if (iswxdigit(c1) && iswxdigit(c2))
+ {
+ *it++ = char_type((to_number(c1) << 4) | to_number(c2));
+ it = str.erase(it, b);
+ }
+ }
+ break;
+ }
+ case L'u':
+ {
+ string_type::iterator b = it;
+ if (std::distance(++b, str.end()) >= 4)
+ {
+ char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
+ if (iswxdigit(c1) && iswxdigit(c2) && iswxdigit(c3) && iswxdigit(c4))
+ {
+ *it++ = char_type(
+ (to_number(c1) << 12) |
+ (to_number(c2) << 8) |
+ (to_number(c3) << 4) |
+ to_number(c4));
+ it = str.erase(it, b);
+ }
+ }
+ break;
+ }
+ case L'U':
+ {
+ string_type::iterator b = it;
+ if (std::distance(++b, str.end()) >= 8)
+ {
+ char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
+ char_type c5 = *b++, c6 = *b++, c7 = *b++, c8 = *b++;
+ if (iswxdigit(c1) && iswxdigit(c2) && iswxdigit(c3) && iswxdigit(c4) &&
+ iswxdigit(c5) && iswxdigit(c6) && iswxdigit(c7) && iswxdigit(c8))
+ {
+ *it++ = char_type(
+ (to_number(c1) << 28) |
+ (to_number(c2) << 24) |
+ (to_number(c3) << 20) |
+ (to_number(c4) << 16) |
+ (to_number(c5) << 12) |
+ (to_number(c6) << 8) |
+ (to_number(c7) << 4) |
+ to_number(c8));
+ it = str.erase(it, b);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ if (*it >= L'0' && *it <= L'7')
+ {
+ string_type::iterator b = it;
+ int c = (*b++) - L'0';
+ if (*b >= L'0' && *b <= L'7')
+ c = c * 8 + (*b++) - L'0';
+ if (*b >= L'0' && *b <= L'7')
+ c = c * 8 + (*b++) - L'0';
+
+ *it++ = char_type(c);
+ it = str.erase(it, b);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
diff --git a/src/boost/libs/log/src/setup/parser_utils.hpp b/src/boost/libs/log/src/setup/parser_utils.hpp
new file mode 100644
index 000000000..bf0be4b87
--- /dev/null
+++ b/src/boost/libs/log/src/setup/parser_utils.hpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file parser_utils.hpp
+ * \author Andrey Semashev
+ * \date 31.03.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_PARSER_UTILS_HPP_INCLUDED_
+#define BOOST_LOG_PARSER_UTILS_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <string>
+#include <iostream>
+#include <cctype>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Some constants and algorithms needed for parsing
+template< typename > struct char_constants;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct char_constants< char >
+{
+ typedef char char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef boost::log::basic_string_literal< char_type > literal_type;
+
+ static const char_type char_comment = '#';
+ static const char_type char_comma = ',';
+ static const char_type char_dot = '.';
+ static const char_type char_quote = '"';
+ static const char_type char_percent = '%';
+ static const char_type char_exclamation = '!';
+ static const char_type char_and = '&';
+ static const char_type char_or = '|';
+ static const char_type char_equal = '=';
+ static const char_type char_greater = '>';
+ static const char_type char_less = '<';
+ static const char_type char_underline = '_';
+ static const char_type char_backslash = '\\';
+ static const char_type char_section_bracket_left = '[';
+ static const char_type char_section_bracket_right = ']';
+ static const char_type char_paren_bracket_left = '(';
+ static const char_type char_paren_bracket_right = ')';
+
+ static const char_type* not_keyword() { return "not"; }
+ static const char_type* and_keyword() { return "and"; }
+ static const char_type* or_keyword() { return "or"; }
+ static const char_type* equal_keyword() { return "="; }
+ static const char_type* greater_keyword() { return ">"; }
+ static const char_type* less_keyword() { return "<"; }
+ static const char_type* not_equal_keyword() { return "!="; }
+ static const char_type* greater_or_equal_keyword() { return ">="; }
+ static const char_type* less_or_equal_keyword() { return "<="; }
+ static const char_type* begins_with_keyword() { return "begins_with"; }
+ static const char_type* ends_with_keyword() { return "ends_with"; }
+ static const char_type* contains_keyword() { return "contains"; }
+ static const char_type* matches_keyword() { return "matches"; }
+
+ static const char_type* message_text_keyword() { return "_"; }
+
+ static literal_type true_keyword() { return literal_type("true"); }
+ static literal_type false_keyword() { return literal_type("false"); }
+
+ static const char_type* default_level_attribute_name() { return "Severity"; }
+
+ static const char_type* core_section_name() { return "Core"; }
+ static const char_type* sink_section_name_prefix() { return "Sink:"; }
+
+ static const char_type* core_disable_logging_param_name() { return "DisableLogging"; }
+ static const char_type* filter_param_name() { return "Filter"; }
+
+ static const char_type* sink_destination_param_name() { return "Destination"; }
+ static const char_type* file_name_param_name() { return "FileName"; }
+ static const char_type* rotation_size_param_name() { return "RotationSize"; }
+ static const char_type* rotation_interval_param_name() { return "RotationInterval"; }
+ static const char_type* rotation_time_point_param_name() { return "RotationTimePoint"; }
+ static const char_type* append_param_name() { return "Append"; }
+ static const char_type* enable_final_rotation_param_name() { return "EnableFinalRotation"; }
+ static const char_type* auto_flush_param_name() { return "AutoFlush"; }
+ static const char_type* auto_newline_mode_param_name() { return "AutoNewline"; }
+ static const char_type* asynchronous_param_name() { return "Asynchronous"; }
+ static const char_type* format_param_name() { return "Format"; }
+ static const char_type* provider_id_param_name() { return "ProviderID"; }
+ static const char_type* log_name_param_name() { return "LogName"; }
+ static const char_type* source_name_param_name() { return "LogSource"; }
+ static const char_type* registration_param_name() { return "Registration"; }
+ static const char_type* local_address_param_name() { return "LocalAddress"; }
+ static const char_type* target_address_param_name() { return "TargetAddress"; }
+ static const char_type* target_param_name() { return "Target"; }
+ static const char_type* max_size_param_name() { return "MaxSize"; }
+ static const char_type* max_files_param_name() { return "MaxFiles"; }
+ static const char_type* min_free_space_param_name() { return "MinFreeSpace"; }
+ static const char_type* scan_for_files_param_name() { return "ScanForFiles"; }
+
+ static const char_type* scan_method_all() { return "All"; }
+ static const char_type* scan_method_matching() { return "Matching"; }
+
+ static const char_type* auto_newline_mode_disabled() { return "Disabled"; }
+ static const char_type* auto_newline_mode_always_insert() { return "AlwaysInsert"; }
+ static const char_type* auto_newline_mode_insert_if_missing() { return "InsertIfMissing"; }
+
+ static const char_type* registration_never() { return "Never"; }
+ static const char_type* registration_on_demand() { return "OnDemand"; }
+ static const char_type* registration_forced() { return "Forced"; }
+
+ static const char_type* text_file_destination() { return "TextFile"; }
+ static const char_type* console_destination() { return "Console"; }
+ static const char_type* syslog_destination() { return "Syslog"; }
+ static const char_type* simple_event_log_destination() { return "SimpleEventLog"; }
+ static const char_type* debugger_destination() { return "Debugger"; }
+
+ static literal_type monday_keyword() { return literal_type("Monday"); }
+ static literal_type short_monday_keyword() { return literal_type("Mon"); }
+ static literal_type tuesday_keyword() { return literal_type("Tuesday"); }
+ static literal_type short_tuesday_keyword() { return literal_type("Tue"); }
+ static literal_type wednesday_keyword() { return literal_type("Wednesday"); }
+ static literal_type short_wednesday_keyword() { return literal_type("Wed"); }
+ static literal_type thursday_keyword() { return literal_type("Thursday"); }
+ static literal_type short_thursday_keyword() { return literal_type("Thu"); }
+ static literal_type friday_keyword() { return literal_type("Friday"); }
+ static literal_type short_friday_keyword() { return literal_type("Fri"); }
+ static literal_type saturday_keyword() { return literal_type("Saturday"); }
+ static literal_type short_saturday_keyword() { return literal_type("Sat"); }
+ static literal_type sunday_keyword() { return literal_type("Sunday"); }
+ static literal_type short_sunday_keyword() { return literal_type("Sun"); }
+
+ static std::ostream& get_console_log_stream() { return std::clog; }
+
+ static int to_number(char_type c)
+ {
+ using namespace std; // to make sure we can use C functions unqualified
+ int n = 0;
+ if (isdigit(c))
+ n = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ n = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ n = c - 'A' + 10;
+ return n;
+ }
+
+ //! Skips spaces in the beginning of the input
+ static const char_type* trim_spaces_left(const char_type* begin, const char_type* end);
+ //! Skips spaces in the end of the input
+ static const char_type* trim_spaces_right(const char_type* begin, const char_type* end);
+ //! Scans for the attribute name placeholder in the input
+ static const char_type* scan_attr_placeholder(const char_type* begin, const char_type* end);
+ //! Parses an operand string (possibly quoted) from the input
+ static const char_type* parse_operand(const char_type* begin, const char_type* end, string_type& operand);
+ //! Converts escape sequences to the corresponding characters
+ static void translate_escape_sequences(string_type& str);
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct char_constants< wchar_t >
+{
+ typedef wchar_t char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef boost::log::basic_string_literal< char_type > literal_type;
+
+ static const char_type char_comment = L'#';
+ static const char_type char_comma = L',';
+ static const char_type char_dot = L'.';
+ static const char_type char_quote = L'"';
+ static const char_type char_percent = L'%';
+ static const char_type char_exclamation = L'!';
+ static const char_type char_and = L'&';
+ static const char_type char_or = L'|';
+ static const char_type char_equal = L'=';
+ static const char_type char_greater = L'>';
+ static const char_type char_less = L'<';
+ static const char_type char_underline = L'_';
+ static const char_type char_backslash = L'\\';
+ static const char_type char_section_bracket_left = L'[';
+ static const char_type char_section_bracket_right = L']';
+ static const char_type char_paren_bracket_left = L'(';
+ static const char_type char_paren_bracket_right = L')';
+
+ static const char_type* not_keyword() { return L"not"; }
+ static const char_type* and_keyword() { return L"and"; }
+ static const char_type* or_keyword() { return L"or"; }
+ static const char_type* equal_keyword() { return L"="; }
+ static const char_type* greater_keyword() { return L">"; }
+ static const char_type* less_keyword() { return L"<"; }
+ static const char_type* not_equal_keyword() { return L"!="; }
+ static const char_type* greater_or_equal_keyword() { return L">="; }
+ static const char_type* less_or_equal_keyword() { return L"<="; }
+ static const char_type* begins_with_keyword() { return L"begins_with"; }
+ static const char_type* ends_with_keyword() { return L"ends_with"; }
+ static const char_type* contains_keyword() { return L"contains"; }
+ static const char_type* matches_keyword() { return L"matches"; }
+
+ static const char_type* message_text_keyword() { return L"_"; }
+
+ static literal_type true_keyword() { return literal_type(L"true"); }
+ static literal_type false_keyword() { return literal_type(L"false"); }
+
+ static const char_type* default_level_attribute_name() { return L"Severity"; }
+
+ static const char_type* core_section_name() { return L"Core"; }
+ static const char_type* sink_section_name_prefix() { return L"Sink:"; }
+
+ static const char_type* core_disable_logging_param_name() { return L"DisableLogging"; }
+ static const char_type* filter_param_name() { return L"Filter"; }
+
+ static const char_type* sink_destination_param_name() { return L"Destination"; }
+ static const char_type* file_name_param_name() { return L"FileName"; }
+ static const char_type* rotation_size_param_name() { return L"RotationSize"; }
+ static const char_type* rotation_interval_param_name() { return L"RotationInterval"; }
+ static const char_type* rotation_time_point_param_name() { return L"RotationTimePoint"; }
+ static const char_type* append_param_name() { return L"Append"; }
+ static const char_type* enable_final_rotation_param_name() { return L"EnableFinalRotation"; }
+ static const char_type* auto_flush_param_name() { return L"AutoFlush"; }
+ static const char_type* auto_newline_mode_param_name() { return L"AutoNewline"; }
+ static const char_type* asynchronous_param_name() { return L"Asynchronous"; }
+ static const char_type* format_param_name() { return L"Format"; }
+ static const char_type* provider_id_param_name() { return L"ProviderID"; }
+ static const char_type* log_name_param_name() { return L"LogName"; }
+ static const char_type* source_name_param_name() { return L"LogSource"; }
+ static const char_type* registration_param_name() { return L"Registration"; }
+ static const char_type* local_address_param_name() { return L"LocalAddress"; }
+ static const char_type* target_address_param_name() { return L"TargetAddress"; }
+ static const char_type* target_param_name() { return L"Target"; }
+ static const char_type* max_size_param_name() { return L"MaxSize"; }
+ static const char_type* max_files_param_name() { return L"MaxFiles"; }
+ static const char_type* min_free_space_param_name() { return L"MinFreeSpace"; }
+ static const char_type* scan_for_files_param_name() { return L"ScanForFiles"; }
+
+ static const char_type* scan_method_all() { return L"All"; }
+ static const char_type* scan_method_matching() { return L"Matching"; }
+
+ static const char_type* auto_newline_mode_disabled() { return L"Disabled"; }
+ static const char_type* auto_newline_mode_always_insert() { return L"AlwaysInsert"; }
+ static const char_type* auto_newline_mode_insert_if_missing() { return L"InsertIfMissing"; }
+
+ static const char_type* registration_never() { return L"Never"; }
+ static const char_type* registration_on_demand() { return L"OnDemand"; }
+ static const char_type* registration_forced() { return L"Forced"; }
+
+ static const char_type* text_file_destination() { return L"TextFile"; }
+ static const char_type* console_destination() { return L"Console"; }
+ static const char_type* syslog_destination() { return L"Syslog"; }
+ static const char_type* simple_event_log_destination() { return L"SimpleEventLog"; }
+ static const char_type* debugger_destination() { return L"Debugger"; }
+
+ static literal_type monday_keyword() { return literal_type(L"Monday"); }
+ static literal_type short_monday_keyword() { return literal_type(L"Mon"); }
+ static literal_type tuesday_keyword() { return literal_type(L"Tuesday"); }
+ static literal_type short_tuesday_keyword() { return literal_type(L"Tue"); }
+ static literal_type wednesday_keyword() { return literal_type(L"Wednesday"); }
+ static literal_type short_wednesday_keyword() { return literal_type(L"Wed"); }
+ static literal_type thursday_keyword() { return literal_type(L"Thursday"); }
+ static literal_type short_thursday_keyword() { return literal_type(L"Thu"); }
+ static literal_type friday_keyword() { return literal_type(L"Friday"); }
+ static literal_type short_friday_keyword() { return literal_type(L"Fri"); }
+ static literal_type saturday_keyword() { return literal_type(L"Saturday"); }
+ static literal_type short_saturday_keyword() { return literal_type(L"Sat"); }
+ static literal_type sunday_keyword() { return literal_type(L"Sunday"); }
+ static literal_type short_sunday_keyword() { return literal_type(L"Sun"); }
+
+ static std::wostream& get_console_log_stream() { return std::wclog; }
+
+ static int to_number(char_type c)
+ {
+ int n = 0;
+ if (c >= L'0' && c <= L'9')
+ n = c - L'0';
+ else if (c >= L'a' && c <= L'f')
+ n = c - L'a' + 10;
+ else if (c >= L'A' && c <= L'F')
+ n = c - L'A' + 10;
+ return n;
+ }
+
+ static bool iswxdigit(char_type c)
+ {
+ return (c >= L'0' && c <= L'9') || (c >= L'a' && c <= L'f') || (c >= L'A' && c <= L'F');
+ }
+
+ //! Skips spaces in the beginning of the input
+ static const char_type* trim_spaces_left(const char_type* begin, const char_type* end);
+ //! Skips spaces in the end of the input
+ static const char_type* trim_spaces_right(const char_type* begin, const char_type* end);
+ //! Scans for the attribute name placeholder in the input
+ static const char_type* scan_attr_placeholder(const char_type* begin, const char_type* end);
+ //! Parses an operand string (possibly quoted) from the input
+ static const char_type* parse_operand(const char_type* begin, const char_type* end, string_type& operand);
+ //! Converts escape sequences to the corresponding characters
+ static void translate_escape_sequences(string_type& str);
+};
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_PARSER_UTILS_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/setup/settings_parser.cpp b/src/boost/libs/log/src/setup/settings_parser.cpp
new file mode 100644
index 000000000..d0ebe6fed
--- /dev/null
+++ b/src/boost/libs/log/src/setup/settings_parser.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file settings_parser.cpp
+ * \author Andrey Semashev
+ * \date 20.07.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
+
+#include <boost/log/detail/setup_config.hpp>
+#include <string>
+#include <locale>
+#include <iostream>
+#include <stdexcept>
+#include <algorithm>
+#include <boost/throw_exception.hpp>
+#include <boost/exception/exception.hpp>
+#include <boost/exception/info.hpp>
+#include <boost/exception/errinfo_at_line.hpp>
+#include <boost/io/ios_state.hpp>
+#include <boost/move/core.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/utility/setup/settings_parser.hpp>
+#include <boost/log/exceptions.hpp>
+#include "parser_utils.hpp"
+#include "spirit_encoding.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! Settings parser
+template< typename CharT >
+class settings_parser
+{
+private:
+ typedef CharT char_type;
+ typedef const char_type* iterator_type;
+ typedef typename log::aux::encoding< char_type >::type encoding;
+ typedef settings_parser< char_type > this_type;
+
+ typedef std::basic_string< char_type > string_type;
+ typedef log::aux::char_constants< char_type > constants;
+ typedef basic_settings< char_type > settings_type;
+
+private:
+ //! Current section name
+ std::string m_SectionName;
+ //! Current parameter name
+ std::string m_ParameterName;
+ //! Settings instance
+ settings_type& m_Settings;
+ //! Locale from the source stream
+ std::locale m_Locale;
+ //! Current line number
+ unsigned int& m_LineCounter;
+
+public:
+ //! Constructor
+ explicit settings_parser(settings_type& setts, unsigned int& line_counter, std::locale const& loc) :
+ m_Settings(setts),
+ m_Locale(loc),
+ m_LineCounter(line_counter)
+ {
+ }
+
+ //! Parses a line of the input
+ void parse_line(iterator_type& begin, iterator_type end)
+ {
+ iterator_type p = begin;
+ p = constants::trim_spaces_left(p, end);
+ if (p != end)
+ {
+ char_type c = *p;
+ if (c == constants::char_section_bracket_left)
+ {
+ // We have a section name
+ iterator_type start = ++p;
+ start = constants::trim_spaces_left(start, end);
+ iterator_type stop = std::find(start, end, constants::char_section_bracket_right);
+ if (stop == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section header is invalid", (m_LineCounter));
+
+ p = stop + 1;
+ stop = constants::trim_spaces_right(start, stop);
+
+ set_section_name(start, stop);
+ }
+ else if (c != constants::char_comment)
+ {
+ // We have a parameter
+ iterator_type eq = std::find(p, end, constants::char_equal);
+ if (eq == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter description is invalid", (m_LineCounter));
+
+ // Parameter name
+ set_parameter_name(p, constants::trim_spaces_right(p, eq));
+
+ // Parameter value
+ p = constants::trim_spaces_left(eq + 1, end);
+ if (p == end || *p == constants::char_comment)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter value is not specified", (m_LineCounter));
+
+ try
+ {
+ string_type value;
+ p = constants::parse_operand(p, end, value);
+ set_parameter_value(value);
+ }
+ catch (parse_error& e)
+ {
+ throw boost::enable_error_info(e) << boost::errinfo_at_line(m_LineCounter);
+ }
+ }
+
+ // In the end of the line we may have a comment
+ p = constants::trim_spaces_left(p, end);
+ if (p != end)
+ {
+ c = *p;
+ if (c == constants::char_comment)
+ {
+ // The comment spans until the end of the line
+ p = end;
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unexpected characters in the end of the line", (m_LineCounter));
+ }
+ }
+ }
+
+ begin = p;
+ }
+
+private:
+ //! The method sets the parsed section name
+ void set_section_name(iterator_type begin, iterator_type end)
+ {
+ // Check that the section name is valid
+ if (begin == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is empty", (m_LineCounter));
+
+ for (iterator_type p = begin; p != end; ++p)
+ {
+ char_type c = *p;
+ if (c != constants::char_dot && !encoding::isalnum(c))
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is invalid", (m_LineCounter));
+ }
+
+ m_SectionName = log::aux::to_narrow(string_type(begin, end), m_Locale);
+
+ // For compatibility with Boost.Log v1, we replace the "Sink:" prefix with "Sinks."
+ // so that all sink parameters are placed in the common Sinks section.
+ if (m_SectionName.compare(0, 5, "Sink:") == 0)
+ m_SectionName = "Sinks." + m_SectionName.substr(5);
+ }
+
+ //! The method sets the parsed parameter name
+ void set_parameter_name(iterator_type begin, iterator_type end)
+ {
+ if (m_SectionName.empty())
+ {
+ // The parameter encountered before any section starter
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections", (m_LineCounter));
+ }
+
+ // Check that the parameter name is valid
+ if (begin == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is empty", (m_LineCounter));
+
+ iterator_type p = begin;
+ if (!encoding::isalpha(*p))
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter));
+ for (++p; p != end; ++p)
+ {
+ char_type c = *p;
+ if (!encoding::isgraph(c))
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter));
+ }
+
+ m_ParameterName = log::aux::to_narrow(string_type(begin, end), m_Locale);
+ }
+
+ //! The method sets the parsed parameter value (non-quoted)
+ void set_parameter_value(string_type const& value)
+ {
+ m_Settings[m_SectionName][m_ParameterName] = value;
+ m_ParameterName.clear();
+ }
+
+ // Assignment and copying are prohibited
+ BOOST_DELETED_FUNCTION(settings_parser(settings_parser const&))
+ BOOST_DELETED_FUNCTION(settings_parser& operator= (settings_parser const&))
+};
+
+} // namespace
+
+//! The function parses library settings from an input stream
+template< typename CharT >
+BOOST_LOG_SETUP_API basic_settings< CharT > parse_settings(std::basic_istream< CharT >& strm)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef settings_parser< char_type > settings_parser_type;
+ typedef basic_settings< char_type > settings_type;
+
+ if (!strm.good())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("The input stream for parsing settings is not valid"));
+
+ io::basic_ios_exception_saver< char_type > exceptions_guard(strm, std::ios_base::badbit);
+
+ // Engage parsing
+ settings_type settings;
+ unsigned int line_number = 1;
+ std::locale loc = strm.getloc();
+ settings_parser_type parser(settings, line_number, loc);
+
+ string_type line;
+ while (!strm.eof())
+ {
+ std::getline(strm, line);
+
+ const char_type* p = line.c_str();
+ parser.parse_line(p, p + line.size());
+
+ line.clear();
+ ++line_number;
+ }
+
+ return BOOST_LOG_NRVO_RESULT(settings);
+}
+
+
+#ifdef BOOST_LOG_USE_CHAR
+template BOOST_LOG_SETUP_API basic_settings< char > parse_settings< char >(std::basic_istream< char >& strm);
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template BOOST_LOG_SETUP_API basic_settings< wchar_t > parse_settings< wchar_t >(std::basic_istream< wchar_t >& strm);
+#endif
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS
diff --git a/src/boost/libs/log/src/severity_level.cpp b/src/boost/libs/log/src/severity_level.cpp
new file mode 100644
index 000000000..03f8ebbd4
--- /dev/null
+++ b/src/boost/libs/log/src/severity_level.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file severity_level.cpp
+ * \author Andrey Semashev
+ * \date 10.05.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/log/sources/severity_feature.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_USE_COMPILER_TLS)
+#include <boost/bind/bind.hpp>
+#include <boost/checked_delete.hpp>
+#include <boost/thread/thread.hpp> // at_thread_exit
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/detail/thread_specific.hpp>
+#endif
+#include "unique_ptr.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sources {
+
+namespace aux {
+
+#if defined(BOOST_LOG_NO_THREADS)
+
+static uintmax_t g_Severity = 0;
+
+#elif defined(BOOST_LOG_USE_COMPILER_TLS)
+
+static BOOST_LOG_TLS uintmax_t g_Severity = 0;
+
+#else
+
+//! Severity level storage class
+class severity_level_holder :
+ public boost::log::aux::lazy_singleton< severity_level_holder, boost::log::aux::thread_specific< uintmax_t* > >
+{
+};
+
+#endif
+
+
+#if !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_USE_COMPILER_TLS)
+
+//! The method returns the severity level for the current thread
+BOOST_LOG_API uintmax_t& get_severity_level()
+{
+ boost::log::aux::thread_specific< uintmax_t* >& tss = severity_level_holder::get();
+ uintmax_t* p = tss.get();
+ if (BOOST_UNLIKELY(!p))
+ {
+ log::aux::unique_ptr< uintmax_t > ptr(new uintmax_t(0));
+ tss.set(ptr.get());
+ p = ptr.release();
+ boost::this_thread::at_thread_exit(boost::bind(checked_deleter< uintmax_t >(), p));
+ }
+ return *p;
+}
+
+#else // !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_USE_COMPILER_TLS)
+
+//! The method returns the severity level for the current thread
+BOOST_LOG_API uintmax_t& get_severity_level()
+{
+ return g_Severity;
+}
+
+#endif // !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_USE_COMPILER_TLS)
+
+} // namespace aux
+
+} // namespace sources
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/spirit_encoding.cpp b/src/boost/libs/log/src/spirit_encoding.cpp
new file mode 100644
index 000000000..1222435ee
--- /dev/null
+++ b/src/boost/libs/log/src/spirit_encoding.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file spirit_encoding.cpp
+ * \author Andrey Semashev
+ * \date 20.07.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/preprocessor/tuple/elem.hpp>
+#include <boost/preprocessor/seq/for_each.hpp>
+#include "spirit_encoding.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#define BOOST_LOG_DEFINE_CHARSET_PARSER(r, charset, parser)\
+ BOOST_LOG_API encoding_specific< spirit::char_encoding::charset >::BOOST_PP_TUPLE_ELEM(2, 0, parser) const&\
+ encoding_specific< spirit::char_encoding::charset >::BOOST_PP_TUPLE_ELEM(2, 1, parser) =\
+ spirit::charset::BOOST_PP_TUPLE_ELEM(2, 1, parser);
+
+#define BOOST_LOG_DEFINE_CHARSET_PARSERS(charset)\
+ BOOST_PP_SEQ_FOR_EACH(BOOST_LOG_DEFINE_CHARSET_PARSER, charset, BOOST_LOG_CHARSET_PARSERS)
+
+BOOST_LOG_DEFINE_CHARSET_PARSERS(standard)
+BOOST_LOG_DEFINE_CHARSET_PARSERS(standard_wide)
+
+#undef BOOST_LOG_DEFINE_CHARSET_PARSERS
+#undef BOOST_LOG_DEFINE_CHARSET_PARSER
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/spirit_encoding.hpp b/src/boost/libs/log/src/spirit_encoding.hpp
new file mode 100644
index 000000000..654290788
--- /dev/null
+++ b/src/boost/libs/log/src/spirit_encoding.hpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file spirit_encoding.hpp
+ * \author Andrey Semashev
+ * \date 20.07.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_SPIRIT_ENCODING_HPP_INCLUDED_
+#define BOOST_LOG_SPIRIT_ENCODING_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/preprocessor/tuple/elem.hpp>
+#include <boost/preprocessor/seq/for_each.hpp>
+#include <boost/spirit/include/support_standard.hpp>
+#include <boost/spirit/include/support_standard_wide.hpp>
+#include <boost/spirit/home/support/common_terminals.hpp>
+#include <boost/log/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+template< typename >
+struct encoding;
+
+template< >
+struct encoding< char >
+{
+ typedef spirit::char_encoding::standard type;
+};
+template< >
+struct encoding< wchar_t >
+{
+ typedef spirit::char_encoding::standard_wide type;
+};
+
+//! A simple trait that allows to use charset-specific Qi parsers in a generic way
+template< typename EncodingT >
+struct encoding_specific;
+
+#define BOOST_LOG_CHARSET_PARSERS\
+ ((char_type, char_))\
+ ((string_type, string))\
+ ((alnum_type, alnum))\
+ ((alpha_type, alpha))\
+ ((blank_type, blank))\
+ ((cntrl_type, cntrl))\
+ ((digit_type, digit))\
+ ((graph_type, graph))\
+ ((print_type, print))\
+ ((punct_type, punct))\
+ ((space_type, space))\
+ ((xdigit_type, xdigit))\
+ ((no_case_type, no_case))\
+ ((lower_type, lower))\
+ ((upper_type, upper))\
+ ((lowernum_type, lowernum))\
+ ((uppernum_type, uppernum))
+
+#define BOOST_LOG_DECLARE_CHARSET_PARSER(r, charset, parser)\
+ typedef spirit::charset::BOOST_PP_TUPLE_ELEM(2, 0, parser) BOOST_PP_TUPLE_ELEM(2, 0, parser);\
+ BOOST_LOG_API static BOOST_PP_TUPLE_ELEM(2, 0, parser) const& BOOST_PP_TUPLE_ELEM(2, 1, parser);
+
+#define BOOST_LOG_DECLARE_CHARSET_PARSERS(charset)\
+ BOOST_PP_SEQ_FOR_EACH(BOOST_LOG_DECLARE_CHARSET_PARSER, charset, BOOST_LOG_CHARSET_PARSERS)
+
+template< >
+struct encoding_specific< spirit::char_encoding::standard >
+{
+ BOOST_LOG_DECLARE_CHARSET_PARSERS(standard)
+};
+
+template< >
+struct encoding_specific< spirit::char_encoding::standard_wide >
+{
+ BOOST_LOG_DECLARE_CHARSET_PARSERS(standard_wide)
+};
+
+#undef BOOST_LOG_DECLARE_CHARSET_PARSERS
+#undef BOOST_LOG_DECLARE_CHARSET_PARSER
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_SPIRIT_ENCODING_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/stateless_allocator.hpp b/src/boost/libs/log/src/stateless_allocator.hpp
new file mode 100644
index 000000000..3377f0831
--- /dev/null
+++ b/src/boost/libs/log/src/stateless_allocator.hpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file stateless_allocator.hpp
+ * \author Andrey Semashev
+ * \date 11.02.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_STATELESS_ALLOCATOR_HPP_INCLUDED_
+#define BOOST_LOG_STATELESS_ALLOCATOR_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <cstdlib>
+#include <memory>
+#include <boost/log/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#if defined(_STLPORT_VERSION)
+
+#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
+
+template< typename T >
+using stateless_allocator = std::allocator< T >;
+
+#else
+
+template< typename T >
+struct stateless_allocator :
+ public std::allocator< T >
+{
+};
+
+#endif
+
+#else
+
+template< typename T >
+struct stateless_allocator
+{
+ template< typename U >
+ struct rebind
+ {
+ typedef stateless_allocator< U > other;
+ };
+
+ typedef T value_type;
+ typedef value_type* pointer;
+ typedef value_type const* const_pointer;
+ typedef value_type& reference;
+ typedef value_type const& const_reference;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ static pointer allocate(size_type n, const void* = NULL)
+ {
+ pointer p = static_cast< pointer >(std::malloc(n * sizeof(value_type)));
+ if (p)
+ return p;
+ else
+ throw std::bad_alloc();
+ }
+ static void deallocate(pointer p, size_type)
+ {
+ std::free(p);
+ }
+};
+
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_STATELESS_ALLOCATOR_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/syslog_backend.cpp b/src/boost/libs/log/src/syslog_backend.cpp
new file mode 100644
index 000000000..19731880b
--- /dev/null
+++ b/src/boost/libs/log/src/syslog_backend.cpp
@@ -0,0 +1,620 @@
+/*
+ * Copyright Andrey Semashev 2007 - 2018.
+ * 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)
+ */
+/*!
+ * \file syslog_backend.cpp
+ * \author Andrey Semashev
+ * \date 08.01.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WITHOUT_SYSLOG
+
+#include <boost/log/detail/config.hpp>
+#include <ctime>
+#include <algorithm>
+#include <stdexcept>
+#include <boost/limits.hpp>
+#include <boost/assert.hpp>
+#include <boost/smart_ptr/weak_ptr.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/throw_exception.hpp>
+#if !defined(BOOST_LOG_NO_ASIO)
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/asio/ip/address.hpp>
+#include <boost/asio/ip/host_name.hpp>
+#include <boost/asio/ip/resolver_base.hpp>
+#endif
+#include <boost/system/error_code.hpp>
+#include <boost/date_time/c_time.hpp>
+#include <boost/log/sinks/syslog_backend.hpp>
+#include <boost/log/sinks/syslog_constants.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/detail/snprintf.hpp>
+#include <boost/log/exceptions.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/locks.hpp>
+#include <boost/thread/mutex.hpp>
+#endif
+#include "unique_ptr.hpp"
+
+#ifdef BOOST_LOG_USE_NATIVE_SYSLOG
+#include <syslog.h>
+#endif // BOOST_LOG_USE_NATIVE_SYSLOG
+
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+namespace syslog {
+
+ //! The function constructs log record level from an integer
+ BOOST_LOG_API level make_level(int lev)
+ {
+ if (BOOST_UNLIKELY(static_cast< unsigned int >(lev) >= 8u))
+ BOOST_THROW_EXCEPTION(std::out_of_range("syslog level value is out of range"));
+ return static_cast< level >(lev);
+ }
+
+ //! The function constructs log source facility from an integer
+ BOOST_LOG_API facility make_facility(int fac)
+ {
+ if (BOOST_UNLIKELY((static_cast< unsigned int >(fac) & 7u) != 0u
+ || static_cast< unsigned int >(fac) > (23u * 8u)))
+ {
+ BOOST_THROW_EXCEPTION(std::out_of_range("syslog facility code value is out of range"));
+ }
+ return static_cast< facility >(fac);
+ }
+
+} // namespace syslog
+
+////////////////////////////////////////////////////////////////////////////////
+//! Syslog sink backend implementation
+////////////////////////////////////////////////////////////////////////////////
+struct syslog_backend::implementation
+{
+#ifdef BOOST_LOG_USE_NATIVE_SYSLOG
+ struct native;
+#endif // BOOST_LOG_USE_NATIVE_SYSLOG
+#if !defined(BOOST_LOG_NO_ASIO)
+ struct udp_socket_based;
+#endif
+
+ //! Level mapper
+ severity_mapper_type m_LevelMapper;
+
+ //! Logging facility (portable or native, depending on the backend implementation)
+ const int m_Facility;
+
+ //! Constructor
+ explicit implementation(int facility) :
+ m_Facility(facility)
+ {
+ }
+ //! Virtual destructor
+ virtual ~implementation() {}
+
+ //! The method sends the formatted message to the syslog host
+ virtual void send(syslog::level lev, string_type const& formatted_message) = 0;
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Native syslog API support
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef BOOST_LOG_USE_NATIVE_SYSLOG
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ //! Syslog service initializer (implemented as a weak singleton)
+#if !defined(BOOST_LOG_NO_THREADS)
+ class native_syslog_initializer :
+ private log::aux::lazy_singleton< native_syslog_initializer, mutex >
+#else
+ class native_syslog_initializer
+#endif
+ {
+#if !defined(BOOST_LOG_NO_THREADS)
+ friend class log::aux::lazy_singleton< native_syslog_initializer, mutex >;
+ typedef log::aux::lazy_singleton< native_syslog_initializer, mutex > mutex_holder;
+#endif
+
+ private:
+ /*!
+ * \brief Application identification string
+ *
+ * \note We have to keep it as an immutable member because some syslog implementations (e.g. glibc)
+ * do not deep-copy the ident string to internal storage when \c openlog is called
+ * and instead save a pointer to the user-provided string. This means the user-provided
+ * string needs to remain accessible for the whole duration of logging.
+ *
+ * https://github.com/boostorg/log/issues/97
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=25442
+ */
+ const std::string m_Ident;
+
+ public:
+ native_syslog_initializer(std::string const& ident, int facility) :
+ m_Ident(ident)
+ {
+ ::openlog((m_Ident.empty() ? static_cast< const char* >(NULL) : m_Ident.c_str()), 0, facility);
+ }
+ ~native_syslog_initializer()
+ {
+ ::closelog();
+ }
+
+ static shared_ptr< native_syslog_initializer > get_instance(std::string const& ident, int facility)
+ {
+#if !defined(BOOST_LOG_NO_THREADS)
+ lock_guard< mutex > lock(mutex_holder::get());
+#endif
+ static weak_ptr< native_syslog_initializer > instance;
+ shared_ptr< native_syslog_initializer > p(instance.lock());
+ if (!p)
+ {
+ p = boost::make_shared< native_syslog_initializer >(ident, facility);
+ instance = p;
+ }
+ return p;
+ }
+
+ BOOST_DELETED_FUNCTION(native_syslog_initializer(native_syslog_initializer const&))
+ BOOST_DELETED_FUNCTION(native_syslog_initializer& operator= (native_syslog_initializer const&))
+ };
+
+} // namespace
+
+struct syslog_backend::implementation::native :
+ public implementation
+{
+ //! Reference to the syslog service initializer
+ const shared_ptr< native_syslog_initializer > m_pSyslogInitializer;
+
+ //! Constructor
+ native(syslog::facility const& fac, std::string const& ident) :
+ implementation(convert_facility(fac)),
+ m_pSyslogInitializer(native_syslog_initializer::get_instance(ident, this->m_Facility))
+ {
+ }
+
+ //! The method sends the formatted message to the syslog host
+ void send(syslog::level lev, string_type const& formatted_message)
+ {
+ int native_level;
+ switch (lev)
+ {
+ case syslog::emergency:
+ native_level = LOG_EMERG; break;
+ case syslog::alert:
+ native_level = LOG_ALERT; break;
+ case syslog::critical:
+ native_level = LOG_CRIT; break;
+ case syslog::error:
+ native_level = LOG_ERR; break;
+ case syslog::warning:
+ native_level = LOG_WARNING; break;
+ case syslog::notice:
+ native_level = LOG_NOTICE; break;
+ case syslog::debug:
+ native_level = LOG_DEBUG; break;
+ default:
+ native_level = LOG_INFO; break;
+ }
+
+ ::syslog(this->m_Facility | native_level, "%s", formatted_message.c_str());
+ }
+
+private:
+ //! The function converts portable facility codes to the native codes
+ static int convert_facility(syslog::facility const& fac)
+ {
+ // POSIX does not specify anything except for LOG_USER and LOG_LOCAL*
+ #ifndef LOG_KERN
+ #define LOG_KERN LOG_USER
+ #endif
+ #ifndef LOG_DAEMON
+ #define LOG_DAEMON LOG_KERN
+ #endif
+ #ifndef LOG_MAIL
+ #define LOG_MAIL LOG_USER
+ #endif
+ #ifndef LOG_AUTH
+ #define LOG_AUTH LOG_DAEMON
+ #endif
+ #ifndef LOG_SYSLOG
+ #define LOG_SYSLOG LOG_DAEMON
+ #endif
+ #ifndef LOG_LPR
+ #define LOG_LPR LOG_DAEMON
+ #endif
+ #ifndef LOG_NEWS
+ #define LOG_NEWS LOG_USER
+ #endif
+ #ifndef LOG_UUCP
+ #define LOG_UUCP LOG_USER
+ #endif
+ #ifndef LOG_CRON
+ #define LOG_CRON LOG_DAEMON
+ #endif
+ #ifndef LOG_AUTHPRIV
+ #define LOG_AUTHPRIV LOG_AUTH
+ #endif
+ #ifndef LOG_FTP
+ #define LOG_FTP LOG_DAEMON
+ #endif
+
+ static const int native_facilities[24] =
+ {
+ LOG_KERN,
+ LOG_USER,
+ LOG_MAIL,
+ LOG_DAEMON,
+ LOG_AUTH,
+ LOG_SYSLOG,
+ LOG_LPR,
+ LOG_NEWS,
+ LOG_UUCP,
+ LOG_CRON,
+ LOG_AUTHPRIV,
+ LOG_FTP,
+
+ // reserved values
+ LOG_USER,
+ LOG_USER,
+ LOG_USER,
+ LOG_USER,
+
+ LOG_LOCAL0,
+ LOG_LOCAL1,
+ LOG_LOCAL2,
+ LOG_LOCAL3,
+ LOG_LOCAL4,
+ LOG_LOCAL5,
+ LOG_LOCAL6,
+ LOG_LOCAL7
+ };
+
+ std::size_t n = static_cast< unsigned int >(fac) / 8u;
+ BOOST_ASSERT(n < sizeof(native_facilities) / sizeof(*native_facilities));
+ return native_facilities[n];
+ }
+};
+
+#endif // BOOST_LOG_USE_NATIVE_SYSLOG
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Socket-based implementation
+////////////////////////////////////////////////////////////////////////////////
+
+#if !defined(BOOST_LOG_NO_ASIO)
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ //! The shared UDP socket
+ struct syslog_udp_socket
+ {
+ private:
+ //! The socket primitive
+ asio::ip::udp::socket m_Socket;
+
+ public:
+ //! The constructor creates a socket bound to the specified local address and port
+ explicit syslog_udp_socket(asio::io_context& io_ctx, asio::ip::udp const& protocol, asio::ip::udp::endpoint const& local_address) :
+ m_Socket(io_ctx)
+ {
+ m_Socket.open(protocol);
+ m_Socket.set_option(asio::socket_base::reuse_address(true));
+ m_Socket.bind(local_address);
+ }
+ //! The destructor closes the socket
+ ~syslog_udp_socket()
+ {
+ boost::system::error_code ec;
+ m_Socket.shutdown(asio::socket_base::shutdown_both, ec);
+ m_Socket.close(ec);
+ }
+
+ //! The method sends the syslog message to the specified endpoint
+ void send_message(int pri, const char* local_host_name, asio::ip::udp::endpoint const& target, const char* message);
+
+ BOOST_DELETED_FUNCTION(syslog_udp_socket(syslog_udp_socket const&))
+ BOOST_DELETED_FUNCTION(syslog_udp_socket& operator= (syslog_udp_socket const&))
+ };
+
+ //! The class contains the UDP service for syslog sockets to function
+ class syslog_udp_service :
+ public log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > >
+ {
+ friend class log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > >;
+ typedef log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > > base_type;
+
+ public:
+ //! The IO context instance
+ asio::io_context m_IOContext;
+ //! The local host name to put into log message
+ std::string m_LocalHostName;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! A synchronization primitive to protect the host name resolver
+ mutex m_Mutex;
+ //! The resolver is used to acquire connection endpoints
+ asio::ip::udp::resolver m_HostNameResolver;
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+ private:
+ //! Default constructor
+ syslog_udp_service()
+#if !defined(BOOST_LOG_NO_THREADS)
+ : m_HostNameResolver(m_IOContext)
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ {
+ boost::system::error_code err;
+ m_LocalHostName = asio::ip::host_name(err);
+ }
+ //! Initializes the singleton instance
+ static void init_instance()
+ {
+ base_type::get_instance().reset(new syslog_udp_service());
+ }
+ };
+
+ //! The method sends the syslog message to the specified endpoint
+ void syslog_udp_socket::send_message(
+ int pri, const char* local_host_name, asio::ip::udp::endpoint const& target, const char* message)
+ {
+ std::time_t t = std::time(NULL);
+ std::tm ts;
+ std::tm* time_stamp = boost::date_time::c_time::localtime(&t, &ts);
+
+ // Month will have to be injected separately, as involving locale won't do here
+ static const char months[12][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ // The packet size is mandated in RFC3164, plus one for the terminating zero
+ char packet[1025];
+ int n = boost::log::aux::snprintf
+ (
+ packet,
+ sizeof(packet),
+ "<%d>%s %2d %02d:%02d:%02d %s %s",
+ pri,
+ months[time_stamp->tm_mon],
+ time_stamp->tm_mday,
+ time_stamp->tm_hour,
+ time_stamp->tm_min,
+ time_stamp->tm_sec,
+ local_host_name,
+ message
+ );
+ if (BOOST_LIKELY(n > 0))
+ {
+ std::size_t packet_size = static_cast< std::size_t >(n) >= sizeof(packet) ? sizeof(packet) - 1u : static_cast< std::size_t >(n);
+ m_Socket.send_to(asio::buffer(packet, packet_size), target);
+ }
+ }
+
+} // namespace
+
+struct syslog_backend::implementation::udp_socket_based :
+ public implementation
+{
+ //! Protocol to be used
+ asio::ip::udp m_Protocol;
+ //! Pointer to the list of sockets
+ shared_ptr< syslog_udp_service > m_pService;
+ //! Pointer to the socket being used
+ log::aux::unique_ptr< syslog_udp_socket > m_pSocket;
+ //! The target host to send packets to
+ asio::ip::udp::endpoint m_TargetHost;
+
+ //! Constructor
+ explicit udp_socket_based(syslog::facility const& fac, asio::ip::udp const& protocol) :
+ implementation(fac),
+ m_Protocol(protocol),
+ m_pService(syslog_udp_service::get())
+ {
+ if (m_Protocol == asio::ip::udp::v4())
+ {
+ m_TargetHost = asio::ip::udp::endpoint(asio::ip::address_v4(0x7F000001), 514); // 127.0.0.1:514
+ }
+ else
+ {
+ // ::1, port 514
+ asio::ip::address_v6::bytes_type addr;
+ std::fill_n(addr.data(), addr.size() - 1u, static_cast< unsigned char >(0u));
+ addr[addr.size() - 1u] = 1u;
+ m_TargetHost = asio::ip::udp::endpoint(asio::ip::address_v6(addr), 514);
+ }
+ }
+
+ //! The method sends the formatted message to the syslog host
+ void send(syslog::level lev, string_type const& formatted_message)
+ {
+ if (!m_pSocket.get())
+ {
+ asio::ip::udp::endpoint any_local_address;
+ m_pSocket.reset(new syslog_udp_socket(m_pService->m_IOContext, m_Protocol, any_local_address));
+ }
+
+ m_pSocket->send_message(
+ this->m_Facility | static_cast< int >(lev),
+ m_pService->m_LocalHostName.c_str(),
+ m_TargetHost,
+ formatted_message.c_str());
+ }
+};
+
+#endif // !defined(BOOST_LOG_NO_ASIO)
+
+////////////////////////////////////////////////////////////////////////////////
+// Sink backend implementation
+////////////////////////////////////////////////////////////////////////////////
+BOOST_LOG_API syslog_backend::syslog_backend()
+{
+ construct(log::aux::empty_arg_list());
+}
+
+//! Destructor
+BOOST_LOG_API syslog_backend::~syslog_backend()
+{
+ delete m_pImpl;
+}
+
+//! The method installs the function object that maps application severity levels to Syslog levels
+BOOST_LOG_API void syslog_backend::set_severity_mapper(severity_mapper_type const& mapper)
+{
+ m_pImpl->m_LevelMapper = mapper;
+}
+
+//! The method writes the message to the sink
+BOOST_LOG_API void syslog_backend::consume(record_view const& rec, string_type const& formatted_message)
+{
+ m_pImpl->send(
+ m_pImpl->m_LevelMapper.empty() ? syslog::info : m_pImpl->m_LevelMapper(rec),
+ formatted_message);
+}
+
+
+//! The method creates the backend implementation
+BOOST_LOG_API void syslog_backend::construct(syslog::facility fac, syslog::impl_types use_impl, ip_versions ip_version, std::string const& ident)
+{
+#ifdef BOOST_LOG_USE_NATIVE_SYSLOG
+ if (use_impl == syslog::native)
+ {
+ typedef implementation::native native_impl;
+ m_pImpl = new native_impl(fac, ident);
+ return;
+ }
+#endif // BOOST_LOG_USE_NATIVE_SYSLOG
+
+#if !defined(BOOST_LOG_NO_ASIO)
+ typedef implementation::udp_socket_based udp_socket_based_impl;
+ switch (ip_version)
+ {
+ case v4:
+ m_pImpl = new udp_socket_based_impl(fac, asio::ip::udp::v4());
+ break;
+ case v6:
+ m_pImpl = new udp_socket_based_impl(fac, asio::ip::udp::v6());
+ break;
+ default:
+ BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified");
+ }
+#endif
+}
+
+#if !defined(BOOST_LOG_NO_ASIO)
+
+//! The method sets the local address which log records will be sent from.
+BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, unsigned short port)
+{
+#if !defined(BOOST_LOG_NO_THREADS)
+ typedef implementation::udp_socket_based udp_socket_based_impl;
+ if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl))
+ {
+ char service_name[std::numeric_limits< int >::digits10 + 3];
+ boost::log::aux::snprintf(service_name, sizeof(service_name), "%d", static_cast< int >(port));
+
+ asio::ip::udp::endpoint local_address;
+ {
+ lock_guard< mutex > lock(impl->m_pService->m_Mutex);
+ asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve
+ (
+ addr,
+ service_name,
+ asio::ip::resolver_base::address_configured | asio::ip::resolver_base::passive
+ );
+
+ local_address = *results.cbegin();
+ }
+
+ impl->m_pSocket.reset(new syslog_udp_socket(impl->m_pService->m_IOContext, impl->m_Protocol, local_address));
+ }
+#else
+ // Boost.ASIO requires threads for the host name resolver,
+ // so without threads we simply assume the string already contains IP address
+ set_local_address(boost::asio::ip::address::from_string(addr), port);
+#endif // !defined(BOOST_LOG_NO_THREADS)
+}
+//! The method sets the local address which log records will be sent from.
+BOOST_LOG_API void syslog_backend::set_local_address(boost::asio::ip::address const& addr, unsigned short port)
+{
+ typedef implementation::udp_socket_based udp_socket_based_impl;
+ if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl))
+ {
+ impl->m_pSocket.reset(new syslog_udp_socket(
+ impl->m_pService->m_IOContext, impl->m_Protocol, asio::ip::udp::endpoint(addr, port)));
+ }
+}
+
+//! The method sets the address of the remote host where log records will be sent to.
+BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, unsigned short port)
+{
+#if !defined(BOOST_LOG_NO_THREADS)
+ typedef implementation::udp_socket_based udp_socket_based_impl;
+ if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl))
+ {
+ char service_name[std::numeric_limits< int >::digits10 + 3];
+ boost::log::aux::snprintf(service_name, sizeof(service_name), "%d", static_cast< int >(port));
+
+ asio::ip::udp::endpoint remote_address;
+ {
+ lock_guard< mutex > lock(impl->m_pService->m_Mutex);
+ asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve
+ (
+ addr,
+ service_name,
+ asio::ip::resolver_query_base::address_configured
+ );
+
+ remote_address = *results.cbegin();
+ }
+
+ impl->m_TargetHost = remote_address;
+ }
+#else
+ // Boost.ASIO requires threads for the host name resolver,
+ // so without threads we simply assume the string already contains IP address
+ set_target_address(boost::asio::ip::address::from_string(addr), port);
+#endif // !defined(BOOST_LOG_NO_THREADS)
+}
+//! The method sets the address of the remote host where log records will be sent to.
+BOOST_LOG_API void syslog_backend::set_target_address(boost::asio::ip::address const& addr, unsigned short port)
+{
+ typedef implementation::udp_socket_based udp_socket_based_impl;
+ if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl))
+ {
+ impl->m_TargetHost = asio::ip::udp::endpoint(addr, port);
+ }
+}
+
+#endif // !defined(BOOST_LOG_NO_ASIO)
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_WITHOUT_SYSLOG)
diff --git a/src/boost/libs/log/src/text_file_backend.cpp b/src/boost/libs/log/src/text_file_backend.cpp
new file mode 100644
index 000000000..f71f832d9
--- /dev/null
+++ b/src/boost/libs/log/src/text_file_backend.cpp
@@ -0,0 +1,1569 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file text_file_backend.cpp
+ * \author Andrey Semashev
+ * \date 09.06.2009
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <ctime>
+#include <cctype>
+#include <cwctype>
+#include <ctime>
+#include <cstdio>
+#include <cstdlib>
+#include <cstddef>
+#include <list>
+#include <string>
+#include <locale>
+#include <ostream>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include <stdexcept>
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/filesystem/directory.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/list_hook.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+#include <boost/spirit/home/qi/numeric/numeric_utils.hpp>
+#include <boost/log/detail/singleton.hpp>
+#include <boost/log/detail/light_function.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/attributes/time_traits.hpp>
+#include <boost/log/sinks/auto_newline_mode.hpp>
+#include <boost/log/sinks/text_file_backend.hpp>
+#include "unique_ptr.hpp"
+
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/thread/locks.hpp>
+#include <boost/thread/mutex.hpp>
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+#include <boost/log/detail/header.hpp>
+
+namespace qi = boost::spirit::qi;
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ typedef filesystem::filesystem_error filesystem_error;
+
+ //! A possible Boost.Filesystem extension - renames or moves the file to the target storage
+ inline void move_file(
+ filesystem::path const& from,
+ filesystem::path const& to)
+ {
+#if defined(BOOST_WINDOWS_API)
+ // On Windows MoveFile already does what we need
+ filesystem::rename(from, to);
+#else
+ // On POSIX rename fails if the target points to a different device
+ system::error_code ec;
+ filesystem::rename(from, to, ec);
+ if (ec)
+ {
+ if (BOOST_LIKELY(ec.value() == system::errc::cross_device_link))
+ {
+ // Attempt to manually move the file instead
+ filesystem::copy_file(from, to);
+ filesystem::remove(from);
+ }
+ else
+ {
+ BOOST_THROW_EXCEPTION(filesystem_error("failed to move file to another location", from, to, ec));
+ }
+ }
+#endif
+ }
+
+ typedef filesystem::path::string_type path_string_type;
+ typedef path_string_type::value_type path_char_type;
+
+ //! An auxiliary traits that contain various constants and functions regarding string and character operations
+ template< typename CharT >
+ struct file_char_traits;
+
+ template< >
+ struct file_char_traits< char >
+ {
+ typedef char char_type;
+
+ static const char_type percent = '%';
+ static const char_type number_placeholder = 'N';
+ static const char_type day_placeholder = 'd';
+ static const char_type month_placeholder = 'm';
+ static const char_type year_placeholder = 'y';
+ static const char_type full_year_placeholder = 'Y';
+ static const char_type frac_sec_placeholder = 'f';
+ static const char_type seconds_placeholder = 'S';
+ static const char_type minutes_placeholder = 'M';
+ static const char_type hours_placeholder = 'H';
+ static const char_type space = ' ';
+ static const char_type plus = '+';
+ static const char_type minus = '-';
+ static const char_type zero = '0';
+ static const char_type dot = '.';
+ static const char_type newline = '\n';
+
+ static bool is_digit(char c)
+ {
+ using namespace std;
+ return (isdigit(c) != 0);
+ }
+ static std::string default_file_name_pattern() { return "%5N.log"; }
+ };
+
+#ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+ const file_char_traits< char >::char_type file_char_traits< char >::percent;
+ const file_char_traits< char >::char_type file_char_traits< char >::number_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::day_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::month_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::year_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::full_year_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::frac_sec_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::seconds_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::minutes_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::hours_placeholder;
+ const file_char_traits< char >::char_type file_char_traits< char >::space;
+ const file_char_traits< char >::char_type file_char_traits< char >::plus;
+ const file_char_traits< char >::char_type file_char_traits< char >::minus;
+ const file_char_traits< char >::char_type file_char_traits< char >::zero;
+ const file_char_traits< char >::char_type file_char_traits< char >::dot;
+ const file_char_traits< char >::char_type file_char_traits< char >::newline;
+#endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+
+ template< >
+ struct file_char_traits< wchar_t >
+ {
+ typedef wchar_t char_type;
+
+ static const char_type percent = L'%';
+ static const char_type number_placeholder = L'N';
+ static const char_type day_placeholder = L'd';
+ static const char_type month_placeholder = L'm';
+ static const char_type year_placeholder = L'y';
+ static const char_type full_year_placeholder = L'Y';
+ static const char_type frac_sec_placeholder = L'f';
+ static const char_type seconds_placeholder = L'S';
+ static const char_type minutes_placeholder = L'M';
+ static const char_type hours_placeholder = L'H';
+ static const char_type space = L' ';
+ static const char_type plus = L'+';
+ static const char_type minus = L'-';
+ static const char_type zero = L'0';
+ static const char_type dot = L'.';
+ static const char_type newline = L'\n';
+
+ static bool is_digit(wchar_t c)
+ {
+ using namespace std;
+ return (iswdigit(c) != 0);
+ }
+ static std::wstring default_file_name_pattern() { return L"%5N.log"; }
+ };
+
+#ifndef BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::percent;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::number_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::day_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::month_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::year_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::full_year_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::frac_sec_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::seconds_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::minutes_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::hours_placeholder;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::space;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::plus;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::minus;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::zero;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::dot;
+ const file_char_traits< wchar_t >::char_type file_char_traits< wchar_t >::newline;
+#endif // BOOST_LOG_BROKEN_STATIC_CONSTANTS_LINKAGE
+
+ //! Date and time formatter
+ class date_and_time_formatter
+ {
+ public:
+ typedef path_string_type result_type;
+
+ private:
+ typedef date_time::time_facet< posix_time::ptime, path_char_type > time_facet_type;
+
+ private:
+ mutable time_facet_type m_Facet;
+ mutable std::basic_ostringstream< path_char_type > m_Stream;
+
+ public:
+ //! Constructor
+ date_and_time_formatter() : m_Facet(1u)
+ {
+ }
+ //! Copy constructor
+ date_and_time_formatter(date_and_time_formatter const& that) : m_Facet(1u)
+ {
+ }
+ //! The method formats the current date and time according to the format string str and writes the result into it
+ path_string_type operator()(path_string_type const& pattern, unsigned int counter) const
+ {
+ m_Facet.format(pattern.c_str());
+ m_Stream.str(path_string_type());
+ // Note: the regular operator<< fails because std::use_facet fails to find the facet in the locale because
+ // the facet type in Boost.DateTime has hidden visibility. See this ticket:
+ // https://svn.boost.org/trac/boost/ticket/11707
+ std::ostreambuf_iterator< path_char_type > sbuf_it(m_Stream);
+ m_Facet.put(sbuf_it, m_Stream, m_Stream.fill(), boost::log::attributes::local_time_traits::get_clock());
+ if (m_Stream.good())
+ {
+ return m_Stream.str();
+ }
+ else
+ {
+ m_Stream.clear();
+ return pattern;
+ }
+ }
+
+ BOOST_DELETED_FUNCTION(date_and_time_formatter& operator= (date_and_time_formatter const&))
+ };
+
+ //! The functor formats the file counter into the file name
+ class file_counter_formatter
+ {
+ public:
+ typedef path_string_type result_type;
+
+ private:
+ //! The position in the pattern where the file counter placeholder is
+ path_string_type::size_type m_FileCounterPosition;
+ //! File counter width
+ std::streamsize m_Width;
+ //! The file counter formatting stream
+ mutable std::basic_ostringstream< path_char_type > m_Stream;
+
+ public:
+ //! Initializing constructor
+ file_counter_formatter(path_string_type::size_type pos, unsigned int width) :
+ m_FileCounterPosition(pos),
+ m_Width(width)
+ {
+ typedef file_char_traits< path_char_type > traits_t;
+ m_Stream.fill(traits_t::zero);
+ }
+ //! Copy constructor
+ file_counter_formatter(file_counter_formatter const& that) :
+ m_FileCounterPosition(that.m_FileCounterPosition),
+ m_Width(that.m_Width)
+ {
+ m_Stream.fill(that.m_Stream.fill());
+ }
+
+ //! The function formats the file counter into the file name
+ path_string_type operator()(path_string_type const& pattern, unsigned int counter) const
+ {
+ path_string_type file_name = pattern;
+
+ m_Stream.str(path_string_type());
+ m_Stream.width(m_Width);
+ m_Stream << counter;
+ file_name.insert(m_FileCounterPosition, m_Stream.str());
+
+ return file_name;
+ }
+
+ BOOST_DELETED_FUNCTION(file_counter_formatter& operator= (file_counter_formatter const&))
+ };
+
+ //! The function returns the pattern as the file name
+ class empty_formatter
+ {
+ public:
+ typedef path_string_type result_type;
+
+ private:
+ path_string_type m_Pattern;
+
+ public:
+ //! Initializing constructor
+ explicit empty_formatter(path_string_type const& pattern) : m_Pattern(pattern)
+ {
+ }
+ //! Copy constructor
+ empty_formatter(empty_formatter const& that) : m_Pattern(that.m_Pattern)
+ {
+ }
+
+ //! The function returns the pattern as the file name
+ path_string_type const& operator() (unsigned int) const
+ {
+ return m_Pattern;
+ }
+
+ BOOST_DELETED_FUNCTION(empty_formatter& operator= (empty_formatter const&))
+ };
+
+ //! The function parses the format placeholder for file counter
+ bool parse_counter_placeholder(path_string_type::const_iterator& it, path_string_type::const_iterator end, unsigned int& width)
+ {
+ typedef qi::extract_uint< unsigned int, 10, 1, -1 > width_extract;
+ typedef file_char_traits< path_char_type > traits_t;
+ if (it == end)
+ return false;
+
+ path_char_type c = *it;
+ if (c == traits_t::zero || c == traits_t::space || c == traits_t::plus || c == traits_t::minus)
+ {
+ // Skip filler and alignment specification
+ ++it;
+ if (it == end)
+ return false;
+ c = *it;
+ }
+
+ if (traits_t::is_digit(c))
+ {
+ // Parse width
+ if (!width_extract::call(it, end, width))
+ return false;
+ if (it == end)
+ return false;
+ c = *it;
+ }
+
+ if (c == traits_t::dot)
+ {
+ // Skip precision
+ ++it;
+ while (it != end && traits_t::is_digit(*it))
+ ++it;
+ if (it == end)
+ return false;
+ c = *it;
+ }
+
+ if (c == traits_t::number_placeholder)
+ {
+ ++it;
+ return true;
+ }
+
+ return false;
+ }
+
+ //! The function matches the file name and the pattern
+ bool match_pattern(path_string_type const& file_name, path_string_type const& pattern, unsigned int& file_counter, bool& file_counter_parsed)
+ {
+ typedef qi::extract_uint< unsigned int, 10, 1, -1 > file_counter_extract;
+ typedef file_char_traits< path_char_type > traits_t;
+
+ struct local
+ {
+ // Verifies that the string contains exactly n digits
+ static bool scan_digits(path_string_type::const_iterator& it, path_string_type::const_iterator end, std::ptrdiff_t n)
+ {
+ for (; n > 0; --n)
+ {
+ if (it == end)
+ return false;
+ path_char_type c = *it++;
+ if (!traits_t::is_digit(c))
+ return false;
+ }
+ return true;
+ }
+ };
+
+ path_string_type::const_iterator
+ f_it = file_name.begin(),
+ f_end = file_name.end(),
+ p_it = pattern.begin(),
+ p_end = pattern.end();
+ bool placeholder_expected = false;
+ while (f_it != f_end && p_it != p_end)
+ {
+ path_char_type p_c = *p_it, f_c = *f_it;
+ if (!placeholder_expected)
+ {
+ if (p_c == traits_t::percent)
+ {
+ placeholder_expected = true;
+ ++p_it;
+ }
+ else if (p_c == f_c)
+ {
+ ++p_it;
+ ++f_it;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ switch (p_c)
+ {
+ case traits_t::percent: // An escaped '%'
+ if (p_c == f_c)
+ {
+ ++p_it;
+ ++f_it;
+ break;
+ }
+ else
+ return false;
+
+ case traits_t::seconds_placeholder: // Date/time components with 2-digits width
+ case traits_t::minutes_placeholder:
+ case traits_t::hours_placeholder:
+ case traits_t::day_placeholder:
+ case traits_t::month_placeholder:
+ case traits_t::year_placeholder:
+ if (!local::scan_digits(f_it, f_end, 2))
+ return false;
+ ++p_it;
+ break;
+
+ case traits_t::full_year_placeholder: // Date/time components with 4-digits width
+ if (!local::scan_digits(f_it, f_end, 4))
+ return false;
+ ++p_it;
+ break;
+
+ case traits_t::frac_sec_placeholder: // Fraction seconds width is configuration-dependent
+ typedef posix_time::time_res_traits posix_resolution_traits;
+ if (!local::scan_digits(f_it, f_end, posix_resolution_traits::num_fractional_digits()))
+ {
+ return false;
+ }
+ ++p_it;
+ break;
+
+ default: // This should be the file counter placeholder or some unsupported placeholder
+ {
+ path_string_type::const_iterator p = p_it;
+ unsigned int width = 0;
+ if (!parse_counter_placeholder(p, p_end, width))
+ {
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported placeholder used in pattern for file scanning"));
+ }
+
+ // Find where the file number ends
+ path_string_type::const_iterator f = f_it;
+ if (!local::scan_digits(f, f_end, width))
+ return false;
+ while (f != f_end && traits_t::is_digit(*f))
+ ++f;
+
+ if (!file_counter_extract::call(f_it, f, file_counter))
+ return false;
+
+ file_counter_parsed = true;
+ p_it = p;
+ }
+ break;
+ }
+
+ placeholder_expected = false;
+ }
+ }
+
+ if (p_it == p_end)
+ {
+ if (f_it != f_end)
+ {
+ // The actual file name may end with an additional counter
+ // that is added by the collector in case if file name clash
+ return local::scan_digits(f_it, f_end, std::distance(f_it, f_end));
+ }
+ else
+ return true;
+ }
+ else
+ return false;
+ }
+
+ //! The function parses file name pattern and splits it into path and filename and creates a function object that will generate the actual filename from the pattern
+ void parse_file_name_pattern(filesystem::path const& pattern, filesystem::path& storage_dir, filesystem::path& file_name_pattern, boost::log::aux::light_function< path_string_type (unsigned int) >& file_name_generator)
+ {
+ // Note: avoid calling Boost.Filesystem functions that involve path::codecvt()
+ // https://svn.boost.org/trac/boost/ticket/9119
+
+ typedef file_char_traits< path_char_type > traits_t;
+
+ file_name_pattern = pattern.filename();
+ path_string_type name_pattern = file_name_pattern.native();
+ storage_dir = filesystem::absolute(pattern.parent_path());
+
+ // Let's try to find the file counter placeholder
+ unsigned int placeholder_count = 0;
+ unsigned int width = 0;
+ bool counter_found = false;
+ path_string_type::size_type counter_pos = 0;
+ path_string_type::const_iterator end = name_pattern.end();
+ path_string_type::const_iterator it = name_pattern.begin();
+
+ do
+ {
+ it = std::find(it, end, traits_t::percent);
+ if (it == end)
+ break;
+ path_string_type::const_iterator placeholder_begin = it++;
+ if (it == end)
+ break;
+ if (*it == traits_t::percent)
+ {
+ // An escaped percent detected
+ ++it;
+ continue;
+ }
+
+ ++placeholder_count;
+
+ if (!counter_found)
+ {
+ path_string_type::const_iterator it2 = it;
+ if (parse_counter_placeholder(it2, end, width))
+ {
+ // We've found the file counter placeholder in the pattern
+ counter_found = true;
+ counter_pos = placeholder_begin - name_pattern.begin();
+ name_pattern.erase(counter_pos, it2 - placeholder_begin);
+ --placeholder_count;
+ it = name_pattern.begin() + counter_pos;
+ end = name_pattern.end();
+ }
+ }
+ }
+ while (it != end);
+
+ // Construct the formatter functor
+ if (placeholder_count > 0)
+ {
+ if (counter_found)
+ {
+ // Both counter and date/time placeholder in the pattern
+ file_name_generator = boost::bind(date_and_time_formatter(),
+ boost::bind(file_counter_formatter(counter_pos, width), name_pattern, boost::placeholders::_1), boost::placeholders::_1);
+ }
+ else
+ {
+ // Only date/time placeholders in the pattern
+ file_name_generator = boost::bind(date_and_time_formatter(), name_pattern, boost::placeholders::_1);
+ }
+ }
+ else if (counter_found)
+ {
+ // Only counter placeholder in the pattern
+ file_name_generator = boost::bind(file_counter_formatter(counter_pos, width), name_pattern, boost::placeholders::_1);
+ }
+ else
+ {
+ // No placeholders detected
+ file_name_generator = empty_formatter(name_pattern);
+ }
+ }
+
+
+ class file_collector_repository;
+
+ //! Type of the hook used for sequencing file collectors
+ typedef intrusive::list_base_hook<
+ intrusive::link_mode< intrusive::safe_link >
+ > file_collector_hook;
+
+ //! Log file collector implementation
+ class file_collector :
+ public file::collector,
+ public file_collector_hook,
+ public enable_shared_from_this< file_collector >
+ {
+ private:
+ //! Information about a single stored file
+ struct file_info
+ {
+ uintmax_t m_Size;
+ std::time_t m_TimeStamp;
+ filesystem::path m_Path;
+ };
+ //! A list of the stored files
+ typedef std::list< file_info > file_list;
+ //! The string type compatible with the universal path type
+ typedef filesystem::path::string_type path_string_type;
+
+ private:
+ //! A reference to the repository this collector belongs to
+ shared_ptr< file_collector_repository > m_pRepository;
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex
+ mutex m_Mutex;
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+ //! Total file size upper limit
+ uintmax_t m_MaxSize;
+ //! Free space lower limit
+ uintmax_t m_MinFreeSpace;
+ //! File count upper limit
+ uintmax_t m_MaxFiles;
+
+ //! The current path at the point when the collector is created
+ /*
+ * The special member is required to calculate absolute paths with no
+ * dependency on the current path for the application, which may change
+ */
+ const filesystem::path m_BasePath;
+ //! Target directory to store files to
+ filesystem::path m_StorageDir;
+
+ //! The list of stored files
+ file_list m_Files;
+ //! Total size of the stored files
+ uintmax_t m_TotalSize;
+
+ public:
+ //! Constructor
+ file_collector(
+ shared_ptr< file_collector_repository > const& repo,
+ filesystem::path const& target_dir,
+ uintmax_t max_size,
+ uintmax_t min_free_space,
+ uintmax_t max_files);
+
+ //! Destructor
+ ~file_collector();
+
+ //! The function stores the specified file in the storage
+ void store_file(filesystem::path const& file_name);
+
+ //! Scans the target directory for the files that have already been stored
+ uintmax_t scan_for_files(
+ file::scan_method method, filesystem::path const& pattern, unsigned int* counter);
+
+ //! The function updates storage restrictions
+ void update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files);
+
+ //! The function checks if the directory is governed by this collector
+ bool is_governed(filesystem::path const& dir) const
+ {
+ return filesystem::equivalent(m_StorageDir, dir);
+ }
+
+ private:
+ //! Makes relative path absolute with respect to the base path
+ filesystem::path make_absolute(filesystem::path const& p)
+ {
+ return filesystem::absolute(p, m_BasePath);
+ }
+ //! Acquires file name string from the path
+ static path_string_type filename_string(filesystem::path const& p)
+ {
+ return p.filename().string< path_string_type >();
+ }
+ };
+
+
+ //! The singleton of the list of file collectors
+ class file_collector_repository :
+ public log::aux::lazy_singleton< file_collector_repository, shared_ptr< file_collector_repository > >
+ {
+ private:
+ //! Base type
+ typedef log::aux::lazy_singleton< file_collector_repository, shared_ptr< file_collector_repository > > base_type;
+
+#if !defined(BOOST_LOG_BROKEN_FRIEND_TEMPLATE_SPECIALIZATIONS)
+ friend class log::aux::lazy_singleton< file_collector_repository, shared_ptr< file_collector_repository > >;
+#else
+ friend class base_type;
+#endif
+
+ //! The type of the list of collectors
+ typedef intrusive::list<
+ file_collector,
+ intrusive::base_hook< file_collector_hook >
+ > file_collectors;
+
+ private:
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex
+ mutex m_Mutex;
+#endif // !defined(BOOST_LOG_NO_THREADS)
+ //! The list of file collectors
+ file_collectors m_Collectors;
+
+ public:
+ //! Finds or creates a file collector
+ shared_ptr< file::collector > get_collector(
+ filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files);
+
+ //! Removes the file collector from the list
+ void remove_collector(file_collector* p);
+
+ private:
+ //! Initializes the singleton instance
+ static void init_instance()
+ {
+ base_type::get_instance() = boost::make_shared< file_collector_repository >();
+ }
+ };
+
+ //! Constructor
+ file_collector::file_collector(
+ shared_ptr< file_collector_repository > const& repo,
+ filesystem::path const& target_dir,
+ uintmax_t max_size,
+ uintmax_t min_free_space,
+ uintmax_t max_files
+ ) :
+ m_pRepository(repo),
+ m_MaxSize(max_size),
+ m_MinFreeSpace(min_free_space),
+ m_MaxFiles(max_files),
+ m_BasePath(filesystem::current_path()),
+ m_TotalSize(0)
+ {
+ m_StorageDir = make_absolute(target_dir);
+ filesystem::create_directories(m_StorageDir);
+ }
+
+ //! Destructor
+ file_collector::~file_collector()
+ {
+ m_pRepository->remove_collector(this);
+ }
+
+ //! The function stores the specified file in the storage
+ void file_collector::store_file(filesystem::path const& src_path)
+ {
+ // NOTE FOR THE FOLLOWING CODE:
+ // Avoid using Boost.Filesystem functions that would call path::codecvt(). store_file() can be called
+ // at process termination, and the global codecvt facet can already be destroyed at this point.
+ // https://svn.boost.org/trac/boost/ticket/8642
+
+ // Let's construct the new file name
+ file_info info;
+ info.m_TimeStamp = filesystem::last_write_time(src_path);
+ info.m_Size = filesystem::file_size(src_path);
+
+ filesystem::path file_name_path = src_path.filename();
+ path_string_type file_name = file_name_path.native();
+ info.m_Path = m_StorageDir / file_name_path;
+
+ // Check if the file is already in the target directory
+ filesystem::path src_dir = src_path.has_parent_path() ?
+ filesystem::system_complete(src_path.parent_path()) :
+ m_BasePath;
+ const bool is_in_target_dir = filesystem::equivalent(src_dir, m_StorageDir);
+ if (!is_in_target_dir)
+ {
+ if (filesystem::exists(info.m_Path))
+ {
+ // If the file already exists, try to mangle the file name
+ // to ensure there's no conflict. I'll need to make this customizable some day.
+ file_counter_formatter formatter(file_name.size(), 5);
+ unsigned int n = 0;
+ while (true)
+ {
+ path_string_type alt_file_name = formatter(file_name, n);
+ info.m_Path = m_StorageDir / filesystem::path(alt_file_name);
+ if (!filesystem::exists(info.m_Path))
+ break;
+
+ if (BOOST_UNLIKELY(n == (std::numeric_limits< unsigned int >::max)()))
+ {
+ BOOST_THROW_EXCEPTION(filesystem_error(
+ "Target file exists and an unused fallback file name could not be found",
+ info.m_Path,
+ system::error_code(system::errc::io_error, system::generic_category())));
+ }
+
+ ++n;
+ }
+ }
+
+ // The directory should have been created in constructor, but just in case it got deleted since then...
+ filesystem::create_directories(m_StorageDir);
+ }
+
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);)
+
+ file_list::iterator it = m_Files.begin();
+ const file_list::iterator end = m_Files.end();
+ if (is_in_target_dir)
+ {
+ // If the sink writes log file into the target dir (is_in_target_dir == true), it is possible that after scanning
+ // an old file entry refers to the file that is picked up by the sink for writing. Later on, the sink attempts
+ // to store the file in the storage. At best, this would result in duplicate file entries. At worst, if the storage
+ // limits trigger a deletion and this file get deleted, we may have an entry that refers to no actual file. In any case,
+ // the total size of files in the storage will be incorrect. Here we work around this problem and simply remove
+ // the old file entry without removing the file. The entry will be re-added to the list later.
+ while (it != end)
+ {
+ system::error_code ec;
+ if (filesystem::equivalent(it->m_Path, info.m_Path, ec))
+ {
+ m_TotalSize -= it->m_Size;
+ m_Files.erase(it);
+ break;
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ it = m_Files.begin();
+ }
+
+ // Check if an old file should be erased
+ uintmax_t free_space = m_MinFreeSpace ? filesystem::space(m_StorageDir).available : static_cast< uintmax_t >(0);
+ while (it != end &&
+ (m_TotalSize + info.m_Size > m_MaxSize || (m_MinFreeSpace && m_MinFreeSpace > free_space) || m_MaxFiles <= m_Files.size()))
+ {
+ file_info& old_info = *it;
+ system::error_code ec;
+ filesystem::file_status status = filesystem::status(old_info.m_Path, ec);
+
+ if (status.type() == filesystem::regular_file)
+ {
+ try
+ {
+ filesystem::remove(old_info.m_Path);
+ // Free space has to be queried as it may not increase equally
+ // to the erased file size on compressed filesystems
+ if (m_MinFreeSpace)
+ free_space = filesystem::space(m_StorageDir).available;
+ m_TotalSize -= old_info.m_Size;
+ m_Files.erase(it++);
+ }
+ catch (system::system_error&)
+ {
+ // Can't erase the file. Maybe it's locked? Never mind...
+ ++it;
+ }
+ }
+ else
+ {
+ // If it's not a file or is absent, just remove it from the list
+ m_TotalSize -= old_info.m_Size;
+ m_Files.erase(it++);
+ }
+ }
+
+ if (!is_in_target_dir)
+ {
+ // Move/rename the file to the target storage
+ move_file(src_path, info.m_Path);
+ }
+
+ m_Files.push_back(info);
+ m_TotalSize += info.m_Size;
+ }
+
+ //! Scans the target directory for the files that have already been stored
+ uintmax_t file_collector::scan_for_files(
+ file::scan_method method, filesystem::path const& pattern, unsigned int* counter)
+ {
+ uintmax_t file_count = 0;
+ if (method != file::no_scan)
+ {
+ filesystem::path dir = m_StorageDir;
+ path_string_type mask;
+ if (method == file::scan_matching)
+ {
+ mask = filename_string(pattern);
+ if (pattern.has_parent_path())
+ dir = make_absolute(pattern.parent_path());
+ }
+ else
+ {
+ counter = NULL;
+ }
+
+ system::error_code ec;
+ filesystem::file_status status = filesystem::status(dir, ec);
+ if (status.type() == filesystem::directory_file)
+ {
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);)
+
+ if (counter)
+ *counter = 0;
+
+ file_list files;
+ filesystem::directory_iterator it(dir), end;
+ uintmax_t total_size = 0;
+ for (; it != end; ++it)
+ {
+ filesystem::directory_entry const& dir_entry = *it;
+ file_info info;
+ info.m_Path = dir_entry.path();
+ status = dir_entry.status(ec);
+ if (status.type() == filesystem::regular_file)
+ {
+ // Check that there are no duplicates in the resulting list
+ struct local
+ {
+ static bool equivalent(filesystem::path const& left, file_info const& right)
+ {
+ return filesystem::equivalent(left, right.m_Path);
+ }
+ };
+ if (std::find_if(m_Files.begin(), m_Files.end(),
+ boost::bind(&local::equivalent, boost::cref(info.m_Path), boost::placeholders::_1)) == m_Files.end())
+ {
+ // Check that the file name matches the pattern
+ unsigned int file_number = 0;
+ bool file_number_parsed = false;
+ if (method != file::scan_matching ||
+ match_pattern(filename_string(info.m_Path), mask, file_number, file_number_parsed))
+ {
+ info.m_Size = filesystem::file_size(info.m_Path);
+ total_size += info.m_Size;
+ info.m_TimeStamp = filesystem::last_write_time(info.m_Path);
+ files.push_back(info);
+ ++file_count;
+
+ // Test that the file_number >= *counter accounting for the integer overflow
+ if (file_number_parsed && counter != NULL && (file_number - *counter) < ((~0u) ^ ((~0u) >> 1)))
+ *counter = file_number + 1u;
+ }
+ }
+ }
+ }
+
+ // Sort files chronologically
+ m_Files.splice(m_Files.end(), files);
+ m_TotalSize += total_size;
+ m_Files.sort(boost::bind(&file_info::m_TimeStamp, boost::placeholders::_1) < boost::bind(&file_info::m_TimeStamp, boost::placeholders::_2));
+ }
+ }
+
+ return file_count;
+ }
+
+ //! The function updates storage restrictions
+ void file_collector::update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files)
+ {
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);)
+
+ m_MaxSize = (std::min)(m_MaxSize, max_size);
+ m_MinFreeSpace = (std::max)(m_MinFreeSpace, min_free_space);
+ m_MaxFiles = (std::min)(m_MaxFiles, max_files);
+ }
+
+
+ //! Finds or creates a file collector
+ shared_ptr< file::collector > file_collector_repository::get_collector(
+ filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files)
+ {
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);)
+
+ file_collectors::iterator it = std::find_if(m_Collectors.begin(), m_Collectors.end(),
+ boost::bind(&file_collector::is_governed, boost::placeholders::_1, boost::cref(target_dir)));
+ shared_ptr< file_collector > p;
+ if (it != m_Collectors.end()) try
+ {
+ // This may throw if the collector is being currently destroyed
+ p = it->shared_from_this();
+ p->update(max_size, min_free_space, max_files);
+ }
+ catch (bad_weak_ptr&)
+ {
+ }
+
+ if (!p)
+ {
+ p = boost::make_shared< file_collector >(
+ file_collector_repository::get(), target_dir, max_size, min_free_space, max_files);
+ m_Collectors.push_back(*p);
+ }
+
+ return p;
+ }
+
+ //! Removes the file collector from the list
+ void file_collector_repository::remove_collector(file_collector* p)
+ {
+ BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);)
+ m_Collectors.erase(m_Collectors.iterator_to(*p));
+ }
+
+ //! Checks if the time point is valid
+ void check_time_point_validity(unsigned char hour, unsigned char minute, unsigned char second)
+ {
+ if (BOOST_UNLIKELY(hour >= 24))
+ {
+ std::ostringstream strm;
+ strm << "Time point hours value is out of range: " << static_cast< unsigned int >(hour);
+ BOOST_THROW_EXCEPTION(std::out_of_range(strm.str()));
+ }
+ if (BOOST_UNLIKELY(minute >= 60))
+ {
+ std::ostringstream strm;
+ strm << "Time point minutes value is out of range: " << static_cast< unsigned int >(minute);
+ BOOST_THROW_EXCEPTION(std::out_of_range(strm.str()));
+ }
+ if (BOOST_UNLIKELY(second >= 60))
+ {
+ std::ostringstream strm;
+ strm << "Time point seconds value is out of range: " << static_cast< unsigned int >(second);
+ BOOST_THROW_EXCEPTION(std::out_of_range(strm.str()));
+ }
+ }
+
+} // namespace
+
+namespace file {
+
+namespace aux {
+
+ //! Creates and returns a file collector with the specified parameters
+ BOOST_LOG_API shared_ptr< collector > make_collector(
+ filesystem::path const& target_dir,
+ uintmax_t max_size,
+ uintmax_t min_free_space,
+ uintmax_t max_files)
+ {
+ return file_collector_repository::get()->get_collector(target_dir, max_size, min_free_space, max_files);
+ }
+
+} // namespace aux
+
+//! Creates a rotation time point of every day at the specified time
+BOOST_LOG_API rotation_at_time_point::rotation_at_time_point(
+ unsigned char hour,
+ unsigned char minute,
+ unsigned char second
+) :
+ m_Day(0),
+ m_DayKind(not_specified),
+ m_Hour(hour),
+ m_Minute(minute),
+ m_Second(second),
+ m_Previous(date_time::not_a_date_time)
+{
+ check_time_point_validity(hour, minute, second);
+}
+
+//! Creates a rotation time point of each specified weekday at the specified time
+BOOST_LOG_API rotation_at_time_point::rotation_at_time_point(
+ date_time::weekdays wday,
+ unsigned char hour,
+ unsigned char minute,
+ unsigned char second
+) :
+ m_Day(static_cast< unsigned char >(wday)),
+ m_DayKind(weekday),
+ m_Hour(hour),
+ m_Minute(minute),
+ m_Second(second),
+ m_Previous(date_time::not_a_date_time)
+{
+ check_time_point_validity(hour, minute, second);
+}
+
+//! Creates a rotation time point of each specified day of month at the specified time
+BOOST_LOG_API rotation_at_time_point::rotation_at_time_point(
+ gregorian::greg_day mday,
+ unsigned char hour,
+ unsigned char minute,
+ unsigned char second
+) :
+ m_Day(static_cast< unsigned char >(mday.as_number())),
+ m_DayKind(monthday),
+ m_Hour(hour),
+ m_Minute(minute),
+ m_Second(second),
+ m_Previous(date_time::not_a_date_time)
+{
+ check_time_point_validity(hour, minute, second);
+}
+
+//! Checks if it's time to rotate the file
+BOOST_LOG_API bool rotation_at_time_point::operator()() const
+{
+ bool result = false;
+ posix_time::time_duration rotation_time(
+ static_cast< posix_time::time_duration::hour_type >(m_Hour),
+ static_cast< posix_time::time_duration::min_type >(m_Minute),
+ static_cast< posix_time::time_duration::sec_type >(m_Second));
+ posix_time::ptime now = posix_time::second_clock::local_time();
+
+ if (m_Previous.is_special())
+ {
+ m_Previous = now;
+ return false;
+ }
+
+ const bool time_of_day_passed = rotation_time.total_seconds() <= m_Previous.time_of_day().total_seconds();
+ switch (static_cast< day_kind >(m_DayKind))
+ {
+ case not_specified:
+ {
+ // The rotation takes place every day at the specified time
+ gregorian::date previous_date = m_Previous.date();
+ if (time_of_day_passed)
+ previous_date += gregorian::days(1);
+ posix_time::ptime next(previous_date, rotation_time);
+ result = (now >= next);
+ }
+ break;
+
+ case weekday:
+ {
+ // The rotation takes place on the specified week day at the specified time
+ gregorian::date previous_date = m_Previous.date(), next_date = previous_date;
+ int weekday = m_Day, previous_weekday = static_cast< int >(previous_date.day_of_week().as_number());
+ next_date += gregorian::days(weekday - previous_weekday);
+ if (weekday < previous_weekday || (weekday == previous_weekday && time_of_day_passed))
+ {
+ next_date += gregorian::weeks(1);
+ }
+
+ posix_time::ptime next(next_date, rotation_time);
+ result = (now >= next);
+ }
+ break;
+
+ case monthday:
+ {
+ // The rotation takes place on the specified day of month at the specified time
+ gregorian::date previous_date = m_Previous.date();
+ gregorian::date::day_type monthday = static_cast< gregorian::date::day_type >(m_Day),
+ previous_monthday = previous_date.day();
+ gregorian::date next_date(previous_date.year(), previous_date.month(), monthday);
+ if (monthday < previous_monthday || (monthday == previous_monthday && time_of_day_passed))
+ {
+ next_date += gregorian::months(1);
+ }
+
+ posix_time::ptime next(next_date, rotation_time);
+ result = (now >= next);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (result)
+ m_Previous = now;
+
+ return result;
+}
+
+//! Checks if it's time to rotate the file
+BOOST_LOG_API bool rotation_at_time_interval::operator()() const
+{
+ bool result = false;
+ posix_time::ptime now = posix_time::second_clock::universal_time();
+ if (m_Previous.is_special())
+ {
+ m_Previous = now;
+ return false;
+ }
+
+ result = (now - m_Previous) >= m_Interval;
+
+ if (result)
+ m_Previous = now;
+
+ return result;
+}
+
+} // namespace file
+
+////////////////////////////////////////////////////////////////////////////////
+// File sink backend implementation
+////////////////////////////////////////////////////////////////////////////////
+//! Sink implementation data
+struct text_file_backend::implementation
+{
+ //! File open mode
+ std::ios_base::openmode m_FileOpenMode;
+
+ //! File name pattern
+ filesystem::path m_FileNamePattern;
+ //! Directory to store files in
+ filesystem::path m_StorageDir;
+ //! File name generator (according to m_FileNamePattern)
+ boost::log::aux::light_function< path_string_type (unsigned int) > m_FileNameGenerator;
+
+ //! Target file name pattern
+ filesystem::path m_TargetFileNamePattern;
+ //! Target directory to store files in
+ filesystem::path m_TargetStorageDir;
+ //! Target file name generator (according to m_TargetFileNamePattern)
+ boost::log::aux::light_function< path_string_type (unsigned int) > m_TargetFileNameGenerator;
+
+ //! Stored files counter
+ unsigned int m_FileCounter;
+
+ //! Current file name
+ filesystem::path m_FileName;
+ //! File stream
+ filesystem::ofstream m_File;
+ //! Characters written
+ uintmax_t m_CharactersWritten;
+
+ //! File collector functional object
+ shared_ptr< file::collector > m_pFileCollector;
+ //! File open handler
+ open_handler_type m_OpenHandler;
+ //! File close handler
+ close_handler_type m_CloseHandler;
+
+ //! The maximum temp file size, in characters written to the stream
+ uintmax_t m_FileRotationSize;
+ //! Time-based rotation predicate
+ time_based_rotation_predicate m_TimeBasedRotation;
+ //! Indicates whether to append a trailing newline after every log record
+ auto_newline_mode m_AutoNewlineMode;
+ //! The flag shows if every written record should be flushed
+ bool m_AutoFlush;
+ //! The flag indicates whether the final rotation should be performed
+ bool m_FinalRotationEnabled;
+
+ implementation(uintmax_t rotation_size, auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation) :
+ m_FileOpenMode(std::ios_base::trunc | std::ios_base::out),
+ m_FileCounter(0),
+ m_CharactersWritten(0),
+ m_FileRotationSize(rotation_size),
+ m_AutoNewlineMode(auto_newline),
+ m_AutoFlush(auto_flush),
+ m_FinalRotationEnabled(enable_final_rotation)
+ {
+ }
+};
+
+//! Constructor. No streams attached to the constructed backend, auto flush feature disabled.
+BOOST_LOG_API text_file_backend::text_file_backend()
+{
+ construct(log::aux::empty_arg_list());
+}
+
+//! Destructor
+BOOST_LOG_API text_file_backend::~text_file_backend()
+{
+ try
+ {
+ // Attempt to put the temporary file into storage
+ if (m_pImpl->m_FinalRotationEnabled && m_pImpl->m_File.is_open() && m_pImpl->m_CharactersWritten > 0)
+ rotate_file();
+ }
+ catch (...)
+ {
+ }
+
+ delete m_pImpl;
+}
+
+//! Constructor implementation
+BOOST_LOG_API void text_file_backend::construct(
+ filesystem::path const& pattern,
+ filesystem::path const& target_file_name,
+ std::ios_base::openmode mode,
+ uintmax_t rotation_size,
+ time_based_rotation_predicate const& time_based_rotation,
+ auto_newline_mode auto_newline,
+ bool auto_flush,
+ bool enable_final_rotation)
+{
+ m_pImpl = new implementation(rotation_size, auto_newline, auto_flush, enable_final_rotation);
+ set_file_name_pattern_internal(pattern);
+ set_target_file_name_pattern_internal(target_file_name);
+ set_time_based_rotation(time_based_rotation);
+ set_open_mode(mode);
+}
+
+//! The method sets maximum file size.
+BOOST_LOG_API void text_file_backend::set_rotation_size(uintmax_t size)
+{
+ m_pImpl->m_FileRotationSize = size;
+}
+
+//! The method sets the maximum time interval between file rotations.
+BOOST_LOG_API void text_file_backend::set_time_based_rotation(time_based_rotation_predicate const& predicate)
+{
+ m_pImpl->m_TimeBasedRotation = predicate;
+}
+
+//! The method allows to enable or disable log file rotation on sink destruction.
+BOOST_LOG_API void text_file_backend::enable_final_rotation(bool enable)
+{
+ m_pImpl->m_FinalRotationEnabled = enable;
+}
+
+//! Sets the flag to automatically flush write buffers of the file being written after each log record.
+BOOST_LOG_API void text_file_backend::auto_flush(bool enable)
+{
+ m_pImpl->m_AutoFlush = enable;
+}
+
+//! Selects whether a trailing newline should be automatically inserted after every log record.
+BOOST_LOG_API void text_file_backend::set_auto_newline_mode(auto_newline_mode mode)
+{
+ m_pImpl->m_AutoNewlineMode = mode;
+}
+
+//! The method writes the message to the sink
+BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_type const& formatted_message)
+{
+ typedef file_char_traits< string_type::value_type > traits_t;
+
+ filesystem::path prev_file_name;
+ bool use_prev_file_name = false;
+ if (BOOST_UNLIKELY(!m_pImpl->m_File.good()))
+ {
+ // The file stream is not operational. One possible reason is that there is no more free space
+ // on the file system. In this case it is possible that this log record will fail to be written as well,
+ // leaving the newly creted file empty. Eventually this results in lots of empty log files.
+ // We should take precautions to avoid this. https://svn.boost.org/trac/boost/ticket/11016
+ prev_file_name = m_pImpl->m_FileName;
+ close_file();
+
+ system::error_code ec;
+ uintmax_t size = filesystem::file_size(prev_file_name, ec);
+ if (!!ec || size == 0)
+ {
+ // To reuse the empty file avoid re-generating the new file name later
+ use_prev_file_name = true;
+ }
+ else if (!!m_pImpl->m_pFileCollector)
+ {
+ // Complete file rotation
+ m_pImpl->m_pFileCollector->store_file(prev_file_name);
+ }
+ }
+ else if
+ (
+ m_pImpl->m_File.is_open() &&
+ (
+ m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize ||
+ (!m_pImpl->m_TimeBasedRotation.empty() && m_pImpl->m_TimeBasedRotation())
+ )
+ )
+ {
+ rotate_file();
+ }
+
+ if (!m_pImpl->m_File.is_open())
+ {
+ filesystem::path new_file_name;
+ if (!use_prev_file_name)
+ new_file_name = m_pImpl->m_StorageDir / m_pImpl->m_FileNameGenerator(m_pImpl->m_FileCounter++);
+ else
+ prev_file_name.swap(new_file_name);
+
+ filesystem::create_directories(new_file_name.parent_path());
+
+ m_pImpl->m_File.open(new_file_name, m_pImpl->m_FileOpenMode);
+ if (BOOST_UNLIKELY(!m_pImpl->m_File.is_open()))
+ {
+ BOOST_THROW_EXCEPTION(filesystem_error(
+ "Failed to open file for writing",
+ new_file_name,
+ system::error_code(system::errc::io_error, system::generic_category())));
+ }
+ m_pImpl->m_FileName.swap(new_file_name);
+
+ if (!m_pImpl->m_OpenHandler.empty())
+ m_pImpl->m_OpenHandler(m_pImpl->m_File);
+
+ m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp());
+ }
+
+ m_pImpl->m_File.write(formatted_message.data(), static_cast< std::streamsize >(formatted_message.size()));
+ m_pImpl->m_CharactersWritten += formatted_message.size();
+
+ if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline)
+ {
+ if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || *formatted_message.rbegin() != traits_t::newline)
+ {
+ m_pImpl->m_File.put(traits_t::newline);
+ ++m_pImpl->m_CharactersWritten;
+ }
+ }
+
+ if (m_pImpl->m_AutoFlush)
+ m_pImpl->m_File.flush();
+}
+
+//! The method flushes the currently open log file
+BOOST_LOG_API void text_file_backend::flush()
+{
+ if (m_pImpl->m_File.is_open())
+ m_pImpl->m_File.flush();
+}
+
+//! The method sets file name pattern
+BOOST_LOG_API void text_file_backend::set_file_name_pattern_internal(filesystem::path const& pattern)
+{
+ typedef file_char_traits< path_char_type > traits_t;
+
+ parse_file_name_pattern
+ (
+ !pattern.empty() ? pattern : filesystem::path(traits_t::default_file_name_pattern()),
+ m_pImpl->m_StorageDir,
+ m_pImpl->m_FileNamePattern,
+ m_pImpl->m_FileNameGenerator
+ );
+}
+
+//! The method sets target file name pattern
+BOOST_LOG_API void text_file_backend::set_target_file_name_pattern_internal(filesystem::path const& pattern)
+{
+ if (!pattern.empty())
+ {
+ parse_file_name_pattern(pattern, m_pImpl->m_TargetStorageDir, m_pImpl->m_TargetFileNamePattern, m_pImpl->m_TargetFileNameGenerator);
+ }
+ else
+ {
+ m_pImpl->m_TargetStorageDir.clear();
+ m_pImpl->m_TargetFileNamePattern.clear();
+ m_pImpl->m_TargetFileNameGenerator.clear();
+ }
+}
+
+//! Closes the currently open file
+void text_file_backend::close_file()
+{
+ if (m_pImpl->m_File.is_open())
+ {
+ if (!m_pImpl->m_CloseHandler.empty())
+ {
+ // Rationale: We should call the close handler even if the stream is !good() because
+ // writing the footer may not be the only thing the handler does. However, there is
+ // a chance that the file had become writable since the last failure (e.g. there was
+ // no space left to write the last record, but it got freed since then), so if the handler
+ // attempts to write a footer it may succeed now. For this reason we clear the stream state
+ // and let the handler have a try.
+ m_pImpl->m_File.clear();
+ m_pImpl->m_CloseHandler(m_pImpl->m_File);
+ }
+
+ m_pImpl->m_File.close();
+ }
+
+ m_pImpl->m_File.clear();
+ m_pImpl->m_CharactersWritten = 0;
+ m_pImpl->m_FileName.clear();
+}
+
+//! The method rotates the file
+BOOST_LOG_API void text_file_backend::rotate_file()
+{
+ filesystem::path prev_file_name = m_pImpl->m_FileName;
+ close_file();
+
+ // Check if the file has been created in the first place
+ system::error_code ec;
+ filesystem::file_status status = filesystem::status(prev_file_name, ec);
+ if (status.type() == filesystem::regular_file)
+ {
+ if (!!m_pImpl->m_TargetFileNameGenerator)
+ {
+ filesystem::path new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter);
+
+ if (new_file_name != prev_file_name)
+ {
+ filesystem::create_directories(new_file_name.parent_path());
+ move_file(prev_file_name, new_file_name);
+
+ prev_file_name.swap(new_file_name);
+ }
+ }
+
+ if (!!m_pImpl->m_pFileCollector)
+ m_pImpl->m_pFileCollector->store_file(prev_file_name);
+ }
+}
+
+//! The method sets the file open mode
+BOOST_LOG_API void text_file_backend::set_open_mode(std::ios_base::openmode mode)
+{
+ mode |= std::ios_base::out;
+ mode &= ~std::ios_base::in;
+ if ((mode & (std::ios_base::trunc | std::ios_base::app)) == 0)
+ mode |= std::ios_base::trunc;
+ m_pImpl->m_FileOpenMode = mode;
+}
+
+//! The method sets file collector
+BOOST_LOG_API void text_file_backend::set_file_collector(shared_ptr< file::collector > const& collector)
+{
+ m_pImpl->m_pFileCollector = collector;
+}
+
+//! The method sets file open handler
+BOOST_LOG_API void text_file_backend::set_open_handler(open_handler_type const& handler)
+{
+ m_pImpl->m_OpenHandler = handler;
+}
+
+//! The method sets file close handler
+BOOST_LOG_API void text_file_backend::set_close_handler(close_handler_type const& handler)
+{
+ m_pImpl->m_CloseHandler = handler;
+}
+
+//! The method returns name of the currently open log file. If no file is open, returns an empty path.
+BOOST_LOG_API filesystem::path text_file_backend::get_current_file_name() const
+{
+ return m_pImpl->m_FileName;
+}
+
+//! Performs scanning of the target directory for log files
+BOOST_LOG_API uintmax_t text_file_backend::scan_for_files(file::scan_method method, bool update_counter)
+{
+ if (BOOST_LIKELY(!!m_pImpl->m_pFileCollector))
+ {
+ unsigned int* counter = update_counter ? &m_pImpl->m_FileCounter : static_cast< unsigned int* >(NULL);
+ return m_pImpl->m_pFileCollector->scan_for_files
+ (
+ method,
+ m_pImpl->m_TargetFileNamePattern.empty() ? m_pImpl->m_FileNamePattern : m_pImpl->m_TargetFileNamePattern,
+ counter
+ );
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR(setup_error, "File collector is not set");
+ }
+}
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/text_multifile_backend.cpp b/src/boost/libs/log/src/text_multifile_backend.cpp
new file mode 100644
index 000000000..550dd57f6
--- /dev/null
+++ b/src/boost/libs/log/src/text_multifile_backend.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file text_multifile_backend.cpp
+ * \author Andrey Semashev
+ * \date 09.06.2009
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <ios>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/log/detail/parameter_tools.hpp>
+#include <boost/log/sinks/auto_newline_mode.hpp>
+#include <boost/log/sinks/text_multifile_backend.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+//! Sink implementation data
+struct text_multifile_backend::implementation
+{
+ //! File name composer
+ file_name_composer_type m_FileNameComposer;
+ //! Base path for absolute path composition
+ const filesystem::path m_BasePath;
+ //! File stream
+ filesystem::ofstream m_File;
+ //! Indicates whether to append a trailing newline after every log record
+ auto_newline_mode m_AutoNewlineMode;
+
+ explicit implementation(auto_newline_mode auto_newline) :
+ m_BasePath(filesystem::current_path()),
+ m_AutoNewlineMode(auto_newline)
+ {
+ }
+
+ //! Makes relative path absolute with respect to the base path
+ filesystem::path make_absolute(filesystem::path const& p)
+ {
+ return filesystem::absolute(p, m_BasePath);
+ }
+};
+
+//! Default constructor
+BOOST_LOG_API text_multifile_backend::text_multifile_backend()
+{
+ construct(log::aux::empty_arg_list());
+}
+
+//! Constructor implementation
+BOOST_LOG_API void text_multifile_backend::construct(auto_newline_mode auto_newline)
+{
+ m_pImpl = new implementation(auto_newline);
+}
+
+//! Destructor
+BOOST_LOG_API text_multifile_backend::~text_multifile_backend()
+{
+ delete m_pImpl;
+}
+
+//! The method sets the file name composer
+BOOST_LOG_API void text_multifile_backend::set_file_name_composer_internal(file_name_composer_type const& composer)
+{
+ m_pImpl->m_FileNameComposer = composer;
+}
+
+//! Selects whether a trailing newline should be automatically inserted after every log record.
+BOOST_LOG_API void text_multifile_backend::set_auto_newline_mode(auto_newline_mode mode)
+{
+ m_pImpl->m_AutoNewlineMode = mode;
+}
+
+//! The method writes the message to the sink
+BOOST_LOG_API void text_multifile_backend::consume(record_view const& rec, string_type const& formatted_message)
+{
+ if (BOOST_LIKELY(!m_pImpl->m_FileNameComposer.empty()))
+ {
+ filesystem::path file_name = m_pImpl->make_absolute(m_pImpl->m_FileNameComposer(rec));
+ filesystem::create_directories(file_name.parent_path());
+ m_pImpl->m_File.open(file_name, std::ios_base::out | std::ios_base::app);
+ if (BOOST_LIKELY(m_pImpl->m_File.is_open()))
+ {
+ m_pImpl->m_File.write(formatted_message.data(), static_cast< std::streamsize >(formatted_message.size()));
+ if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline)
+ {
+ if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || *formatted_message.rbegin() != static_cast< string_type::value_type >('\n'))
+ m_pImpl->m_File.put(static_cast< string_type::value_type >('\n'));
+ }
+ m_pImpl->m_File.close();
+ }
+ }
+}
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/text_ostream_backend.cpp b/src/boost/libs/log/src/text_ostream_backend.cpp
new file mode 100644
index 000000000..047b0c00f
--- /dev/null
+++ b/src/boost/libs/log/src/text_ostream_backend.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file text_ostream_backend.cpp
+ * \author Andrey Semashev
+ * \date 19.04.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <vector>
+#include <algorithm>
+#include <boost/log/detail/parameter_tools.hpp>
+#include <boost/log/sinks/auto_newline_mode.hpp>
+#include <boost/log/sinks/text_ostream_backend.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+//! Sink implementation
+template< typename CharT >
+struct basic_text_ostream_backend< CharT >::implementation
+{
+ //! Type of the container that holds all aggregated streams
+ typedef std::vector< shared_ptr< stream_type > > ostream_sequence;
+
+ //! Output stream list
+ ostream_sequence m_Streams;
+ //! Indicates whether to append a trailing newline after every log record
+ auto_newline_mode m_AutoNewlineMode;
+ //! Auto-flush flag
+ bool m_fAutoFlush;
+
+ implementation(auto_newline_mode auto_newline, bool auto_flush) :
+ m_AutoNewlineMode(auto_newline),
+ m_fAutoFlush(auto_flush)
+ {
+ }
+};
+
+
+//! Constructor
+template< typename CharT >
+BOOST_LOG_API basic_text_ostream_backend< CharT >::basic_text_ostream_backend()
+{
+ construct(log::aux::empty_arg_list());
+}
+
+//! Constructor implementation
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::construct(auto_newline_mode auto_newline, bool auto_flush)
+{
+ m_pImpl = new implementation(auto_newline, auto_flush);
+}
+
+//! Destructor (just to make it link from the shared library)
+template< typename CharT >
+BOOST_LOG_API basic_text_ostream_backend< CharT >::~basic_text_ostream_backend()
+{
+ delete m_pImpl;
+}
+
+//! Selects whether a trailing newline should be automatically inserted after every log record.
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::set_auto_newline_mode(auto_newline_mode mode)
+{
+ m_pImpl->m_AutoNewlineMode = mode;
+}
+
+//! The method adds a new stream to the sink
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::add_stream(shared_ptr< stream_type > const& strm)
+{
+ typename implementation::ostream_sequence::iterator it =
+ std::find(m_pImpl->m_Streams.begin(), m_pImpl->m_Streams.end(), strm);
+ if (it == m_pImpl->m_Streams.end())
+ {
+ m_pImpl->m_Streams.push_back(strm);
+ }
+}
+
+//! The method removes a stream from the sink
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::remove_stream(shared_ptr< stream_type > const& strm)
+{
+ typename implementation::ostream_sequence::iterator it =
+ std::find(m_pImpl->m_Streams.begin(), m_pImpl->m_Streams.end(), strm);
+ if (it != m_pImpl->m_Streams.end())
+ m_pImpl->m_Streams.erase(it);
+}
+
+//! Sets the flag to automatically flush buffers after each logged line
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::auto_flush(bool f)
+{
+ m_pImpl->m_fAutoFlush = f;
+}
+
+//! The method writes the message to the sink
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::consume(record_view const&, string_type const& message)
+{
+ typename string_type::const_pointer const p = message.data();
+ typename string_type::size_type const s = message.size();
+ typename implementation::ostream_sequence::const_iterator
+ it = m_pImpl->m_Streams.begin(), end = m_pImpl->m_Streams.end();
+ bool need_trailing_newline = false;
+ if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline)
+ need_trailing_newline = (m_pImpl->m_AutoNewlineMode == always_insert || s == 0u || p[s - 1u] != static_cast< char_type >('\n'));
+
+ for (; it != end; ++it)
+ {
+ stream_type* const strm = it->get();
+ if (BOOST_LIKELY(strm->good()))
+ {
+ strm->write(p, static_cast< std::streamsize >(s));
+ if (need_trailing_newline)
+ strm->put(static_cast< char_type >('\n'));
+
+ if (m_pImpl->m_fAutoFlush)
+ strm->flush();
+ }
+ }
+}
+
+//! The method flushes the associated streams
+template< typename CharT >
+BOOST_LOG_API void basic_text_ostream_backend< CharT >::flush()
+{
+ typename implementation::ostream_sequence::const_iterator
+ it = m_pImpl->m_Streams.begin(), end = m_pImpl->m_Streams.end();
+ for (; it != end; ++it)
+ {
+ stream_type* const strm = it->get();
+ if (BOOST_LIKELY(strm->good()))
+ strm->flush();
+ }
+}
+
+//! Explicitly instantiate sink backend implementation
+#ifdef BOOST_LOG_USE_CHAR
+template class basic_text_ostream_backend< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template class basic_text_ostream_backend< wchar_t >;
+#endif
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/thread_id.cpp b/src/boost/libs/log/src/thread_id.cpp
new file mode 100644
index 000000000..e3a70a462
--- /dev/null
+++ b/src/boost/libs/log/src/thread_id.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file thread_id.cpp
+ * \author Andrey Semashev
+ * \date 08.1.2012
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+#include <new>
+#include <iostream>
+#include <boost/throw_exception.hpp>
+#if !defined(BOOST_WINDOWS)
+#include <cstring>
+#include <boost/predef/other/endian.h>
+#endif
+#include <boost/log/detail/thread_id.hpp>
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+#include <boost/aligned_storage.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#elif defined(BOOST_WINDOWS)
+#include <boost/thread/thread.hpp>
+#include <boost/log/detail/thread_specific.hpp>
+#else
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/once_block.hpp>
+#endif
+#if !defined(BOOST_LOG_USE_COMPILER_TLS)
+#include <boost/log/detail/singleton.hpp>
+#endif
+#include "id_formatting.hpp"
+#include <boost/log/detail/header.hpp>
+
+#if defined(BOOST_WINDOWS)
+
+#include <windows.h>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+enum { tid_size = sizeof(GetCurrentThreadId()) };
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ //! The function returns current process identifier
+ inline thread::id get_id_impl()
+ {
+ return thread::id(GetCurrentThreadId());
+ }
+
+} // namespace
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#else // defined(BOOST_WINDOWS)
+
+#include <pthread.h>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+enum
+{
+ headroom_size = sizeof(pthread_t) > sizeof(uintmax_t) ? 0u : (sizeof(uintmax_t) - sizeof(pthread_t)),
+ tid_size = sizeof(uintmax_t) - headroom_size
+};
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+ //! The function returns current thread identifier
+ inline thread::id get_id_impl()
+ {
+ // According to POSIX, pthread_t may not be an integer type:
+ // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/types.h.html
+ // For now we use the hackish cast to get some opaque number that hopefully correlates with system thread identification.
+ thread::id::native_type int_id = 0;
+ pthread_t pthread_id = pthread_self();
+#if BOOST_ENDIAN_BIG_BYTE || BOOST_ENDIAN_BIG_WORD
+ std::memcpy(reinterpret_cast< unsigned char* >(&int_id) + headroom_size, &pthread_id, tid_size);
+#else
+ std::memcpy(&int_id, &pthread_id, tid_size);
+#endif
+ return thread::id(int_id);
+ }
+
+} // namespace
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS)
+
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+namespace this_thread {
+
+#if defined(BOOST_LOG_USE_COMPILER_TLS)
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+struct id_storage
+{
+ aligned_storage< sizeof(thread::id), alignment_of< thread::id >::value >::type m_storage;
+ bool m_initialized;
+};
+
+BOOST_LOG_TLS id_storage g_id_storage = {};
+
+} // namespace
+
+//! The function returns current thread identifier
+BOOST_LOG_API thread::id const& get_id()
+{
+ id_storage& s = g_id_storage;
+ if (BOOST_UNLIKELY(!s.m_initialized))
+ {
+ new (s.m_storage.address()) thread::id(get_id_impl());
+ s.m_initialized = true;
+ }
+
+ return *static_cast< thread::id const* >(s.m_storage.address());
+}
+
+#elif defined(BOOST_WINDOWS)
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+struct id_storage :
+ lazy_singleton< id_storage >
+{
+ struct deleter
+ {
+ typedef void result_type;
+
+ explicit deleter(thread::id const* p) : m_p(p) {}
+
+ result_type operator() () const
+ {
+ delete m_p;
+ }
+
+ private:
+ thread::id const* m_p;
+ };
+
+ thread_specific< thread::id const* > m_id;
+};
+
+} // namespace
+
+//! The function returns current thread identifier
+BOOST_LOG_API thread::id const& get_id()
+{
+ id_storage& s = id_storage::get();
+ thread::id const* p = s.m_id.get();
+ if (BOOST_UNLIKELY(!p))
+ {
+ p = new thread::id(get_id_impl());
+ s.m_id.set(p);
+ boost::this_thread::at_thread_exit(id_storage::deleter(p));
+ }
+
+ return *p;
+}
+
+#else
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+pthread_key_t g_key;
+
+void deleter(void* p)
+{
+ delete static_cast< thread::id* >(p);
+}
+
+} // namespace
+
+//! The function returns current thread identifier
+BOOST_LOG_API thread::id const& get_id()
+{
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ if (int err = pthread_key_create(&g_key, &deleter))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create a thread-specific storage for thread id", (err));
+ }
+ }
+
+ thread::id* p = static_cast< thread::id* >(pthread_getspecific(g_key));
+ if (BOOST_UNLIKELY(!p))
+ {
+ p = new thread::id(get_id_impl());
+ pthread_setspecific(g_key, p);
+ }
+
+ return *p;
+}
+
+#endif
+
+} // namespace this_thread
+
+// Used in default_sink.cpp
+void format_thread_id(char* buf, std::size_t size, thread::id tid)
+{
+ format_id< tid_size >(buf, size, tid.native_id(), false);
+}
+
+template< typename CharT, typename TraitsT >
+BOOST_LOG_API std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, thread::id const& tid)
+{
+ if (strm.good())
+ {
+ CharT buf[tid_size * 2 + 3]; // 2 chars per byte + 3 chars for the leading 0x and terminating zero
+ format_id< tid_size >(buf, sizeof(buf) / sizeof(*buf), tid.native_id(), (strm.flags() & std::ios_base::uppercase) != 0);
+
+ strm << buf;
+ }
+
+ return strm;
+}
+
+#if defined(BOOST_LOG_USE_CHAR)
+template BOOST_LOG_API
+std::basic_ostream< char, std::char_traits< char > >&
+operator<< (std::basic_ostream< char, std::char_traits< char > >& strm, thread::id const& tid);
+#endif // defined(BOOST_LOG_USE_CHAR)
+
+#if defined(BOOST_LOG_USE_WCHAR_T)
+template BOOST_LOG_API
+std::basic_ostream< wchar_t, std::char_traits< wchar_t > >&
+operator<< (std::basic_ostream< wchar_t, std::char_traits< wchar_t > >& strm, thread::id const& tid);
+#endif // defined(BOOST_LOG_USE_WCHAR_T)
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_NO_THREADS)
diff --git a/src/boost/libs/log/src/thread_specific.cpp b/src/boost/libs/log/src/thread_specific.cpp
new file mode 100644
index 000000000..851d4c166
--- /dev/null
+++ b/src/boost/libs/log/src/thread_specific.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file thread_specific.cpp
+ * \author Andrey Semashev
+ * \date 01.03.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <string>
+#include <stdexcept>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/detail/thread_specific.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+#if defined(BOOST_THREAD_PLATFORM_WIN32)
+
+#include <windows.h>
+#include <boost/system/error_code.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+thread_specific_base::thread_specific_base()
+{
+ m_Key = TlsAlloc();
+ if (BOOST_UNLIKELY(m_Key == TLS_OUT_OF_INDEXES))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (boost::system::errc::not_enough_memory));
+ }
+}
+
+thread_specific_base::~thread_specific_base()
+{
+ TlsFree(m_Key);
+}
+
+void* thread_specific_base::get_content() const
+{
+ return TlsGetValue(m_Key);
+}
+
+void thread_specific_base::set_content(void* value) const
+{
+ TlsSetValue(m_Key, value);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
+
+#include <cstddef>
+#include <cstring>
+#include <pthread.h>
+#include <boost/cstdint.hpp>
+#include <boost/type_traits/conditional.hpp>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/is_signed.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! Some portability magic to detect how to store the TLS key
+template< typename KeyT, bool IsStoreableV = sizeof(KeyT) <= sizeof(void*), bool IsIntegralV = boost::is_integral< KeyT >::value >
+struct pthread_key_traits
+{
+ typedef KeyT pthread_key_type;
+
+ static void allocate(void*& stg)
+ {
+ pthread_key_type* pkey = new pthread_key_type();
+ const int res = pthread_key_create(pkey, NULL);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ delete pkey;
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
+ }
+ stg = pkey;
+ }
+
+ static void deallocate(void* stg)
+ {
+ pthread_key_type* pkey = static_cast< pthread_key_type* >(stg);
+ pthread_key_delete(*pkey);
+ delete pkey;
+ }
+
+ static void set_value(void* stg, void* value)
+ {
+ const int res = pthread_setspecific(*static_cast< pthread_key_type* >(stg), value);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
+ }
+ }
+
+ static void* get_value(void* stg)
+ {
+ return pthread_getspecific(*static_cast< pthread_key_type* >(stg));
+ }
+};
+
+template< typename KeyT >
+struct pthread_key_traits< KeyT, true, true >
+{
+ typedef KeyT pthread_key_type;
+
+#if defined(BOOST_HAS_INTPTR_T)
+ typedef typename boost::conditional<
+ boost::is_signed< pthread_key_type >::value,
+ intptr_t,
+ uintptr_t
+ >::type intptr_type;
+#else
+ typedef typename boost::conditional<
+ boost::is_signed< pthread_key_type >::value,
+ std::ptrdiff_t,
+ std::size_t
+ >::type intptr_type;
+#endif
+
+ static void allocate(void*& stg)
+ {
+ pthread_key_type key;
+ const int res = pthread_key_create(&key, NULL);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
+ }
+ stg = (void*)(intptr_type)key;
+ }
+
+ static void deallocate(void* stg)
+ {
+ pthread_key_delete((pthread_key_type)(intptr_type)stg);
+ }
+
+ static void set_value(void* stg, void* value)
+ {
+ const int res = pthread_setspecific((pthread_key_type)(intptr_type)stg, value);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
+ }
+ }
+
+ static void* get_value(void* stg)
+ {
+ return pthread_getspecific((pthread_key_type)(intptr_type)stg);
+ }
+};
+
+template< typename KeyT >
+struct pthread_key_traits< KeyT, true, false >
+{
+ typedef KeyT pthread_key_type;
+
+ static void allocate(void*& stg)
+ {
+ pthread_key_type key;
+ const int res = pthread_key_create(&key, NULL);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
+ }
+ std::memset(&stg, 0, sizeof(stg));
+ std::memcpy(&stg, &key, sizeof(pthread_key_type));
+ }
+
+ static void deallocate(void* stg)
+ {
+ pthread_key_type key;
+ std::memcpy(&key, &stg, sizeof(pthread_key_type));
+ pthread_key_delete(key);
+ }
+
+ static void set_value(void* stg, void* value)
+ {
+ pthread_key_type key;
+ std::memcpy(&key, &stg, sizeof(pthread_key_type));
+ const int res = pthread_setspecific(key, value);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
+ }
+ }
+
+ static void* get_value(void* stg)
+ {
+ pthread_key_type key;
+ std::memcpy(&key, &stg, sizeof(pthread_key_type));
+ return pthread_getspecific(key);
+ }
+};
+
+template< typename KeyT >
+struct pthread_key_traits< KeyT*, true, false >
+{
+ typedef KeyT* pthread_key_type;
+
+ static void allocate(void*& stg)
+ {
+ pthread_key_type key = NULL;
+ const int res = pthread_key_create(&key, NULL);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res));
+ }
+ stg = static_cast< void* >(key);
+ }
+
+ static void deallocate(void* stg)
+ {
+ pthread_key_delete(static_cast< pthread_key_type >(stg));
+ }
+
+ static void set_value(void* stg, void* value)
+ {
+ const int res = pthread_setspecific(static_cast< pthread_key_type >(stg), value);
+ if (BOOST_UNLIKELY(res != 0))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set TLS value", (res));
+ }
+ }
+
+ static void* get_value(void* stg)
+ {
+ return pthread_getspecific(static_cast< pthread_key_type >(stg));
+ }
+};
+
+} // namespace
+
+thread_specific_base::thread_specific_base()
+{
+ typedef pthread_key_traits< pthread_key_t > traits_t;
+ traits_t::allocate(m_Key);
+}
+
+thread_specific_base::~thread_specific_base()
+{
+ typedef pthread_key_traits< pthread_key_t > traits_t;
+ traits_t::deallocate(m_Key);
+}
+
+void* thread_specific_base::get_content() const
+{
+ typedef pthread_key_traits< pthread_key_t > traits_t;
+ return traits_t::get_value(m_Key);
+}
+
+void thread_specific_base::set_content(void* value) const
+{
+ typedef pthread_key_traits< pthread_key_t > traits_t;
+ traits_t::set_value(m_Key, value);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#else
+#error Boost.Log: unsupported threading API
+#endif
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_NO_THREADS)
diff --git a/src/boost/libs/log/src/threadsafe_queue.cpp b/src/boost/libs/log/src/threadsafe_queue.cpp
new file mode 100644
index 000000000..bbad463de
--- /dev/null
+++ b/src/boost/libs/log/src/threadsafe_queue.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file threadsafe_queue.cpp
+ * \author Andrey Semashev
+ * \date 05.11.2010
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ *
+ * The implementation is based on algorithms published in the "Simple, Fast,
+ * and Practical Non-Blocking and Blocking Concurrent Queue Algorithms" article
+ * in PODC96 by Maged M. Michael and Michael L. Scott. Pseudocode is available here:
+ * http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html
+ *
+ * The lock-free version of the mentioned algorithms contain a race condition and therefore
+ * were not included here.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/detail/threadsafe_queue.hpp>
+
+#ifndef BOOST_LOG_NO_THREADS
+
+#include <new>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/align/aligned_alloc.hpp>
+#include <boost/type_traits/alignment_of.hpp>
+#include <boost/log/detail/adaptive_mutex.hpp>
+#include <boost/log/detail/locks.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Generic queue implementation with two locks
+class threadsafe_queue_impl_generic :
+ public threadsafe_queue_impl
+{
+private:
+ //! Mutex type to be used
+ typedef adaptive_mutex mutex_type;
+
+ /*!
+ * A structure that contains a pointer to the node and the associated mutex.
+ * The alignment below allows to eliminate false sharing, it should not be less than CPU cache line size.
+ */
+ struct BOOST_ALIGNMENT(BOOST_LOG_CPU_CACHE_LINE_SIZE) pointer
+ {
+ //! Pointer to the either end of the queue
+ node_base* node;
+ //! Lock for access synchronization
+ mutex_type mutex;
+ // 128 bytes padding is chosen to mitigate false sharing for NetBurst CPUs, which load two cache lines in one go.
+ unsigned char padding[128U - (sizeof(node_base*) + sizeof(mutex_type)) % 128U];
+ };
+
+private:
+ //! Pointer to the beginning of the queue
+ pointer m_Head;
+ //! Pointer to the end of the queue
+ pointer m_Tail;
+
+public:
+ explicit threadsafe_queue_impl_generic(node_base* first_node)
+ {
+ set_next(first_node, NULL);
+ m_Head.node = m_Tail.node = first_node;
+ }
+
+ ~threadsafe_queue_impl_generic()
+ {
+ }
+
+ node_base* reset_last_node()
+ {
+ BOOST_ASSERT(m_Head.node == m_Tail.node);
+ node_base* p = m_Head.node;
+ m_Head.node = m_Tail.node = NULL;
+ return p;
+ }
+
+ bool unsafe_empty()
+ {
+ return m_Head.node == m_Tail.node;
+ }
+
+ void push(node_base* p)
+ {
+ set_next(p, NULL);
+ exclusive_lock_guard< mutex_type > _(m_Tail.mutex);
+ set_next(m_Tail.node, p);
+ m_Tail.node = p;
+ }
+
+ bool try_pop(node_base*& node_to_free, node_base*& node_with_value)
+ {
+ exclusive_lock_guard< mutex_type > _(m_Head.mutex);
+ node_base* next = get_next(m_Head.node);
+ if (next)
+ {
+ // We have a node to pop
+ node_to_free = m_Head.node;
+ node_with_value = m_Head.node = next;
+ return true;
+ }
+ else
+ return false;
+ }
+
+private:
+ BOOST_FORCEINLINE static void set_next(node_base* p, node_base* next)
+ {
+ p->next.data[0] = next;
+ }
+ BOOST_FORCEINLINE static node_base* get_next(node_base* p)
+ {
+ return static_cast< node_base* >(p->next.data[0]);
+ }
+
+ // Copying and assignment are closed
+ BOOST_DELETED_FUNCTION(threadsafe_queue_impl_generic(threadsafe_queue_impl_generic const&))
+ BOOST_DELETED_FUNCTION(threadsafe_queue_impl_generic& operator= (threadsafe_queue_impl_generic const&))
+};
+
+BOOST_LOG_API threadsafe_queue_impl* threadsafe_queue_impl::create(node_base* first_node)
+{
+ return new threadsafe_queue_impl_generic(first_node);
+}
+
+BOOST_LOG_API void* threadsafe_queue_impl::operator new (std::size_t size)
+{
+ void* p = alignment::aligned_alloc(BOOST_LOG_CPU_CACHE_LINE_SIZE, size);
+ if (BOOST_UNLIKELY(!p))
+ BOOST_THROW_EXCEPTION(std::bad_alloc());
+ return p;
+}
+
+BOOST_LOG_API void threadsafe_queue_impl::operator delete (void* p, std::size_t)
+{
+ alignment::aligned_free(p);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_NO_THREADS
diff --git a/src/boost/libs/log/src/timer.cpp b/src/boost/libs/log/src/timer.cpp
new file mode 100644
index 000000000..f9b4cdfdb
--- /dev/null
+++ b/src/boost/libs/log/src/timer.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file timer.cpp
+ * \author Andrey Semashev
+ * \date 02.12.2007
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/attributes/timer.hpp>
+#include <boost/log/attributes/attribute_value_impl.hpp>
+
+#if defined(BOOST_WINDOWS) && !defined(BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER)
+
+#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <boost/log/detail/locks.hpp>
+#include <boost/thread/mutex.hpp>
+#endif
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace attributes {
+
+//! Factory implementation
+class BOOST_SYMBOL_VISIBLE timer::impl :
+ public attribute::impl
+{
+private:
+#if !defined(BOOST_LOG_NO_THREADS)
+ //! Synchronization mutex type
+ typedef boost::mutex mutex_type;
+ //! Synchronization mutex
+ mutex_type m_Mutex;
+#endif
+ //! Frequency factor for calculating duration
+ double m_FrequencyFactor;
+ //! Last value of the performance counter
+ uint64_t m_LastCounter;
+ //! Elapsed time duration, in microseconds
+ uint64_t m_Duration;
+
+public:
+ //! Constructor
+ impl() : m_Duration(0)
+ {
+ LARGE_INTEGER li;
+ QueryPerformanceFrequency(&li);
+ BOOST_ASSERT(li.QuadPart != 0LL);
+ m_FrequencyFactor = 1000000.0 / static_cast< double >(li.QuadPart);
+
+ QueryPerformanceCounter(&li);
+ m_LastCounter = static_cast< uint64_t >(li.QuadPart);
+ }
+
+ //! The method returns the actual attribute value. It must not return NULL.
+ attribute_value get_value()
+ {
+ uint64_t duration;
+ {
+ BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
+
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ const uint64_t counter = static_cast< uint64_t >(li.QuadPart);
+ const uint64_t counts = counter - m_LastCounter;
+ m_LastCounter = counter;
+ duration = m_Duration + static_cast< uint64_t >(counts * m_FrequencyFactor);
+ m_Duration = duration;
+ }
+
+ return attribute_value(new attribute_value_impl< value_type >(boost::posix_time::microseconds(duration)));
+ }
+};
+
+//! Constructor
+timer::timer() : attribute(new impl())
+{
+}
+
+//! Constructor for casting support
+timer::timer(cast_source const& source) : attribute(source.as< impl >())
+{
+}
+
+} // namespace attributes
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#else // defined(BOOST_WINDOWS) && !defined(BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER)
+
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace attributes {
+
+//! Factory implementation
+class BOOST_SYMBOL_VISIBLE timer::impl :
+ public attribute::impl
+{
+public:
+ //! Time type
+ typedef utc_time_traits::time_type time_type;
+
+private:
+ //! Base time point
+ const time_type m_BaseTimePoint;
+
+public:
+ /*!
+ * Constructor. Starts time counting.
+ */
+ impl() : m_BaseTimePoint(utc_time_traits::get_clock()) {}
+
+ attribute_value get_value()
+ {
+ return attribute_value(new attribute_value_impl< value_type >(
+ utc_time_traits::get_clock() - m_BaseTimePoint));
+ }
+};
+
+//! Constructor
+timer::timer() : attribute(new impl())
+{
+}
+
+//! Constructor for casting support
+timer::timer(cast_source const& source) : attribute(source.as< impl >())
+{
+}
+
+} // namespace attributes
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // defined(BOOST_WINDOWS) && !defined(BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER)
diff --git a/src/boost/libs/log/src/timestamp.cpp b/src/boost/libs/log/src/timestamp.cpp
new file mode 100644
index 000000000..05e5e50c7
--- /dev/null
+++ b/src/boost/libs/log/src/timestamp.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright Andrey Semashev 2007 - 2018.
+ * 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)
+ */
+/*!
+ * \file timestamp.cpp
+ * \author Andrey Semashev
+ * \date 31.07.2011
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/detail/timestamp.hpp>
+
+#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+#include <cstddef>
+#include <cstdlib>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/winapi/time.hpp>
+#include <boost/winapi/event.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/winapi/thread_pool.hpp>
+#else
+#include <unistd.h> // for config macros
+#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+#include <mach/mach_time.h>
+#include <mach/kern_return.h>
+#include <boost/log/utility/once_block.hpp>
+#include <boost/system/error_code.hpp>
+#endif
+#include <time.h>
+#include <errno.h>
+#include <boost/throw_exception.hpp>
+#include <boost/log/exceptions.hpp>
+#endif
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+// Directly use API from Vista and later
+BOOST_LOG_API get_tick_count_t get_tick_count = &boost::winapi::GetTickCount64;
+
+#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+enum init_state
+{
+ uninitialized = 0,
+ in_progress,
+ initialized
+};
+
+struct get_tick_count64_state
+{
+ boost::atomic< uint64_t > ticks;
+ boost::atomic< init_state > init;
+ boost::winapi::HANDLE_ wait_event;
+ boost::winapi::HANDLE_ wait_handle;
+};
+
+// Zero-initialized initially
+BOOST_ALIGNMENT(BOOST_LOG_CPU_CACHE_LINE_SIZE) static get_tick_count64_state g_state;
+
+//! Artifical implementation of GetTickCount64
+uint64_t BOOST_WINAPI_WINAPI_CC get_tick_count64()
+{
+ // Note: Even in single-threaded builds we have to implement get_tick_count64 in a thread-safe way because
+ // it can be called in the system thread pool during refreshes concurrently with user's calls.
+ uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire);
+
+ uint32_t new_ticks = boost::winapi::GetTickCount();
+
+ uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff));
+ uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks);
+
+ g_state.ticks.store(new_state, boost::memory_order_release);
+
+ return new_state;
+}
+
+//! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated
+void BOOST_WINAPI_NTAPI_CC refresh_get_tick_count64(boost::winapi::PVOID_, boost::winapi::BOOLEAN_)
+{
+ get_tick_count64();
+}
+
+//! Cleanup function to stop get_tick_count64 refreshes
+void cleanup_get_tick_count64()
+{
+ if (g_state.wait_handle)
+ {
+ boost::winapi::UnregisterWait(g_state.wait_handle);
+ g_state.wait_handle = NULL;
+ }
+
+ if (g_state.wait_event)
+ {
+ boost::winapi::CloseHandle(g_state.wait_event);
+ g_state.wait_event = NULL;
+ }
+}
+
+uint64_t BOOST_WINAPI_WINAPI_CC get_tick_count_init()
+{
+ boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ {
+ get_tick_count_t p = (get_tick_count_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64");
+ if (p)
+ {
+ // Use native API
+ const_cast< get_tick_count_t volatile& >(get_tick_count) = p;
+ return p();
+ }
+ }
+
+ // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
+ init_state old_init = uninitialized;
+ if (g_state.init.compare_exchange_strong(old_init, in_progress, boost::memory_order_acq_rel, boost::memory_order_relaxed))
+ {
+ if (!g_state.wait_event)
+ g_state.wait_event = boost::winapi::create_anonymous_event(NULL, false, false);
+ if (g_state.wait_event)
+ {
+ boost::winapi::BOOL_ res = boost::winapi::RegisterWaitForSingleObject(&g_state.wait_handle, g_state.wait_event, &refresh_get_tick_count64, NULL, 0x7fffffff, boost::winapi::WT_EXECUTEINWAITTHREAD_);
+ if (res)
+ {
+ std::atexit(&cleanup_get_tick_count64);
+
+ const_cast< get_tick_count_t volatile& >(get_tick_count) = &get_tick_count64;
+ g_state.init.store(initialized, boost::memory_order_release);
+ goto finish;
+ }
+ }
+
+ g_state.init.store(uninitialized, boost::memory_order_release);
+ }
+
+finish:
+ return get_tick_count64();
+}
+
+} // namespace
+
+BOOST_LOG_API get_tick_count_t get_tick_count = &get_tick_count_init;
+
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+#elif (defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0) > 0) /* POSIX timers supported */ \
+ || defined(__GNU__) || defined(__OpenBSD__) || defined(__CloudABI__) /* GNU Hurd, OpenBSD and Nuxi CloudABI don't support POSIX timers fully but do provide clock_gettime() */
+
+BOOST_LOG_API int64_t duration::milliseconds() const
+{
+ // Timestamps are always in nanoseconds
+ return m_ticks / INT64_C(1000000);
+}
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+/*!
+ * \c get_timestamp implementation based on POSIX realtime clock.
+ * Note that this implementation is only used as a last resort since
+ * this timer can be manually set and may jump due to DST change.
+ */
+timestamp get_timestamp_realtime_clock()
+{
+ timespec ts;
+ if (BOOST_UNLIKELY(clock_gettime(CLOCK_REALTIME, &ts) != 0))
+ {
+ const int err = errno;
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err));
+ }
+
+ return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec);
+}
+
+# if defined(_POSIX_MONOTONIC_CLOCK)
+
+//! \c get_timestamp implementation based on POSIX monotonic clock
+timestamp get_timestamp_monotonic_clock()
+{
+ timespec ts;
+ if (BOOST_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0))
+ {
+ const int err = errno;
+ if (err == EINVAL)
+ {
+ // The current platform does not support monotonic timer.
+ // Fall back to realtime clock, which is not exactly what we need
+ // but is better than nothing.
+ get_timestamp = &get_timestamp_realtime_clock;
+ return get_timestamp_realtime_clock();
+ }
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err));
+ }
+
+ return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec);
+}
+
+# define BOOST_LOG_DEFAULT_GET_TIMESTAMP get_timestamp_monotonic_clock
+
+# else // if defined(_POSIX_MONOTONIC_CLOCK)
+# define BOOST_LOG_DEFAULT_GET_TIMESTAMP get_timestamp_realtime_clock
+# endif // if defined(_POSIX_MONOTONIC_CLOCK)
+
+} // namespace
+
+// Use POSIX API
+BOOST_LOG_API get_timestamp_t get_timestamp = &BOOST_LOG_DEFAULT_GET_TIMESTAMP;
+
+# undef BOOST_LOG_DEFAULT_GET_TIMESTAMP
+
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+
+BOOST_LOG_API int64_t duration::milliseconds() const
+{
+ static mach_timebase_info_data_t timebase_info = {};
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ kern_return_t err = mach_timebase_info(&timebase_info);
+ if (err != KERN_SUCCESS)
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize timebase info", (boost::system::errc::not_supported));
+ }
+ }
+
+ // Often the timebase rational equals 1, we can optimize for this case
+ if (timebase_info.numer == timebase_info.denom)
+ {
+ // Timestamps are in nanoseconds
+ return m_ticks / INT64_C(1000000);
+ }
+ else
+ {
+ return (m_ticks * timebase_info.numer) / (INT64_C(1000000) * timebase_info.denom);
+ }
+}
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+//! \c get_timestamp implementation based on MacOS X absolute time
+timestamp get_timestamp_mach()
+{
+ return timestamp(mach_absolute_time());
+}
+
+} // namespace
+
+// Use MacOS X API
+BOOST_LOG_API get_timestamp_t get_timestamp = &get_timestamp_mach;
+
+#else
+
+# error Boost.Log: Timestamp generation is not supported for your platform
+
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/trivial.cpp b/src/boost/libs/log/src/trivial.cpp
new file mode 100644
index 000000000..1461ad71b
--- /dev/null
+++ b/src/boost/libs/log/src/trivial.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file trivial.cpp
+ * \author Andrey Semashev
+ * \date 07.11.2009
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+
+#if defined(BOOST_LOG_USE_CHAR)
+
+#include <string>
+#include <istream>
+#include <boost/log/trivial.hpp>
+#include <boost/log/sources/global_logger_storage.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace trivial {
+
+//! Initialization routine
+BOOST_LOG_API logger::logger_type logger::construct_logger()
+{
+ return logger_type(keywords::severity = info);
+}
+
+//! Returns a reference to the trivial logger instance
+BOOST_LOG_API logger::logger_type& logger::get()
+{
+ return log::sources::aux::logger_singleton< logger >::get();
+}
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+BOOST_CONSTEXPR_OR_CONST unsigned int names_count = 6;
+
+template< typename CharT >
+struct severity_level_names
+{
+ static const CharT names[names_count][8];
+};
+
+template< typename CharT >
+const CharT severity_level_names< CharT >::names[names_count][8] =
+{
+ { 't', 'r', 'a', 'c', 'e', 0 },
+ { 'd', 'e', 'b', 'u', 'g', 0 },
+ { 'i', 'n', 'f', 'o', 0 },
+ { 'w', 'a', 'r', 'n', 'i', 'n', 'g', 0 },
+ { 'e', 'r', 'r', 'o', 'r', 0 },
+ { 'f', 'a', 't', 'a', 'l', 0 }
+};
+
+} // namespace
+
+template< typename CharT >
+BOOST_LOG_API const CharT* to_string(severity_level lvl)
+{
+ typedef severity_level_names< CharT > level_names;
+ if (BOOST_LIKELY(static_cast< unsigned int >(lvl) < names_count))
+ return level_names::names[static_cast< unsigned int >(lvl)];
+ return NULL;
+}
+
+//! Parses enumeration value from string and returns \c true on success and \c false otherwise
+template< typename CharT >
+BOOST_LOG_API bool from_string(const CharT* str, std::size_t len, severity_level& lvl)
+{
+ typedef severity_level_names< CharT > level_names;
+ typedef std::char_traits< CharT > char_traits;
+
+ if (len == 5u)
+ {
+ if (char_traits::compare(str, level_names::names[0], len) == 0)
+ lvl = static_cast< severity_level >(0);
+ else if (char_traits::compare(str, level_names::names[1], len) == 0)
+ lvl = static_cast< severity_level >(1);
+ else if (char_traits::compare(str, level_names::names[4], len) == 0)
+ lvl = static_cast< severity_level >(4);
+ else if (char_traits::compare(str, level_names::names[5], len) == 0)
+ lvl = static_cast< severity_level >(5);
+ else
+ goto no_match;
+ return true;
+ }
+ else if (len == 4u)
+ {
+ if (char_traits::compare(str, level_names::names[2], len) == 0)
+ lvl = static_cast< severity_level >(2);
+ else
+ goto no_match;
+ return true;
+ }
+ else if (len == 7u)
+ {
+ if (char_traits::compare(str, level_names::names[3], len) == 0)
+ lvl = static_cast< severity_level >(3);
+ else
+ goto no_match;
+ return true;
+ }
+
+no_match:
+ return false;
+}
+
+template< typename CharT, typename TraitsT >
+BOOST_LOG_API std::basic_istream< CharT, TraitsT >& operator>> (
+ std::basic_istream< CharT, TraitsT >& strm, severity_level& lvl)
+{
+ if (BOOST_LIKELY(strm.good()))
+ {
+ typedef std::basic_string< CharT, TraitsT > string_type;
+ string_type str;
+ strm >> str;
+ if (BOOST_UNLIKELY(!boost::log::trivial::from_string(str.data(), str.size(), lvl)))
+ strm.setstate(std::ios_base::failbit);
+ }
+
+ return strm;
+}
+
+template BOOST_LOG_API const char* to_string< char >(severity_level lvl);
+template BOOST_LOG_API bool from_string< char >(const char* begin, std::size_t len, severity_level& lvl);
+template BOOST_LOG_API std::basic_istream< char, std::char_traits< char > >&
+ operator>> < char, std::char_traits< char > > (
+ std::basic_istream< char, std::char_traits< char > >& strm, severity_level& lvl);
+#ifdef BOOST_LOG_USE_WCHAR_T
+template BOOST_LOG_API const wchar_t* to_string< wchar_t >(severity_level lvl);
+template BOOST_LOG_API bool from_string< wchar_t >(const wchar_t* begin, std::size_t len, severity_level& lvl);
+template BOOST_LOG_API std::basic_istream< wchar_t, std::char_traits< wchar_t > >&
+ operator>> < wchar_t, std::char_traits< wchar_t > > (
+ std::basic_istream< wchar_t, std::char_traits< wchar_t > >& strm, severity_level& lvl);
+#endif
+
+} // namespace trivial
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // defined(BOOST_LOG_USE_CHAR)
diff --git a/src/boost/libs/log/src/unique_ptr.hpp b/src/boost/libs/log/src/unique_ptr.hpp
new file mode 100644
index 000000000..091bb9cf8
--- /dev/null
+++ b/src/boost/libs/log/src/unique_ptr.hpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file unique_ptr.hpp
+ * \author Andrey Semashev
+ * \date 18.07.2015
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_UNIQUE_PTR_HPP_INCLUDED_
+#define BOOST_LOG_UNIQUE_PTR_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+
+#if !defined(BOOST_NO_CXX11_SMART_PTR)
+
+#include <memory>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+using std::unique_ptr;
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#else // !defined(BOOST_NO_CXX11_SMART_PTR)
+
+#include <boost/move/unique_ptr.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+using boost::movelib::unique_ptr;
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#endif // !defined(BOOST_NO_CXX11_SMART_PTR)
+
+#endif // BOOST_LOG_UNIQUE_PTR_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/windows/auto_handle.hpp b/src/boost/libs/log/src/windows/auto_handle.hpp
new file mode 100644
index 000000000..ebd01babd
--- /dev/null
+++ b/src/boost/libs/log/src/windows/auto_handle.hpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/auto_handle.hpp
+ * \author Andrey Semashev
+ * \date 07.03.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WINDOWS_AUTO_HANDLE_HPP_INCLUDED_
+#define BOOST_LOG_WINDOWS_AUTO_HANDLE_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/assert.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+namespace aux {
+
+//! A wrapper around a kernel object handle. Automatically closes the handle on destruction.
+class auto_handle
+{
+private:
+ boost::winapi::HANDLE_ m_handle;
+
+public:
+ explicit auto_handle(boost::winapi::HANDLE_ h = NULL) BOOST_NOEXCEPT : m_handle(h)
+ {
+ }
+
+ ~auto_handle() BOOST_NOEXCEPT
+ {
+ if (m_handle)
+ BOOST_VERIFY(boost::winapi::CloseHandle(m_handle) != 0);
+ }
+
+ void init(boost::winapi::HANDLE_ h) BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT(m_handle == NULL);
+ m_handle = h;
+ }
+
+ boost::winapi::HANDLE_ get() const BOOST_NOEXCEPT { return m_handle; }
+ boost::winapi::HANDLE_* get_ptr() BOOST_NOEXCEPT { return &m_handle; }
+
+ void swap(auto_handle& that) BOOST_NOEXCEPT
+ {
+ boost::winapi::HANDLE_ h = m_handle;
+ m_handle = that.m_handle;
+ that.m_handle = h;
+ }
+
+ BOOST_DELETED_FUNCTION(auto_handle(auto_handle const&))
+ BOOST_DELETED_FUNCTION(auto_handle& operator=(auto_handle const&))
+};
+
+} // namespace aux
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WINDOWS_AUTO_HANDLE_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/windows/debug_output_backend.cpp b/src/boost/libs/log/src/windows/debug_output_backend.cpp
new file mode 100644
index 000000000..2e59da1c3
--- /dev/null
+++ b/src/boost/libs/log/src/windows/debug_output_backend.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file debug_output_backend.cpp
+ * \author Andrey Semashev
+ * \date 08.11.2008
+ *
+ * \brief A logging sink backend that uses debugger output
+ */
+
+#include <boost/log/detail/config.hpp>
+
+#ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT
+
+#include <string>
+#include <boost/log/sinks/debug_output_backend.hpp>
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+#if defined(BOOST_LOG_USE_CHAR)
+ inline void output_debug_string(const char* str)
+ {
+ OutputDebugStringA(str);
+ }
+#endif // defined(BOOST_LOG_USE_CHAR)
+#if defined(BOOST_LOG_USE_WCHAR_T)
+ inline void output_debug_string(const wchar_t* str)
+ {
+ OutputDebugStringW(str);
+ }
+#endif // defined(BOOST_LOG_USE_WCHAR_T)
+
+} // namespace
+
+template< typename CharT >
+BOOST_LOG_API basic_debug_output_backend< CharT >::basic_debug_output_backend()
+{
+}
+
+template< typename CharT >
+BOOST_LOG_API basic_debug_output_backend< CharT >::~basic_debug_output_backend()
+{
+}
+
+//! The method puts the formatted message to the event log
+template< typename CharT >
+BOOST_LOG_API void basic_debug_output_backend< CharT >::consume(record_view const&, string_type const& formatted_message)
+{
+ output_debug_string(formatted_message.c_str());
+}
+
+#ifdef BOOST_LOG_USE_CHAR
+template class basic_debug_output_backend< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template class basic_debug_output_backend< wchar_t >;
+#endif
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_WITHOUT_DEBUG_OUTPUT)
diff --git a/src/boost/libs/log/src/windows/event_log_backend.cpp b/src/boost/libs/log/src/windows/event_log_backend.cpp
new file mode 100644
index 000000000..7515f8bc5
--- /dev/null
+++ b/src/boost/libs/log/src/windows/event_log_backend.cpp
@@ -0,0 +1,636 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file event_log_backend.cpp
+ * \author Andrey Semashev
+ * \date 07.11.2008
+ *
+ * \brief A logging sink backend that uses Windows NT event log API
+ * for signalling application events.
+ */
+
+#include <boost/log/detail/config.hpp>
+
+#ifndef BOOST_LOG_WITHOUT_EVENT_LOG
+
+#include <string>
+#include <vector>
+#include <ostream>
+#include <stdexcept>
+#include <boost/scoped_array.hpp>
+#include <boost/system/windows_error.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/sinks/event_log_backend.hpp>
+#include <boost/log/sinks/event_log_constants.hpp>
+#include <boost/log/utility/once_block.hpp>
+#include <boost/log/detail/cleanup_scope_guard.hpp>
+#include <boost/log/detail/attachable_sstream_buf.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <windows.h>
+#include <psapi.h>
+#include "unique_ptr.hpp"
+#include "windows/event_log_registry.hpp"
+#include "windows/simple_event_log.h"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+namespace event_log {
+
+ //! The function constructs log record level from an integer
+ BOOST_LOG_API event_type make_event_type(unsigned short lev)
+ {
+ switch (lev)
+ {
+ case success: return success;
+ case warning: return warning;
+ case error: return error;
+ default:
+ BOOST_THROW_EXCEPTION(std::out_of_range("Windows NT event type is out of range"));
+ BOOST_LOG_UNREACHABLE_RETURN(info);
+ case info: return info;
+ }
+ }
+
+} // namespace event_log
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+#ifdef BOOST_LOG_USE_CHAR
+ //! A simple forwarder to the ReportEvent API
+ inline BOOL report_event(
+ HANDLE hEventLog,
+ WORD wType,
+ WORD wCategory,
+ DWORD dwEventID,
+ PSID lpUserSid,
+ WORD wNumStrings,
+ DWORD dwDataSize,
+ const char** lpStrings,
+ LPVOID lpRawData)
+ {
+ return ReportEventA(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
+ }
+ //! A simple forwarder to the GetModuleFileName API
+ inline DWORD get_module_file_name(HMODULE hModule, char* lpFilename, DWORD nSize)
+ {
+ return GetModuleFileNameA(hModule, lpFilename, nSize);
+ }
+ //! A simple forwarder to the RegisterEventSource API
+ inline HANDLE register_event_source(const char* lpUNCServerName, const char* lpSourceName)
+ {
+ return RegisterEventSourceA(lpUNCServerName, lpSourceName);
+ }
+ //! The function completes default source name for the sink backend
+ inline void complete_default_simple_event_log_source_name(std::string& name)
+ {
+ name += " simple event source";
+ }
+ //! The function completes default source name for the sink backend
+ inline void complete_default_event_log_source_name(std::string& name)
+ {
+ name += " event source";
+ }
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ //! A simple forwarder to the ReportEvent API
+ inline BOOL report_event(
+ HANDLE hEventLog,
+ WORD wType,
+ WORD wCategory,
+ DWORD dwEventID,
+ PSID lpUserSid,
+ WORD wNumStrings,
+ DWORD dwDataSize,
+ const wchar_t** lpStrings,
+ LPVOID lpRawData)
+ {
+ return ReportEventW(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, lpStrings, lpRawData);
+ }
+ //! A simple forwarder to the GetModuleFileName API
+ inline DWORD get_module_file_name(HMODULE hModule, wchar_t* lpFilename, DWORD nSize)
+ {
+ return GetModuleFileNameW(hModule, lpFilename, nSize);
+ }
+ //! A simple forwarder to the RegisterEventSource API
+ inline HANDLE register_event_source(const wchar_t* lpUNCServerName, const wchar_t* lpSourceName)
+ {
+ return RegisterEventSourceW(lpUNCServerName, lpSourceName);
+ }
+ //! The function completes default source name for the sink backend
+ inline void complete_default_simple_event_log_source_name(std::wstring& name)
+ {
+ name += L" simple event source";
+ }
+ //! The function completes default source name for the sink backend
+ inline void complete_default_event_log_source_name(std::wstring& name)
+ {
+ name += L" event source";
+ }
+#endif // BOOST_LOG_USE_WCHAR_T
+
+ //! The function finds the handle for the current module
+ void init_self_module_handle(HMODULE& handle)
+ {
+ // Acquire all modules of the current process
+ HANDLE hProcess = GetCurrentProcess();
+ std::vector< HMODULE > modules;
+ DWORD module_count = 1024;
+ do
+ {
+ modules.resize(module_count, HMODULE(0));
+ BOOL res = EnumProcessModules(
+ hProcess,
+ &modules[0],
+ static_cast< DWORD >(modules.size() * sizeof(HMODULE)),
+ &module_count);
+ module_count /= sizeof(HMODULE);
+
+ if (!res)
+ {
+ DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not enumerate process modules", (err));
+ }
+ }
+ while (module_count > modules.size());
+ modules.resize(module_count, HMODULE(0));
+
+ // Now find the current module among them
+ void* p = (void*)&init_self_module_handle;
+ for (std::size_t i = 0, n = modules.size(); i < n; ++i)
+ {
+ MODULEINFO info;
+ if (!GetModuleInformation(hProcess, modules[i], &info, sizeof(info)))
+ {
+ DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not acquire module information", (err));
+ }
+
+ if (info.lpBaseOfDll <= p && (static_cast< unsigned char* >(info.lpBaseOfDll) + info.SizeOfImage) > p)
+ {
+ // Found it
+ handle = modules[i];
+ break;
+ }
+ }
+
+ if (!handle)
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not find self module information", (boost::system::windows_error::invalid_handle));
+ }
+
+ //! Retrieves the full name of the current module (be that dll or exe)
+ template< typename CharT >
+ std::basic_string< CharT > get_current_module_name()
+ {
+ static HMODULE hSelfModule = 0;
+
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ init_self_module_handle(hSelfModule);
+ }
+
+ // Get the module file name
+ CharT buf[MAX_PATH];
+ DWORD size = get_module_file_name(hSelfModule, buf, sizeof(buf) / sizeof(*buf));
+ if (size == 0)
+ {
+ DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not get module file name", (err));
+ }
+
+ return std::basic_string< CharT >(buf, buf + size);
+ }
+
+} // namespace
+
+//////////////////////////////////////////////////////////////////////////
+// Simple event log backend implementation
+//////////////////////////////////////////////////////////////////////////
+//! Sink backend implementation
+template< typename CharT >
+struct basic_simple_event_log_backend< CharT >::implementation
+{
+ //! A handle for the registered event provider
+ HANDLE m_SourceHandle;
+ //! A level mapping functor
+ event_type_mapper_type m_LevelMapper;
+
+ implementation() : m_SourceHandle(0)
+ {
+ }
+};
+
+//! Default constructor. Registers event source Boost.Log <Boost version> in the Application log.
+template< typename CharT >
+BOOST_LOG_API basic_simple_event_log_backend< CharT >::basic_simple_event_log_backend()
+{
+ construct(log::aux::empty_arg_list());
+}
+
+//! Destructor
+template< typename CharT >
+BOOST_LOG_API basic_simple_event_log_backend< CharT >::~basic_simple_event_log_backend()
+{
+ DeregisterEventSource(m_pImpl->m_SourceHandle);
+ delete m_pImpl;
+}
+
+//! Constructs backend implementation
+template< typename CharT >
+BOOST_LOG_API void basic_simple_event_log_backend< CharT >::construct(
+ string_type const& target, string_type const& log_name, string_type const& source_name, event_log::registration_mode reg_mode)
+{
+ if (reg_mode != event_log::never)
+ {
+ aux::registry_params< char_type > reg_params;
+ reg_params.event_message_file = get_current_module_name< char_type >();
+ reg_params.types_supported = DWORD(
+ EVENTLOG_SUCCESS |
+ EVENTLOG_INFORMATION_TYPE |
+ EVENTLOG_WARNING_TYPE |
+ EVENTLOG_ERROR_TYPE);
+ aux::init_event_log_registry(log_name, source_name, reg_mode == event_log::forced, reg_params);
+ }
+
+ log::aux::unique_ptr< implementation > p(new implementation());
+
+ const char_type* target_unc = NULL;
+ if (!target.empty())
+ target_unc = target.c_str();
+
+ HANDLE hSource = register_event_source(target_unc, source_name.c_str());
+ if (!hSource)
+ {
+ const DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not register event source", (err));
+ }
+
+ p->m_SourceHandle = hSource;
+
+ m_pImpl = p.release();
+}
+
+//! Returns default log name
+template< typename CharT >
+BOOST_LOG_API typename basic_simple_event_log_backend< CharT >::string_type
+basic_simple_event_log_backend< CharT >::get_default_log_name()
+{
+ return aux::registry_traits< char_type >::make_default_log_name();
+}
+
+//! Returns default source name
+template< typename CharT >
+BOOST_LOG_API typename basic_simple_event_log_backend< CharT >::string_type
+basic_simple_event_log_backend< CharT >::get_default_source_name()
+{
+ string_type source_name = aux::registry_traits< char_type >::make_default_source_name();
+ complete_default_simple_event_log_source_name(source_name);
+ return source_name;
+}
+
+//! The method installs the function object that maps application severity levels to WinAPI event types
+template< typename CharT >
+BOOST_LOG_API void basic_simple_event_log_backend< CharT >::set_event_type_mapper(event_type_mapper_type const& mapper)
+{
+ m_pImpl->m_LevelMapper = mapper;
+}
+
+//! The method puts the formatted message to the event log
+template< typename CharT >
+BOOST_LOG_API void basic_simple_event_log_backend< CharT >::consume(record_view const& rec, string_type const& formatted_message)
+{
+ const char_type* message = formatted_message.c_str();
+ event_log::event_type evt_type = event_log::info;
+ if (!m_pImpl->m_LevelMapper.empty())
+ evt_type = m_pImpl->m_LevelMapper(rec);
+
+ DWORD event_id;
+ switch (evt_type)
+ {
+ case event_log::success:
+ event_id = BOOST_LOG_MSG_DEBUG; break;
+ case event_log::warning:
+ event_id = BOOST_LOG_MSG_WARNING; break;
+ case event_log::error:
+ event_id = BOOST_LOG_MSG_ERROR; break;
+ default:
+ event_id = BOOST_LOG_MSG_INFO; break;
+ }
+
+ report_event(
+ m_pImpl->m_SourceHandle, // Event log handle.
+ static_cast< WORD >(evt_type), // Event type.
+ 0, // Event category.
+ event_id, // Event identifier.
+ NULL, // No user security identifier.
+ 1, // Number of substitution strings.
+ 0, // No data.
+ &message, // Pointer to strings.
+ NULL); // No data.
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Customizable event log backend implementation
+//////////////////////////////////////////////////////////////////////////
+namespace event_log {
+
+ template< typename CharT >
+ class basic_event_composer< CharT >::insertion_composer
+ {
+ public:
+ //! Function object result type
+ typedef void result_type;
+
+ private:
+ //! The list of insertion composers (in backward order)
+ typedef std::vector< formatter_type > formatters;
+
+ private:
+ //! The insertion string composers
+ formatters m_Formatters;
+
+ public:
+ //! Default constructor
+ insertion_composer() {}
+ //! Composition operator
+ void operator() (record_view const& rec, insertion_list& insertions) const
+ {
+ std::size_t size = m_Formatters.size();
+ insertions.resize(size);
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ typename formatter_type::stream_type strm(insertions[i]);
+ m_Formatters[i](rec, strm);
+ strm.flush();
+ }
+ }
+ //! Adds a new formatter to the list
+ void add_formatter(formatter_type const& fmt)
+ {
+ m_Formatters.push_back(formatter_type(fmt));
+ }
+ };
+
+ //! Default constructor
+ template< typename CharT >
+ basic_event_composer< CharT >::basic_event_composer(event_id_mapper_type const& id_mapper) :
+ m_EventIDMapper(id_mapper)
+ {
+ }
+ //! Copy constructor
+ template< typename CharT >
+ basic_event_composer< CharT >::basic_event_composer(basic_event_composer const& that) :
+ m_EventIDMapper(that.m_EventIDMapper),
+ m_EventMap(that.m_EventMap)
+ {
+ }
+ //! Destructor
+ template< typename CharT >
+ basic_event_composer< CharT >::~basic_event_composer()
+ {
+ }
+
+ //! Assignment
+ template< typename CharT >
+ basic_event_composer< CharT >& basic_event_composer< CharT >::operator= (basic_event_composer that)
+ {
+ swap(that);
+ return *this;
+ }
+ //! Swapping
+ template< typename CharT >
+ void basic_event_composer< CharT >::swap(basic_event_composer& that)
+ {
+ m_EventIDMapper.swap(that.m_EventIDMapper);
+ m_EventMap.swap(that.m_EventMap);
+ }
+ //! Creates a new entry for a message
+ template< typename CharT >
+ typename basic_event_composer< CharT >::event_map_reference
+ basic_event_composer< CharT >::operator[] (event_id id)
+ {
+ return event_map_reference(id, *this);
+ }
+ //! Creates a new entry for a message
+ template< typename CharT >
+ typename basic_event_composer< CharT >::event_map_reference
+ basic_event_composer< CharT >::operator[] (int id)
+ {
+ return event_map_reference(make_event_id(id), *this);
+ }
+
+ //! Event composition operator
+ template< typename CharT >
+ event_id basic_event_composer< CharT >::operator() (record_view const& rec, insertion_list& insertions) const
+ {
+ event_id id = m_EventIDMapper(rec);
+ typename event_map::const_iterator it = m_EventMap.find(id);
+ if (it != m_EventMap.end())
+ it->second(rec, insertions);
+ return id;
+ }
+
+ //! Adds a formatter to the insertion composers list
+ template< typename CharT >
+ typename basic_event_composer< CharT >::insertion_composer*
+ basic_event_composer< CharT >::add_formatter(event_id id, insertion_composer* composer, formatter_type const& fmt)
+ {
+ if (!composer)
+ composer = &m_EventMap[id];
+ composer->add_formatter(fmt);
+ return composer;
+ }
+
+#ifdef BOOST_LOG_USE_CHAR
+ template class BOOST_LOG_API basic_event_composer< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template class BOOST_LOG_API basic_event_composer< wchar_t >;
+#endif
+
+} // namespace event_log
+
+
+//! Backend implementation
+template< typename CharT >
+struct basic_event_log_backend< CharT >::implementation
+{
+ // NOTE: This order of data members is critical for MSVC 9.0 in debug mode,
+ // as it ICEs if boost::functions are not the first members. Doh!
+
+ //! An event category mapper
+ event_category_mapper_type m_CategoryMapper;
+ //! A level mapping functor
+ event_type_mapper_type m_LevelMapper;
+
+ //! A handle for the registered event provider
+ HANDLE m_SourceHandle;
+ //! A functor that composes an event
+ event_composer_type m_EventComposer;
+ //! An array of formatted insertions
+ insertion_list m_Insertions;
+
+ implementation() : m_SourceHandle(0)
+ {
+ }
+};
+
+//! Destructor
+template< typename CharT >
+BOOST_LOG_API basic_event_log_backend< CharT >::~basic_event_log_backend()
+{
+ DeregisterEventSource(m_pImpl->m_SourceHandle);
+ delete m_pImpl;
+}
+
+//! Constructs backend implementation
+template< typename CharT >
+BOOST_LOG_API void basic_event_log_backend< CharT >::construct(
+ filesystem::path const& message_file_name,
+ string_type const& target,
+ string_type const& log_name,
+ string_type const& source_name,
+ event_log::registration_mode reg_mode)
+{
+ if (reg_mode != event_log::never)
+ {
+ if (message_file_name.empty())
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Message file name not specified."));
+ aux::registry_params< char_type > reg_params;
+ string_type file_name;
+ log::aux::code_convert(message_file_name.string(), file_name);
+ reg_params.event_message_file = file_name;
+ reg_params.types_supported = DWORD(
+ EVENTLOG_SUCCESS |
+ EVENTLOG_INFORMATION_TYPE |
+ EVENTLOG_WARNING_TYPE |
+ EVENTLOG_ERROR_TYPE);
+ aux::init_event_log_registry(log_name, source_name, reg_mode == event_log::forced, reg_params);
+ }
+
+ log::aux::unique_ptr< implementation > p(new implementation());
+
+ const char_type* target_unc = NULL;
+ if (!target.empty())
+ target_unc = target.c_str();
+
+ HANDLE hSource = register_event_source(target_unc, source_name.c_str());
+ if (!hSource)
+ {
+ const DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not register event source", (err));
+ }
+
+ p->m_SourceHandle = hSource;
+
+ m_pImpl = p.release();
+}
+
+//! The method puts the formatted message to the event log
+template< typename CharT >
+BOOST_LOG_API void basic_event_log_backend< CharT >::consume(record_view const& rec)
+{
+ if (!m_pImpl->m_EventComposer.empty())
+ {
+ log::aux::cleanup_guard< insertion_list > cleaner(m_pImpl->m_Insertions);
+
+ // Get event ID and construct insertions
+ DWORD id = m_pImpl->m_EventComposer(rec, m_pImpl->m_Insertions);
+ WORD string_count = static_cast< WORD >(m_pImpl->m_Insertions.size());
+ scoped_array< const char_type* > strings(new const char_type*[string_count]);
+ for (WORD i = 0; i < string_count; ++i)
+ strings[i] = m_pImpl->m_Insertions[i].c_str();
+
+ // Get event type
+ WORD event_type = EVENTLOG_INFORMATION_TYPE;
+ if (!m_pImpl->m_LevelMapper.empty())
+ event_type = static_cast< WORD >(m_pImpl->m_LevelMapper(rec));
+
+ WORD event_category = 0;
+ if (!m_pImpl->m_CategoryMapper.empty())
+ event_category = static_cast< WORD >(m_pImpl->m_CategoryMapper(rec));
+
+ report_event(
+ m_pImpl->m_SourceHandle, // Event log handle.
+ event_type, // Event type.
+ event_category, // Event category.
+ id, // Event identifier.
+ NULL, // No user security identifier.
+ string_count, // Number of substitution strings.
+ 0, // No data.
+ strings.get(), // Pointer to strings.
+ NULL); // No data.
+ }
+}
+
+//! Returns default log name
+template< typename CharT >
+BOOST_LOG_API typename basic_event_log_backend< CharT >::string_type
+basic_event_log_backend< CharT >::get_default_log_name()
+{
+ return aux::registry_traits< char_type >::make_default_log_name();
+}
+
+//! Returns default source name
+template< typename CharT >
+BOOST_LOG_API typename basic_event_log_backend< CharT >::string_type
+basic_event_log_backend< CharT >::get_default_source_name()
+{
+ string_type source_name = aux::registry_traits< char_type >::make_default_source_name();
+ complete_default_event_log_source_name(source_name);
+ return source_name;
+}
+
+//! The method installs the function object that maps application severity levels to WinAPI event types
+template< typename CharT >
+BOOST_LOG_API void basic_event_log_backend< CharT >::set_event_type_mapper(event_type_mapper_type const& mapper)
+{
+ m_pImpl->m_LevelMapper = mapper;
+}
+
+//! The method installs the function object that extracts event category from attribute values
+template< typename CharT >
+BOOST_LOG_API void basic_event_log_backend< CharT >::set_event_category_mapper(event_category_mapper_type const& mapper)
+{
+ m_pImpl->m_CategoryMapper = mapper;
+}
+
+/*!
+ * The method installs the function object that extracts event identifier from the attributes and creates
+ * insertion strings that will replace placeholders in the event message.
+ */
+template< typename CharT >
+BOOST_LOG_API void basic_event_log_backend< CharT >::set_event_composer(event_composer_type const& composer)
+{
+ m_pImpl->m_EventComposer = composer;
+}
+
+
+#ifdef BOOST_LOG_USE_CHAR
+template class basic_simple_event_log_backend< char >;
+template class basic_event_log_backend< char >;
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+template class basic_simple_event_log_backend< wchar_t >;
+template class basic_event_log_backend< wchar_t >;
+#endif
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_WITHOUT_EVENT_LOG)
diff --git a/src/boost/libs/log/src/windows/event_log_registry.hpp b/src/boost/libs/log/src/windows/event_log_registry.hpp
new file mode 100644
index 000000000..9d1579acc
--- /dev/null
+++ b/src/boost/libs/log/src/windows/event_log_registry.hpp
@@ -0,0 +1,491 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file event_log_registry.hpp
+ * \author Andrey Semashev
+ * \date 16.11.2008
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WINDOWS_EVENT_LOG_REGISTRY_HPP_INCLUDED_
+#define BOOST_LOG_WINDOWS_EVENT_LOG_REGISTRY_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <cwchar>
+#include <cstring>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <boost/version.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/log/detail/code_conversion.hpp>
+#include <boost/log/exceptions.hpp>
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace sinks {
+
+namespace aux {
+
+// MSVC versions up to 2008 (or their Platform SDKs, to be more precise) don't define LSTATUS.
+// Perhaps, that is also the case for MinGW and Cygwin (untested).
+typedef DWORD LSTATUS;
+
+// Max registry string size, in characters (for security reasons)
+const DWORD max_string_size = 64u * 1024u;
+
+//! Helper traits to integrate with WinAPI
+template< typename CharT >
+struct registry_traits;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct registry_traits< char >
+{
+ static std::string make_event_log_key(std::string const& log_name, std::string const& source_name)
+ {
+ return "SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + log_name + "\\" + source_name;
+ }
+
+ static std::string make_default_log_name()
+ {
+ return "Application";
+ }
+
+ static std::string make_default_source_name()
+ {
+ char buf[MAX_PATH];
+ DWORD size = GetModuleFileNameA(NULL, buf, sizeof(buf) / sizeof(*buf));
+
+ std::string source_name(buf, buf + size);
+ if (source_name.empty())
+ {
+ // In case of error we provide artificial application name
+ std::ostringstream strm;
+ strm << "Boost.Log "
+ << static_cast< unsigned int >(BOOST_VERSION / 100000)
+ << "."
+ << static_cast< unsigned int >(BOOST_VERSION / 100 % 1000)
+ << "."
+ << static_cast< unsigned int >(BOOST_VERSION % 100);
+ source_name = strm.str();
+ }
+ else
+ {
+ // Cut off the path and extension
+ std::size_t backslash_pos = source_name.rfind('\\');
+ if (backslash_pos == std::string::npos || backslash_pos >= source_name.size() - 1)
+ backslash_pos = 0;
+ else
+ ++backslash_pos;
+ std::size_t dot_pos = source_name.rfind('.');
+ if (dot_pos == std::string::npos || dot_pos < backslash_pos)
+ dot_pos = source_name.size();
+ source_name = source_name.substr(backslash_pos, dot_pos - backslash_pos);
+ }
+
+ return source_name;
+ }
+
+ static LSTATUS create_key(
+ HKEY hKey,
+ const char* lpSubKey,
+ DWORD Reserved,
+ char* lpClass,
+ DWORD dwOptions,
+ REGSAM samDesired,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ PHKEY phkResult,
+ LPDWORD lpdwDisposition)
+ {
+ return RegCreateKeyExA(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
+ }
+
+ static LSTATUS open_key(
+ HKEY hKey,
+ const char* lpSubKey,
+ DWORD dwOptions,
+ REGSAM samDesired,
+ PHKEY phkResult)
+ {
+ return RegOpenKeyExA(hKey, lpSubKey, dwOptions, samDesired, phkResult);
+ }
+
+ static LSTATUS set_value(
+ HKEY hKey,
+ const char* lpValueName,
+ DWORD Reserved,
+ DWORD dwType,
+ const BYTE* lpData,
+ DWORD cbData)
+ {
+ return RegSetValueExA(hKey, lpValueName, Reserved, dwType, lpData, cbData);
+ }
+
+ static LSTATUS get_value(HKEY hKey, const char* lpValueName, DWORD& value)
+ {
+ DWORD type = REG_NONE, size = sizeof(value);
+ LSTATUS res = RegQueryValueExA(hKey, lpValueName, NULL, &type, reinterpret_cast< LPBYTE >(&value), &size);
+ if (res == ERROR_SUCCESS && type != REG_DWORD && type != REG_BINARY)
+ res = ERROR_INVALID_DATA;
+ return res;
+ }
+
+ static LSTATUS get_value(HKEY hKey, const char* lpValueName, std::string& value)
+ {
+ DWORD type = REG_NONE, size = 0;
+ LSTATUS res = RegQueryValueExA(hKey, lpValueName, NULL, &type, NULL, &size);
+ if (res == ERROR_SUCCESS && ((type != REG_EXPAND_SZ && type != REG_SZ) || size > max_string_size))
+ return ERROR_INVALID_DATA;
+ if (size == 0)
+ return res;
+
+ value.resize(size);
+ res = RegQueryValueExA(hKey, lpValueName, NULL, &type, reinterpret_cast< LPBYTE >(&value[0]), &size);
+ value.resize(std::strlen(value.c_str())); // remove extra terminating zero
+
+ return res;
+ }
+
+ static const char* get_event_message_file_param_name() { return "EventMessageFile"; }
+ static const char* get_category_message_file_param_name() { return "CategoryMessageFile"; }
+ static const char* get_category_count_param_name() { return "CategoryCount"; }
+ static const char* get_types_supported_param_name() { return "TypesSupported"; }
+};
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct registry_traits< wchar_t >
+{
+ static std::wstring make_event_log_key(std::wstring const& log_name, std::wstring const& source_name)
+ {
+ return L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + log_name + L"\\" + source_name;
+ }
+
+ static std::wstring make_default_log_name()
+ {
+ return L"Application";
+ }
+
+ static std::wstring make_default_source_name()
+ {
+ wchar_t buf[MAX_PATH];
+ DWORD size = GetModuleFileNameW(NULL, buf, sizeof(buf) / sizeof(*buf));
+
+ std::wstring source_name(buf, buf + size);
+ if (source_name.empty())
+ {
+ // In case of error we provide artificial application name
+ std::wostringstream strm;
+ strm << L"Boost.Log "
+ << static_cast< unsigned int >(BOOST_VERSION / 100000)
+ << L"."
+ << static_cast< unsigned int >(BOOST_VERSION / 100 % 1000)
+ << L"."
+ << static_cast< unsigned int >(BOOST_VERSION % 100);
+ source_name = strm.str();
+ }
+ else
+ {
+ // Cut off the path and extension
+ std::size_t backslash_pos = source_name.rfind(L'\\');
+ if (backslash_pos == std::wstring::npos || backslash_pos >= source_name.size() - 1)
+ backslash_pos = 0;
+ else
+ ++backslash_pos;
+ std::size_t dot_pos = source_name.rfind(L'.');
+ if (dot_pos == std::wstring::npos || dot_pos < backslash_pos)
+ dot_pos = source_name.size();
+ source_name = source_name.substr(backslash_pos, dot_pos - backslash_pos);
+ }
+
+ return source_name;
+ }
+
+ static LSTATUS create_key(
+ HKEY hKey,
+ const wchar_t* lpSubKey,
+ DWORD Reserved,
+ wchar_t* lpClass,
+ DWORD dwOptions,
+ REGSAM samDesired,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ PHKEY phkResult,
+ LPDWORD lpdwDisposition)
+ {
+ return RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
+ }
+
+ static LSTATUS open_key(
+ HKEY hKey,
+ const wchar_t* lpSubKey,
+ DWORD dwOptions,
+ REGSAM samDesired,
+ PHKEY phkResult)
+ {
+ return RegOpenKeyExW(hKey, lpSubKey, dwOptions, samDesired, phkResult);
+ }
+
+ static LSTATUS set_value(
+ HKEY hKey,
+ const wchar_t* lpValueName,
+ DWORD Reserved,
+ DWORD dwType,
+ const BYTE* lpData,
+ DWORD cbData)
+ {
+ return RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData);
+ }
+
+ static LSTATUS get_value(HKEY hKey, const wchar_t* lpValueName, DWORD& value)
+ {
+ DWORD type = REG_NONE, size = sizeof(value);
+ LSTATUS res = RegQueryValueExW(hKey, lpValueName, NULL, &type, reinterpret_cast< LPBYTE >(&value), &size);
+ if (res == ERROR_SUCCESS && type != REG_DWORD && type != REG_BINARY)
+ res = ERROR_INVALID_DATA;
+ return res;
+ }
+
+ static LSTATUS get_value(HKEY hKey, const wchar_t* lpValueName, std::wstring& value)
+ {
+ DWORD type = REG_NONE, size = 0;
+ LSTATUS res = RegQueryValueExW(hKey, lpValueName, NULL, &type, NULL, &size);
+ size /= sizeof(wchar_t);
+ if (res == ERROR_SUCCESS && ((type != REG_EXPAND_SZ && type != REG_SZ) || size > max_string_size))
+ return ERROR_INVALID_DATA;
+ if (size == 0)
+ return res;
+
+ value.resize(size);
+ res = RegQueryValueExW(hKey, lpValueName, NULL, &type, reinterpret_cast< LPBYTE >(&value[0]), &size);
+ value.resize(std::wcslen(value.c_str())); // remove extra terminating zero
+
+ return res;
+ }
+
+ static const wchar_t* get_event_message_file_param_name() { return L"EventMessageFile"; }
+ static const wchar_t* get_category_message_file_param_name() { return L"CategoryMessageFile"; }
+ static const wchar_t* get_category_count_param_name() { return L"CategoryCount"; }
+ static const wchar_t* get_types_supported_param_name() { return L"TypesSupported"; }
+
+};
+#endif // BOOST_LOG_USE_WCHAR_T
+
+//! The structure with parameters that have to be registered in the event log registry key
+template< typename CharT >
+struct registry_params
+{
+ typedef std::basic_string< CharT > string_type;
+
+ optional< string_type > event_message_file;
+ optional< string_type > category_message_file;
+ optional< DWORD > category_count;
+ optional< DWORD > types_supported;
+};
+
+//! A simple guard that closes the registry key on destruction
+struct auto_hkey_close
+{
+ explicit auto_hkey_close(HKEY hk) : hk_(hk) {}
+ ~auto_hkey_close() { RegCloseKey(hk_); }
+
+private:
+ HKEY hk_;
+};
+
+//! The function checks if the event log is already registered
+template< typename CharT >
+bool verify_event_log_registry(std::basic_string< CharT > const& reg_key, bool force, registry_params< CharT > const& params)
+{
+ typedef std::basic_string< CharT > string_type;
+ typedef registry_traits< CharT > registry;
+
+ // Open the key
+ HKEY hkey = 0;
+ LSTATUS res = registry::open_key(
+ HKEY_LOCAL_MACHINE,
+ reg_key.c_str(),
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ,
+ &hkey);
+ if (res != ERROR_SUCCESS)
+ return false;
+
+ auto_hkey_close hkey_guard(hkey);
+
+ if (force)
+ {
+ // Verify key values
+ if (!!params.event_message_file)
+ {
+ string_type module_name;
+ res = registry::get_value(hkey, registry::get_event_message_file_param_name(), module_name);
+ if (res != ERROR_SUCCESS || module_name != params.event_message_file.get())
+ return false;
+ }
+
+ if (!!params.category_message_file)
+ {
+ string_type module_name;
+ res = registry::get_value(hkey, registry::get_category_message_file_param_name(), module_name);
+ if (res != ERROR_SUCCESS || module_name != params.category_message_file.get())
+ return false;
+ }
+
+ if (!!params.category_count)
+ {
+ // Set number of categories
+ DWORD category_count = 0;
+ res = registry::get_value(hkey, registry::get_category_count_param_name(), category_count);
+ if (res != ERROR_SUCCESS || category_count != params.category_count.get())
+ return false;
+ }
+
+ if (!!params.types_supported)
+ {
+ // Set the supported event types
+ DWORD event_types = 0;
+ res = registry::get_value(hkey, registry::get_types_supported_param_name(), event_types);
+ if (res != ERROR_SUCCESS || event_types != params.types_supported.get())
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//! The function initializes the event log registry key
+template< typename CharT >
+void init_event_log_registry(
+ std::basic_string< CharT > const& log_name,
+ std::basic_string< CharT > const& source_name,
+ bool force,
+ registry_params< CharT > const& params)
+{
+ typedef std::basic_string< CharT > string_type;
+ typedef registry_traits< CharT > registry;
+ // Registry key name that contains log description
+ string_type reg_key = registry::make_event_log_key(log_name, source_name);
+
+ // First check the registry keys and values in read-only mode.
+ // This allows to avoid UAC asking for elevated permissions to modify HKLM registry when no modification is actually needed.
+ if (verify_event_log_registry(reg_key, force, params))
+ return;
+
+ // Create or open the key
+ HKEY hkey = 0;
+ DWORD disposition = 0;
+ LSTATUS res = registry::create_key(
+ HKEY_LOCAL_MACHINE,
+ reg_key.c_str(),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &hkey,
+ &disposition);
+ if (res != ERROR_SUCCESS)
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not create registry key for the event log", (res));
+
+ auto_hkey_close hkey_guard(hkey);
+
+ if (disposition != REG_OPENED_EXISTING_KEY || force)
+ {
+ // Fill registry values
+ if (!!params.event_message_file)
+ {
+ // Set the module file name that contains event resources
+ string_type const& module_name = params.event_message_file.get();
+ res = registry::set_value(
+ hkey,
+ registry::get_event_message_file_param_name(),
+ 0,
+ REG_EXPAND_SZ,
+ reinterpret_cast< LPBYTE >(const_cast< CharT* >(module_name.c_str())),
+ static_cast< DWORD >((module_name.size() + 1) * sizeof(CharT)));
+ if (res != ERROR_SUCCESS)
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not create registry value "
+ + log::aux::to_narrow(string_type(registry::get_event_message_file_param_name())), (res));
+ }
+ }
+
+ if (!!params.category_message_file)
+ {
+ // Set the module file name that contains event category resources
+ string_type const& module_name = params.category_message_file.get();
+ res = registry::set_value(
+ hkey,
+ registry::get_category_message_file_param_name(),
+ 0,
+ REG_SZ,
+ reinterpret_cast< LPBYTE >(const_cast< CharT* >(module_name.c_str())),
+ static_cast< DWORD >((module_name.size() + 1) * sizeof(CharT)));
+ if (res != ERROR_SUCCESS)
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not create registry value "
+ + log::aux::to_narrow(string_type(registry::get_category_message_file_param_name())), (res));
+ }
+ }
+
+ if (!!params.category_count)
+ {
+ // Set number of categories
+ DWORD category_count = params.category_count.get();
+ res = registry::set_value(
+ hkey,
+ registry::get_category_count_param_name(),
+ 0,
+ REG_DWORD,
+ reinterpret_cast< LPBYTE >(&category_count),
+ static_cast< DWORD >(sizeof(category_count)));
+ if (res != ERROR_SUCCESS)
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not create registry value "
+ + log::aux::to_narrow(string_type(registry::get_category_count_param_name())), (res));
+ }
+ }
+
+ if (!!params.types_supported)
+ {
+ // Set the supported event types
+ DWORD event_types = params.types_supported.get();
+ res = registry::set_value(
+ hkey,
+ registry::get_types_supported_param_name(),
+ 0,
+ REG_DWORD,
+ reinterpret_cast< LPBYTE >(&event_types),
+ static_cast< DWORD >(sizeof(event_types)));
+ if (res != ERROR_SUCCESS)
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not create registry value "
+ + log::aux::to_narrow(string_type(registry::get_types_supported_param_name())), (res));
+ }
+ }
+ }
+}
+
+} // namespace aux
+
+} // namespace sinks
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WINDOWS_EVENT_LOG_REGISTRY_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/windows/ipc_reliable_message_queue.cpp b/src/boost/libs/log/src/windows/ipc_reliable_message_queue.cpp
new file mode 100644
index 000000000..d99d091d1
--- /dev/null
+++ b/src/boost/libs/log/src/windows/ipc_reliable_message_queue.cpp
@@ -0,0 +1,818 @@
+/*
+ * Copyright Lingxi Li 2015.
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file ipc_reliable_message_queue_win.hpp
+ * \author Lingxi Li
+ * \author Andrey Semashev
+ * \date 28.10.2015
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ *
+ * This file provides an interprocess message queue implementation on POSIX platforms.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <cstring>
+#include <new>
+#include <limits>
+#include <string>
+#include <algorithm>
+#include <stdexcept>
+#include <boost/assert.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/atomic/capabilities.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/ipc/reliable_message_queue.hpp>
+#include <boost/log/support/exception.hpp>
+#include <boost/log/detail/pause.hpp>
+#include <boost/exception/info.hpp>
+#include <boost/exception/enable_error_info.hpp>
+#include <boost/align/align_up.hpp>
+#include <boost/winapi/thread.hpp> // SwitchToThread
+#include "windows/ipc_sync_wrappers.hpp"
+#include "windows/mapped_shared_memory.hpp"
+#include "windows/utf_code_conversion.hpp"
+#include "murmur3.hpp"
+#include "bit_tools.hpp"
+#include <windows.h>
+#include <boost/log/detail/header.hpp>
+
+#if BOOST_ATOMIC_INT32_LOCK_FREE != 2
+// 32-bit atomic ops are required to be able to place atomic<uint32_t> in the process-shared memory
+#error Boost.Log: Native 32-bit atomic operations are required but not supported by Boost.Atomic on the target platform
+#endif
+
+//! A suffix used in names of interprocess objects created by the queue.
+//! Used as a protection against clashing with user-supplied names of interprocess queues and also to resolve conflicts between queues of different types.
+#define BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".3010b9950926463398eee00b35b44651"
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+//! Message queue implementation data
+struct reliable_message_queue::implementation
+{
+private:
+ //! Header of an allocation block within the message queue. Placed at the beginning of the block within the shared memory segment.
+ struct block_header
+ {
+ // Element data alignment, in bytes
+ enum { data_alignment = 32u };
+
+ //! Size of the element data, in bytes
+ size_type m_size;
+
+ //! Returns the block header overhead, in bytes
+ static BOOST_CONSTEXPR size_type get_header_overhead() BOOST_NOEXCEPT
+ {
+ return static_cast< size_type >(boost::alignment::align_up(sizeof(block_header), data_alignment));
+ }
+
+ //! Returns a pointer to the element data
+ void* get_data() const BOOST_NOEXCEPT
+ {
+ return const_cast< unsigned char* >(reinterpret_cast< const unsigned char* >(this)) + get_header_overhead();
+ }
+ };
+
+ //! Header of the message queue. Placed at the beginning of the shared memory segment.
+ struct header
+ {
+ // Increment this constant whenever you change the binary layout of the queue (apart from this header structure)
+ enum { abi_version = 0 };
+
+ // !!! Whenever you add/remove members in this structure, also modify get_abi_tag() function accordingly !!!
+
+ //! A tag value to ensure the correct binary layout of the message queue data structures. Must be placed first and always have a fixed size and alignment.
+ uint32_t m_abi_tag;
+ //! Padding to protect against alignment changes in Boost.Atomic. Don't use BOOST_ALIGNMENT to ensure portability.
+ unsigned char m_padding[BOOST_LOG_CPU_CACHE_LINE_SIZE - sizeof(uint32_t)];
+ //! A flag indicating that the queue is constructed (i.e. the queue is constructed when the value is not 0).
+ boost::atomic< uint32_t > m_initialized;
+ //! Number of allocation blocks in the queue.
+ const uint32_t m_capacity;
+ //! Size of an allocation block, in bytes.
+ const size_type m_block_size;
+ //! Shared state of the mutex for protecting queue data structures.
+ boost::log::ipc::aux::interprocess_mutex::shared_state m_mutex_state;
+ //! Shared state of the condition variable used to block writers when the queue is full.
+ boost::log::ipc::aux::interprocess_condition_variable::shared_state m_nonfull_queue_state;
+ //! The current number of allocated blocks in the queue.
+ uint32_t m_size;
+ //! The current writing position (allocation block index).
+ uint32_t m_put_pos;
+ //! The current reading position (allocation block index).
+ uint32_t m_get_pos;
+
+ header(uint32_t capacity, size_type block_size) :
+ m_abi_tag(get_abi_tag()),
+ m_capacity(capacity),
+ m_block_size(block_size),
+ m_size(0u),
+ m_put_pos(0u),
+ m_get_pos(0u)
+ {
+ // Must be initialized last. m_initialized is zero-initialized initially.
+ m_initialized.fetch_add(1u, boost::memory_order_release);
+ }
+
+ //! Returns the header structure ABI tag
+ static uint32_t get_abi_tag() BOOST_NOEXCEPT
+ {
+ // This FOURCC identifies the queue type
+ boost::log::aux::murmur3_32 hash(boost::log::aux::make_fourcc('r', 'e', 'l', 'q'));
+
+ // This FOURCC identifies the queue implementation
+ hash.mix(boost::log::aux::make_fourcc('w', 'n', 't', '5'));
+ hash.mix(abi_version);
+
+ // We will use these constants to align pointers
+ hash.mix(BOOST_LOG_CPU_CACHE_LINE_SIZE);
+ hash.mix(block_header::data_alignment);
+
+ // The members in the sequence below must be enumerated in the same order as they are declared in the header structure.
+ // The ABI tag is supposed change whenever a member changes size or offset from the beginning of the header.
+
+#define BOOST_LOG_MIX_HEADER_MEMBER(name)\
+ hash.mix(static_cast< uint32_t >(sizeof(((header*)NULL)->name)));\
+ hash.mix(static_cast< uint32_t >(offsetof(header, name)))
+
+ BOOST_LOG_MIX_HEADER_MEMBER(m_abi_tag);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_padding);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_initialized);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_capacity);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_block_size);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_mutex_state);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_nonfull_queue_state);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_size);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_put_pos);
+ BOOST_LOG_MIX_HEADER_MEMBER(m_get_pos);
+
+#undef BOOST_LOG_MIX_HEADER_MEMBER
+
+ return hash.finalize();
+ }
+
+ //! Returns an element header at the specified index
+ block_header* get_block(uint32_t index) const BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT(index < m_capacity);
+ unsigned char* p = const_cast< unsigned char* >(reinterpret_cast< const unsigned char* >(this)) + boost::alignment::align_up(sizeof(header), BOOST_LOG_CPU_CACHE_LINE_SIZE);
+ p += static_cast< std::size_t >(m_block_size) * static_cast< std::size_t >(index);
+ return reinterpret_cast< block_header* >(p);
+ }
+
+ BOOST_DELETED_FUNCTION(header(header const&))
+ BOOST_DELETED_FUNCTION(header& operator=(header const&))
+ };
+
+private:
+ //! Shared memory object and mapping
+ boost::log::ipc::aux::mapped_shared_memory m_shared_memory;
+ //! Queue overflow handling policy
+ const overflow_policy m_overflow_policy;
+ //! The mask for selecting bits that constitute size values from 0 to (block_size - 1)
+ size_type m_block_size_mask;
+ //! The number of the bit set in block_size (i.e. log base 2 of block_size)
+ uint32_t m_block_size_log2;
+
+ //! Mutex for protecting queue data structures.
+ boost::log::ipc::aux::interprocess_mutex m_mutex;
+ //! Event used to block readers when the queue is empty.
+ boost::log::ipc::aux::interprocess_event m_nonempty_queue;
+ //! Condition variable used to block writers when the queue is full.
+ boost::log::ipc::aux::interprocess_condition_variable m_nonfull_queue;
+ //! The event indicates that stop has been requested
+ boost::log::ipc::aux::auto_handle m_stop;
+
+ //! The queue name, as specified by the user
+ const object_name m_name;
+
+public:
+ //! The constructor creates a new shared memory segment
+ implementation
+ (
+ open_mode::create_only_tag,
+ object_name const& name,
+ uint32_t capacity,
+ size_type block_size,
+ overflow_policy oflow_policy,
+ permissions const& perms
+ ) :
+ m_overflow_policy(oflow_policy),
+ m_block_size_mask(0u),
+ m_block_size_log2(0u),
+ m_name(name)
+ {
+ const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str());
+ const std::size_t shmem_size = estimate_region_size(capacity, block_size);
+ m_shared_memory.create(wname.c_str(), shmem_size, perms);
+ m_shared_memory.map();
+
+ create_queue(wname, capacity, block_size, perms);
+ }
+
+ //! The constructor creates a new shared memory segment or opens the existing one
+ implementation
+ (
+ open_mode::open_or_create_tag,
+ object_name const& name,
+ uint32_t capacity,
+ size_type block_size,
+ overflow_policy oflow_policy,
+ permissions const& perms
+ ) :
+ m_overflow_policy(oflow_policy),
+ m_block_size_mask(0u),
+ m_block_size_log2(0u),
+ m_name(name)
+ {
+ const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str());
+ const std::size_t shmem_size = estimate_region_size(capacity, block_size);
+ const bool created = m_shared_memory.create_or_open(wname.c_str(), shmem_size, perms);
+ m_shared_memory.map();
+
+ if (created)
+ create_queue(wname, capacity, block_size, perms);
+ else
+ adopt_queue(wname, m_shared_memory.size(), perms);
+ }
+
+ //! The constructor opens the existing shared memory segment
+ implementation
+ (
+ open_mode::open_only_tag,
+ object_name const& name,
+ overflow_policy oflow_policy,
+ permissions const& perms
+ ) :
+ m_overflow_policy(oflow_policy),
+ m_block_size_mask(0u),
+ m_block_size_log2(0u),
+ m_name(name)
+ {
+ const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str());
+ m_shared_memory.open(wname.c_str());
+ m_shared_memory.map();
+
+ adopt_queue(wname, m_shared_memory.size(), perms);
+ }
+
+ object_name const& name() const BOOST_NOEXCEPT
+ {
+ return m_name;
+ }
+
+ uint32_t capacity() const BOOST_NOEXCEPT
+ {
+ return get_header()->m_capacity;
+ }
+
+ size_type block_size() const BOOST_NOEXCEPT
+ {
+ return get_header()->m_block_size;
+ }
+
+ operation_result send(void const* message_data, size_type message_size)
+ {
+ const uint32_t block_count = estimate_block_count(message_size);
+
+ header* const hdr = get_header();
+
+ if (BOOST_UNLIKELY(block_count > hdr->m_capacity))
+ BOOST_LOG_THROW_DESCR(logic_error, "Message size exceeds the interprocess queue capacity");
+
+ if (!lock_queue())
+ return aborted;
+
+ boost::log::ipc::aux::interprocess_mutex::optional_unlock unlock(m_mutex);
+
+ while (true)
+ {
+ if ((hdr->m_capacity - hdr->m_size) >= block_count)
+ break;
+
+ const overflow_policy oflow_policy = m_overflow_policy;
+ if (oflow_policy == fail_on_overflow)
+ return no_space;
+ else if (BOOST_UNLIKELY(oflow_policy == throw_on_overflow))
+ BOOST_LOG_THROW_DESCR(capacity_limit_reached, "Interprocess queue is full");
+
+ if (!m_nonfull_queue.wait(unlock, m_stop.get()))
+ return aborted;
+ }
+
+ enqueue_message(message_data, message_size, block_count);
+
+ return succeeded;
+ }
+
+ bool try_send(void const* message_data, size_type message_size)
+ {
+ const uint32_t block_count = estimate_block_count(message_size);
+
+ header* const hdr = get_header();
+
+ if (BOOST_UNLIKELY(block_count > hdr->m_capacity))
+ BOOST_LOG_THROW_DESCR(logic_error, "Message size exceeds the interprocess queue capacity");
+
+ if (!lock_queue())
+ return false;
+
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(m_mutex);
+
+ if ((hdr->m_capacity - hdr->m_size) < block_count)
+ return false;
+
+ enqueue_message(message_data, message_size, block_count);
+
+ return true;
+ }
+
+ operation_result receive(receive_handler handler, void* state)
+ {
+ if (!lock_queue())
+ return aborted;
+
+ boost::log::ipc::aux::interprocess_mutex::optional_unlock unlock(m_mutex);
+
+ header* const hdr = get_header();
+
+ while (true)
+ {
+ if (hdr->m_size > 0u)
+ break;
+
+ m_mutex.unlock();
+ unlock.disengage();
+
+ if (!m_nonempty_queue.wait(m_stop.get()) || !lock_queue())
+ return aborted;
+
+ unlock.engage(m_mutex);
+ }
+
+ dequeue_message(handler, state);
+
+ return succeeded;
+ }
+
+ bool try_receive(receive_handler handler, void* state)
+ {
+ if (!lock_queue())
+ return false;
+
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(m_mutex);
+
+ header* const hdr = get_header();
+ if (hdr->m_size == 0u)
+ return false;
+
+ dequeue_message(handler, state);
+
+ return true;
+ }
+
+ void stop_local()
+ {
+ BOOST_VERIFY(boost::winapi::SetEvent(m_stop.get()) != 0);
+ }
+
+ void reset_local()
+ {
+ BOOST_VERIFY(boost::winapi::ResetEvent(m_stop.get()) != 0);
+ }
+
+ void clear()
+ {
+ m_mutex.lock();
+ boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(m_mutex);
+ clear_queue();
+ }
+
+private:
+ header* get_header() const BOOST_NOEXCEPT
+ {
+ return static_cast< header* >(m_shared_memory.address());
+ }
+
+ static std::size_t estimate_region_size(uint32_t capacity, size_type block_size) BOOST_NOEXCEPT
+ {
+ return boost::alignment::align_up(sizeof(header), BOOST_LOG_CPU_CACHE_LINE_SIZE) + static_cast< std::size_t >(capacity) * static_cast< std::size_t >(block_size);
+ }
+
+ void create_stop_event()
+ {
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ boost::winapi::HANDLE_ h = boost::winapi::CreateEventExW
+ (
+ NULL, // permissions
+ NULL, // name
+ boost::winapi::CREATE_EVENT_MANUAL_RESET_,
+ boost::winapi::SYNCHRONIZE_ | boost::winapi::EVENT_MODIFY_STATE_
+ );
+#else
+ boost::winapi::HANDLE_ h = boost::winapi::CreateEventW
+ (
+ NULL, // permissions
+ true, // manual reset
+ false, // initial state
+ NULL // name
+ );
+#endif
+ if (BOOST_UNLIKELY(h == NULL))
+ {
+ boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create an stop event object", (err));
+ }
+
+ m_stop.init(h);
+ }
+
+ void create_queue(std::wstring const& name, uint32_t capacity, size_type block_size, permissions const& perms)
+ {
+ // Initialize synchronization primitives before initializing the header as the openers will wait for it to be initialized
+ header* const hdr = get_header();
+ m_mutex.create((name + BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".mutex").c_str(), &hdr->m_mutex_state, perms);
+ m_nonempty_queue.create((name + BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".nonempty_queue_event").c_str(), false, perms);
+ m_nonfull_queue.init((name + BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".nonfull_queue_cond_var").c_str(), &hdr->m_nonfull_queue_state, perms);
+ create_stop_event();
+
+ new (hdr) header(capacity, block_size);
+
+ init_block_size(block_size);
+ }
+
+ void adopt_queue(std::wstring const& name, std::size_t shmem_size, permissions const& perms)
+ {
+ if (shmem_size < sizeof(header))
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment size too small");
+
+ // Wait until the mapped region becomes initialized
+ header* const hdr = get_header();
+ BOOST_CONSTEXPR_OR_CONST unsigned int wait_loops = 1000u, spin_loops = 16u, spins = 16u;
+ for (unsigned int i = 0; i < wait_loops; ++i)
+ {
+ uint32_t initialized = hdr->m_initialized.load(boost::memory_order_acquire);
+ if (initialized)
+ {
+ goto done;
+ }
+
+ if (i < spin_loops)
+ {
+ for (unsigned int j = 0; j < spins; ++j)
+ {
+ boost::log::aux::pause();
+ }
+ }
+ else
+ {
+ boost::winapi::SwitchToThread();
+ }
+ }
+
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment is not initialized by creator for too long");
+
+ done:
+ // Check that the queue layout matches the current process ABI
+ if (hdr->m_abi_tag != header::get_abi_tag())
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: the queue ABI is incompatible");
+
+ if (!boost::log::aux::is_power_of_2(hdr->m_block_size))
+ BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: the queue block size is not a power of 2");
+
+ m_mutex.open((name + BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".mutex").c_str(), &hdr->m_mutex_state);
+ m_nonempty_queue.open((name + BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".nonempty_queue_event").c_str());
+ m_nonfull_queue.init((name + BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".nonfull_queue_cond_var").c_str(), &hdr->m_nonfull_queue_state, perms);
+ create_stop_event();
+
+ init_block_size(hdr->m_block_size);
+ }
+
+ void init_block_size(size_type block_size)
+ {
+ m_block_size_mask = block_size - 1u;
+
+ uint32_t block_size_log2 = 0u;
+ if ((block_size & 0x0000ffff) == 0u)
+ {
+ block_size >>= 16u;
+ block_size_log2 += 16u;
+ }
+ if ((block_size & 0x000000ff) == 0u)
+ {
+ block_size >>= 8u;
+ block_size_log2 += 8u;
+ }
+ if ((block_size & 0x0000000f) == 0u)
+ {
+ block_size >>= 4u;
+ block_size_log2 += 4u;
+ }
+ if ((block_size & 0x00000003) == 0u)
+ {
+ block_size >>= 2u;
+ block_size_log2 += 2u;
+ }
+ if ((block_size & 0x00000001) == 0u)
+ {
+ ++block_size_log2;
+ }
+ m_block_size_log2 = block_size_log2;
+ }
+
+ bool lock_queue()
+ {
+ return m_mutex.lock(m_stop.get());
+ }
+
+ void clear_queue()
+ {
+ header* const hdr = get_header();
+ hdr->m_size = 0u;
+ hdr->m_put_pos = 0u;
+ hdr->m_get_pos = 0u;
+ m_nonfull_queue.notify_all();
+ }
+
+ //! Returns the number of allocation blocks that are required to store user's payload of the specified size
+ uint32_t estimate_block_count(size_type size) const BOOST_NOEXCEPT
+ {
+ // ceil((size + get_header_overhead()) / block_size)
+ return static_cast< uint32_t >((size + block_header::get_header_overhead() + m_block_size_mask) >> m_block_size_log2);
+ }
+
+ //! Puts the message to the back of the queue
+ void enqueue_message(void const* message_data, size_type message_size, uint32_t block_count)
+ {
+ header* const hdr = get_header();
+
+ const uint32_t capacity = hdr->m_capacity;
+ const size_type block_size = hdr->m_block_size;
+ uint32_t pos = hdr->m_put_pos;
+
+ block_header* block = hdr->get_block(pos);
+ block->m_size = message_size;
+
+ size_type write_size = (std::min)(static_cast< size_type >((capacity - pos) * block_size - block_header::get_header_overhead()), message_size);
+ std::memcpy(block->get_data(), message_data, write_size);
+
+ pos += block_count;
+ if (BOOST_UNLIKELY(pos >= capacity))
+ {
+ // Write the rest of the message at the beginning of the queue
+ pos -= capacity;
+ message_data = static_cast< const unsigned char* >(message_data) + write_size;
+ write_size = message_size - write_size;
+ if (write_size > 0u)
+ std::memcpy(hdr->get_block(0u), message_data, write_size);
+ }
+
+ hdr->m_put_pos = pos;
+
+ const uint32_t old_queue_size = hdr->m_size;
+ hdr->m_size = old_queue_size + block_count;
+ if (old_queue_size == 0u)
+ m_nonempty_queue.set();
+ }
+
+ //! Retrieves the next message and invokes the handler to store the message contents
+ void dequeue_message(receive_handler handler, void* state)
+ {
+ header* const hdr = get_header();
+
+ const uint32_t capacity = hdr->m_capacity;
+ const size_type block_size = hdr->m_block_size;
+ uint32_t pos = hdr->m_get_pos;
+
+ block_header* block = hdr->get_block(pos);
+ size_type message_size = block->m_size;
+ uint32_t block_count = estimate_block_count(message_size);
+
+ BOOST_ASSERT(block_count <= hdr->m_size);
+
+ size_type read_size = (std::min)(static_cast< size_type >((capacity - pos) * block_size - block_header::get_header_overhead()), message_size);
+ handler(state, block->get_data(), read_size);
+
+ pos += block_count;
+ if (BOOST_UNLIKELY(pos >= capacity))
+ {
+ // Read the tail of the message
+ pos -= capacity;
+ read_size = message_size - read_size;
+ if (read_size > 0u)
+ handler(state, hdr->get_block(0u), read_size);
+ }
+
+ hdr->m_get_pos = pos;
+ hdr->m_size -= block_count;
+
+ m_nonfull_queue.notify_all();
+ }
+};
+
+BOOST_LOG_API void reliable_message_queue::create(object_name const& name, uint32_t capacity, size_type block_size, overflow_policy oflow_policy, permissions const& perms)
+{
+ BOOST_ASSERT(m_impl == NULL);
+ if (!boost::log::aux::is_power_of_2(block_size))
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Interprocess message queue block size is not a power of 2"));
+ try
+ {
+ m_impl = new implementation(open_mode::create_only, name, capacity, static_cast< size_type >(boost::alignment::align_up(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE)), oflow_policy, perms);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(name);
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::open_or_create(object_name const& name, uint32_t capacity, size_type block_size, overflow_policy oflow_policy, permissions const& perms)
+{
+ BOOST_ASSERT(m_impl == NULL);
+ if (!boost::log::aux::is_power_of_2(block_size))
+ BOOST_THROW_EXCEPTION(std::invalid_argument("Interprocess message queue block size is not a power of 2"));
+ try
+ {
+ m_impl = new implementation(open_mode::open_or_create, name, capacity, static_cast< size_type >(boost::alignment::align_up(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE)), oflow_policy, perms);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(name);
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::open(object_name const& name, overflow_policy oflow_policy, permissions const& perms)
+{
+ BOOST_ASSERT(m_impl == NULL);
+ try
+ {
+ m_impl = new implementation(open_mode::open_only, name, oflow_policy, perms);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(name);
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::clear()
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ m_impl->clear();
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API object_name const& reliable_message_queue::name() const
+{
+ BOOST_ASSERT(m_impl != NULL);
+ return m_impl->name();
+}
+
+BOOST_LOG_API uint32_t reliable_message_queue::capacity() const
+{
+ BOOST_ASSERT(m_impl != NULL);
+ return m_impl->capacity();
+}
+
+BOOST_LOG_API reliable_message_queue::size_type reliable_message_queue::block_size() const
+{
+ BOOST_ASSERT(m_impl != NULL);
+ return m_impl->block_size();
+}
+
+BOOST_LOG_API void reliable_message_queue::stop_local()
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ m_impl->stop_local();
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::reset_local()
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ m_impl->reset_local();
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API void reliable_message_queue::do_close() BOOST_NOEXCEPT
+{
+ delete m_impl;
+ m_impl = NULL;
+}
+
+BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::send(void const* message_data, size_type message_size)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->send(message_data, message_size);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API bool reliable_message_queue::try_send(void const* message_data, size_type message_size)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->try_send(message_data, message_size);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::do_receive(receive_handler handler, void* state)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->receive(handler, state);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+BOOST_LOG_API bool reliable_message_queue::do_try_receive(receive_handler handler, void* state)
+{
+ BOOST_ASSERT(m_impl != NULL);
+ try
+ {
+ return m_impl->try_receive(handler, state);
+ }
+ catch (boost::exception& e)
+ {
+ e << boost::log::ipc::object_name_info(m_impl->name());
+ throw;
+ }
+}
+
+//! Fixed buffer receive handler
+BOOST_LOG_API void reliable_message_queue::fixed_buffer_receive_handler(void* state, const void* data, size_type size)
+{
+ fixed_buffer_state* p = static_cast< fixed_buffer_state* >(state);
+ if (BOOST_UNLIKELY(size > p->size))
+ BOOST_THROW_EXCEPTION(bad_alloc("Buffer too small to receive the message"));
+
+ std::memcpy(p->data, data, size);
+ p->data += size;
+ p->size -= size;
+}
+
+BOOST_LOG_API void reliable_message_queue::remove(object_name const&)
+{
+ // System objects are reference counted on Windows, nothing to do here
+}
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/windows/ipc_sync_wrappers.cpp b/src/boost/libs/log/src/windows/ipc_sync_wrappers.cpp
new file mode 100644
index 000000000..12d743aa6
--- /dev/null
+++ b/src/boost/libs/log/src/windows/ipc_sync_wrappers.cpp
@@ -0,0 +1,544 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/ipc_sync_wrappers.cpp
+ * \author Andrey Semashev
+ * \date 23.01.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/winapi/access_rights.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/winapi/event.hpp>
+#include <boost/winapi/semaphore.hpp>
+#include <boost/winapi/wait.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/winapi/time.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#include <boost/winapi/character_code_conversion.hpp>
+#include <windows.h> // for error codes
+#include <cstddef>
+#include <limits>
+#include <string>
+#include <utility>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/checked_delete.hpp>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/log/detail/snprintf.hpp>
+#include "unique_ptr.hpp"
+#include "windows/ipc_sync_wrappers.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Hex character table, defined in dump.cpp
+extern const char g_hex_char_table[2][16];
+
+} // namespace aux
+
+namespace ipc {
+
+namespace aux {
+
+void interprocess_event::create(const wchar_t* name, bool manual_reset, permissions const& perms)
+{
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ boost::winapi::HANDLE_ h = boost::winapi::CreateEventExW
+ (
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ name,
+ boost::winapi::CREATE_EVENT_MANUAL_RESET_ * manual_reset,
+ boost::winapi::SYNCHRONIZE_ | boost::winapi::EVENT_MODIFY_STATE_
+ );
+#else
+ boost::winapi::HANDLE_ h = boost::winapi::CreateEventW
+ (
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ manual_reset,
+ false,
+ name
+ );
+#endif
+ if (BOOST_UNLIKELY(h == NULL))
+ {
+ boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create an interprocess event object", (err));
+ }
+
+ m_event.init(h);
+}
+
+void interprocess_event::create_or_open(const wchar_t* name, bool manual_reset, permissions const& perms)
+{
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ boost::winapi::HANDLE_ h = boost::winapi::CreateEventExW
+ (
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ name,
+ boost::winapi::CREATE_EVENT_MANUAL_RESET_ * manual_reset,
+ boost::winapi::SYNCHRONIZE_ | boost::winapi::EVENT_MODIFY_STATE_
+ );
+#else
+ boost::winapi::HANDLE_ h = boost::winapi::CreateEventW
+ (
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ manual_reset,
+ false,
+ name
+ );
+#endif
+ if (h == NULL)
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ if (BOOST_LIKELY(err == ERROR_ALREADY_EXISTS))
+ {
+ open(name);
+ return;
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create an interprocess event object", (err));
+ }
+ }
+
+ m_event.init(h);
+}
+
+void interprocess_event::open(const wchar_t* name)
+{
+ boost::winapi::HANDLE_ h = boost::winapi::OpenEventW(boost::winapi::SYNCHRONIZE_ | boost::winapi::EVENT_MODIFY_STATE_, false, name);
+ if (BOOST_UNLIKELY(h == NULL))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to open an interprocess event object", (err));
+ }
+
+ m_event.init(h);
+}
+
+boost::atomic< interprocess_semaphore::is_semaphore_zero_count_t > interprocess_semaphore::is_semaphore_zero_count(&interprocess_semaphore::is_semaphore_zero_count_init);
+interprocess_semaphore::nt_query_semaphore_t interprocess_semaphore::nt_query_semaphore = NULL;
+
+void interprocess_semaphore::create_or_open(const wchar_t* name, permissions const& perms)
+{
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ boost::winapi::HANDLE_ h = boost::winapi::CreateSemaphoreExW
+ (
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ 0, // initial count
+ (std::numeric_limits< boost::winapi::LONG_ >::max)(), // max count
+ name,
+ 0u, // flags
+ boost::winapi::SYNCHRONIZE_ | boost::winapi::SEMAPHORE_MODIFY_STATE_ | boost::winapi::SEMAPHORE_QUERY_STATE_
+ );
+#else
+ boost::winapi::HANDLE_ h = boost::winapi::CreateSemaphoreW
+ (
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ 0, // initial count
+ (std::numeric_limits< boost::winapi::LONG_ >::max)(), // max count
+ name
+ );
+#endif
+ if (h == NULL)
+ {
+ boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ if (BOOST_LIKELY(err == ERROR_ALREADY_EXISTS))
+ {
+ open(name);
+ return;
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create an interprocess semaphore object", (err));
+ }
+ }
+
+ m_sem.init(h);
+}
+
+void interprocess_semaphore::open(const wchar_t* name)
+{
+ boost::winapi::HANDLE_ h = boost::winapi::OpenSemaphoreW(boost::winapi::SYNCHRONIZE_ | boost::winapi::SEMAPHORE_MODIFY_STATE_ | boost::winapi::SEMAPHORE_QUERY_STATE_, false, name);
+ if (BOOST_UNLIKELY(h == NULL))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to open an interprocess semaphore object", (err));
+ }
+
+ m_sem.init(h);
+}
+
+bool interprocess_semaphore::is_semaphore_zero_count_init(boost::winapi::HANDLE_ h)
+{
+ is_semaphore_zero_count_t impl = &interprocess_semaphore::is_semaphore_zero_count_emulated;
+
+ // Check if ntdll.dll provides NtQuerySemaphore, see: http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSemaphore%2FNtQuerySemaphore.html
+ boost::winapi::HMODULE_ ntdll = boost::winapi::GetModuleHandleW(L"ntdll.dll");
+ if (ntdll)
+ {
+ nt_query_semaphore_t ntqs = (nt_query_semaphore_t)boost::winapi::get_proc_address(ntdll, "NtQuerySemaphore");
+ if (ntqs)
+ {
+ nt_query_semaphore = ntqs;
+ impl = &interprocess_semaphore::is_semaphore_zero_count_nt_query_semaphore;
+ }
+ }
+
+ is_semaphore_zero_count.store(impl, boost::memory_order_release);
+
+ return impl(h);
+}
+
+bool interprocess_semaphore::is_semaphore_zero_count_nt_query_semaphore(boost::winapi::HANDLE_ h)
+{
+ semaphore_basic_information info = {};
+ NTSTATUS_ err = nt_query_semaphore
+ (
+ h,
+ 0u, // SemaphoreBasicInformation
+ &info,
+ sizeof(info),
+ NULL
+ );
+ if (BOOST_UNLIKELY(err != 0u))
+ {
+ char buf[sizeof(unsigned int) * 2u + 4u];
+ boost::log::aux::snprintf(buf, sizeof(buf), "0x%08x", static_cast< unsigned int >(err));
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, std::string("Failed to test an interprocess semaphore object for zero count, NT status: ") + buf, (ERROR_INVALID_HANDLE));
+ }
+
+ return info.current_count == 0u;
+}
+
+bool interprocess_semaphore::is_semaphore_zero_count_emulated(boost::winapi::HANDLE_ h)
+{
+ const boost::winapi::DWORD_ retval = boost::winapi::WaitForSingleObject(h, 0u);
+ if (retval == boost::winapi::wait_timeout)
+ {
+ return true;
+ }
+ else if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to test an interprocess semaphore object for zero count", (err));
+ }
+
+ // Restore the decremented counter
+ BOOST_VERIFY(!!boost::winapi::ReleaseSemaphore(h, 1, NULL));
+
+ return false;
+}
+
+#if !defined(BOOST_MSVC) || _MSC_VER >= 1800
+BOOST_CONSTEXPR_OR_CONST uint32_t interprocess_mutex::lock_flag_bit;
+BOOST_CONSTEXPR_OR_CONST uint32_t interprocess_mutex::event_set_flag_bit;
+BOOST_CONSTEXPR_OR_CONST uint32_t interprocess_mutex::lock_flag_value;
+BOOST_CONSTEXPR_OR_CONST uint32_t interprocess_mutex::event_set_flag_value;
+BOOST_CONSTEXPR_OR_CONST uint32_t interprocess_mutex::waiter_count_mask;
+#endif
+
+void interprocess_mutex::lock_slow()
+{
+ uint32_t old_state = m_shared_state->m_lock_state.load(boost::memory_order_relaxed);
+ mark_waiting_and_try_lock(old_state);
+
+ if ((old_state & lock_flag_value) != 0u) try
+ {
+ do
+ {
+ m_event.wait();
+ clear_waiting_and_try_lock(old_state);
+ }
+ while ((old_state & lock_flag_value) != 0u);
+ }
+ catch (...)
+ {
+ m_shared_state->m_lock_state.fetch_sub(1u, boost::memory_order_acq_rel);
+ throw;
+ }
+}
+
+bool interprocess_mutex::lock_slow(boost::winapi::HANDLE_ abort_handle)
+{
+ uint32_t old_state = m_shared_state->m_lock_state.load(boost::memory_order_relaxed);
+ mark_waiting_and_try_lock(old_state);
+
+ if ((old_state & lock_flag_value) != 0u) try
+ {
+ do
+ {
+ if (!m_event.wait(abort_handle))
+ {
+ // Wait was interrupted
+ m_shared_state->m_lock_state.fetch_sub(1u, boost::memory_order_acq_rel);
+ return false;
+ }
+
+ clear_waiting_and_try_lock(old_state);
+ }
+ while ((old_state & lock_flag_value) != 0u);
+ }
+ catch (...)
+ {
+ m_shared_state->m_lock_state.fetch_sub(1u, boost::memory_order_acq_rel);
+ throw;
+ }
+
+ return true;
+}
+
+inline void interprocess_mutex::mark_waiting_and_try_lock(uint32_t& old_state)
+{
+ uint32_t new_state;
+ do
+ {
+ uint32_t was_locked = (old_state & lock_flag_value);
+ if (was_locked)
+ {
+ // Avoid integer overflows
+ if (BOOST_UNLIKELY((old_state & waiter_count_mask) == waiter_count_mask))
+ BOOST_LOG_THROW_DESCR(limitation_error, "Too many waiters on an interprocess mutex");
+
+ new_state = old_state + 1u;
+ }
+ else
+ {
+ new_state = old_state | lock_flag_value;
+ }
+ }
+ while (!m_shared_state->m_lock_state.compare_exchange_weak(old_state, new_state, boost::memory_order_acq_rel, boost::memory_order_relaxed));
+}
+
+inline void interprocess_mutex::clear_waiting_and_try_lock(uint32_t& old_state)
+{
+ old_state &= ~lock_flag_value;
+ old_state |= event_set_flag_value;
+ uint32_t new_state;
+ do
+ {
+ new_state = ((old_state & lock_flag_value) ? old_state : ((old_state - 1u) | lock_flag_value)) & ~event_set_flag_value;
+ }
+ while (!m_shared_state->m_lock_state.compare_exchange_weak(old_state, new_state, boost::memory_order_acq_rel, boost::memory_order_relaxed));
+}
+
+
+bool interprocess_condition_variable::wait(interprocess_mutex::optional_unlock& lock, boost::winapi::HANDLE_ abort_handle)
+{
+ int32_t waiters = m_shared_state->m_waiters;
+ if (waiters < 0)
+ {
+ // We need to select a new semaphore to block on
+ m_current_semaphore = get_unused_semaphore();
+ ++m_shared_state->m_generation;
+ m_shared_state->m_semaphore_id = m_current_semaphore->m_id;
+ waiters = 0;
+ }
+ else
+ {
+ // Avoid integer overflow
+ if (BOOST_UNLIKELY(waiters >= ((std::numeric_limits< int32_t >::max)() - 1)))
+ BOOST_LOG_THROW_DESCR(limitation_error, "Too many waiters on an interprocess condition variable");
+
+ // Make sure we use the right semaphore to block on
+ const uint32_t id = m_shared_state->m_semaphore_id;
+ if (m_current_semaphore->m_id != id)
+ m_current_semaphore = get_semaphore(id);
+ }
+
+ m_shared_state->m_waiters = waiters + 1;
+ const uint32_t generation = m_shared_state->m_generation;
+
+ boost::winapi::HANDLE_ handles[2u] = { m_current_semaphore->m_semaphore.get_handle(), abort_handle };
+
+ interprocess_mutex* const mutex = lock.disengage();
+ mutex->unlock();
+
+ boost::winapi::DWORD_ retval = boost::winapi::WaitForMultipleObjects(2u, handles, false, boost::winapi::INFINITE_);
+
+ if (BOOST_UNLIKELY(retval == boost::winapi::WAIT_FAILED_))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+
+ // Although highly unrealistic, it is possible that it took so long for the current thread to enter WaitForMultipleObjects that
+ // another thread has managed to destroy the semaphore. This can happen if the semaphore remains in a non-zero state
+ // for too long, which means that another process died while being blocked on the semaphore, and the semaphore was signalled,
+ // and the non-zero state timeout has passed. In this case the most logical behavior for the wait function is to return as
+ // if because of a wakeup.
+ if (err == ERROR_INVALID_HANDLE)
+ retval = boost::winapi::WAIT_OBJECT_0_;
+ else
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess semaphore object", (err));
+ }
+
+ // Have to unconditionally lock the mutex here
+ mutex->lock();
+ lock.engage(*mutex);
+
+ if (generation == m_shared_state->m_generation && m_shared_state->m_waiters > 0)
+ --m_shared_state->m_waiters;
+
+ return retval == boost::winapi::WAIT_OBJECT_0_;
+}
+
+//! Finds or opens a semaphore with the specified id
+interprocess_condition_variable::semaphore_info* interprocess_condition_variable::get_semaphore(uint32_t id)
+{
+ semaphore_info_set::insert_commit_data insert_state;
+ std::pair< semaphore_info_set::iterator, bool > res = m_semaphore_info_set.insert_check(id, semaphore_info::order_by_id(), insert_state);
+ if (res.second)
+ {
+ // We need to open the semaphore. It is possible that the semaphore does not exist because all processes that had it opened terminated.
+ // Because of this we also attempt to create it.
+ boost::log::aux::unique_ptr< semaphore_info > p(new semaphore_info(id));
+ generate_semaphore_name(id);
+ p->m_semaphore.create_or_open(m_semaphore_name.c_str(), m_perms);
+
+ res.first = m_semaphore_info_set.insert_commit(*p, insert_state);
+ m_semaphore_info_list.push_back(*p);
+
+ return p.release();
+ }
+ else
+ {
+ // Move the semaphore to the end of the list so that the next time we are less likely to use it
+ semaphore_info& info = *res.first;
+ m_semaphore_info_list.erase(m_semaphore_info_list.iterator_to(info));
+ m_semaphore_info_list.push_back(info);
+
+ return &info;
+ }
+}
+
+//! Finds or creates a semaphore with zero counter
+interprocess_condition_variable::semaphore_info* interprocess_condition_variable::get_unused_semaphore()
+{
+ // Be optimistic, check the current semaphore first
+ if (m_current_semaphore && m_current_semaphore->m_semaphore.is_zero_count())
+ {
+ mark_unused(*m_current_semaphore);
+ return m_current_semaphore;
+ }
+
+ const tick_count_clock::time_point now = tick_count_clock::now();
+
+ semaphore_info_list::iterator it = m_semaphore_info_list.begin(), end = m_semaphore_info_list.end();
+ while (it != end)
+ {
+ if (is_overflow_less(m_next_semaphore_id, it->m_id) || m_next_semaphore_id == it->m_id)
+ m_next_semaphore_id = it->m_id + 1u;
+
+ if (it->m_semaphore.is_zero_count())
+ {
+ semaphore_info& info = *it;
+ mark_unused(info);
+ return &info;
+ }
+ else if (it->check_non_zero_timeout(now))
+ {
+ // The semaphore is non-zero for too long. A blocked process must have crashed. Close it.
+ m_semaphore_info_set.erase(m_semaphore_info_set.iterator_to(*it));
+ m_semaphore_info_list.erase_and_dispose(it++, boost::checked_deleter< semaphore_info >());
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ // No semaphore found, create a new one
+ for (uint32_t semaphore_id = m_next_semaphore_id, semaphore_id_end = semaphore_id - 1u; semaphore_id != semaphore_id_end; ++semaphore_id)
+ {
+ interprocess_semaphore sem;
+ try
+ {
+ generate_semaphore_name(semaphore_id);
+ sem.create_or_open(m_semaphore_name.c_str(), m_perms);
+ if (!sem.is_zero_count())
+ continue;
+ }
+ catch (...)
+ {
+ // Ignore errors, try the next one
+ continue;
+ }
+
+ semaphore_info* p = NULL;
+ semaphore_info_set::insert_commit_data insert_state;
+ std::pair< semaphore_info_set::iterator, bool > res = m_semaphore_info_set.insert_check(semaphore_id, semaphore_info::order_by_id(), insert_state);
+ if (res.second)
+ {
+ p = new semaphore_info(semaphore_id);
+ p->m_semaphore.swap(sem);
+
+ res.first = m_semaphore_info_set.insert_commit(*p, insert_state);
+ m_semaphore_info_list.push_back(*p);
+ }
+ else
+ {
+ // Some of our currently open semaphores must have been released by another thread
+ p = &*res.first;
+ mark_unused(*p);
+ }
+
+ m_next_semaphore_id = semaphore_id + 1u;
+
+ return p;
+ }
+
+ BOOST_LOG_THROW_DESCR(limitation_error, "Too many semaphores are actively used for an interprocess condition variable");
+ BOOST_LOG_UNREACHABLE_RETURN(NULL);
+}
+
+//! Marks the semaphore info as unused and moves to the end of list
+inline void interprocess_condition_variable::mark_unused(semaphore_info& info) BOOST_NOEXCEPT
+{
+ // Restart the timeout for non-zero state next time we search for an unused semaphore
+ info.m_checked_for_zero = false;
+ // Move to the end of the list so that we consider this semaphore last
+ m_semaphore_info_list.erase(m_semaphore_info_list.iterator_to(info));
+ m_semaphore_info_list.push_back(info);
+}
+
+//! Generates semaphore name according to id
+inline void interprocess_condition_variable::generate_semaphore_name(uint32_t id) BOOST_NOEXCEPT
+{
+ // Note: avoid anything that involves locale to make semaphore names as stable as possible
+ BOOST_ASSERT(m_semaphore_name.size() >= 8u);
+
+ wchar_t* p = &m_semaphore_name[m_semaphore_name.size() - 8u];
+ *p++ = boost::log::aux::g_hex_char_table[0][id >> 28];
+ *p++ = boost::log::aux::g_hex_char_table[0][(id >> 24) & 0x0000000Fu];
+
+ *p++ = boost::log::aux::g_hex_char_table[0][(id >> 20) & 0x0000000Fu];
+ *p++ = boost::log::aux::g_hex_char_table[0][(id >> 16) & 0x0000000Fu];
+
+ *p++ = boost::log::aux::g_hex_char_table[0][(id >> 12) & 0x0000000Fu];
+ *p++ = boost::log::aux::g_hex_char_table[0][(id >> 8) & 0x0000000Fu];
+
+ *p++ = boost::log::aux::g_hex_char_table[0][(id >> 4) & 0x0000000Fu];
+ *p = boost::log::aux::g_hex_char_table[0][id & 0x0000000Fu];
+}
+
+} // namespace aux
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/windows/ipc_sync_wrappers.hpp b/src/boost/libs/log/src/windows/ipc_sync_wrappers.hpp
new file mode 100644
index 000000000..8ecd9635c
--- /dev/null
+++ b/src/boost/libs/log/src/windows/ipc_sync_wrappers.hpp
@@ -0,0 +1,544 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/ipc_sync_wrappers.hpp
+ * \author Andrey Semashev
+ * \date 23.01.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WINDOWS_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
+#define BOOST_LOG_WINDOWS_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/winapi/access_rights.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/winapi/event.hpp>
+#include <boost/winapi/semaphore.hpp>
+#include <boost/winapi/wait.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/winapi/time.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#include <cstddef>
+#include <limits>
+#include <string>
+#include <utility>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/checked_delete.hpp>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/set.hpp>
+#include <boost/intrusive/set_hook.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/list_hook.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/permissions.hpp>
+#include "windows/auto_handle.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+namespace aux {
+
+//! Interprocess event object
+class interprocess_event
+{
+private:
+ auto_handle m_event;
+
+public:
+ void create(const wchar_t* name, bool manual_reset, permissions const& perms = permissions());
+ void create_or_open(const wchar_t* name, bool manual_reset, permissions const& perms = permissions());
+ void open(const wchar_t* name);
+
+ boost::winapi::HANDLE_ get_handle() const BOOST_NOEXCEPT { return m_event.get(); }
+
+ void set()
+ {
+ if (BOOST_UNLIKELY(!boost::winapi::SetEvent(m_event.get())))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to set an interprocess event object", (err));
+ }
+ }
+
+ void set_noexcept() BOOST_NOEXCEPT
+ {
+ BOOST_VERIFY(!!boost::winapi::SetEvent(m_event.get()));
+ }
+
+ void reset()
+ {
+ if (BOOST_UNLIKELY(!boost::winapi::ResetEvent(m_event.get())))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to reset an interprocess event object", (err));
+ }
+ }
+
+ void wait()
+ {
+ const boost::winapi::DWORD_ retval = boost::winapi::WaitForSingleObject(m_event.get(), boost::winapi::infinite);
+ if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess event object", (err));
+ }
+ }
+
+ bool wait(boost::winapi::HANDLE_ abort_handle)
+ {
+ boost::winapi::HANDLE_ handles[2u] = { m_event.get(), abort_handle };
+ const boost::winapi::DWORD_ retval = boost::winapi::WaitForMultipleObjects(2u, handles, false, boost::winapi::infinite);
+ if (retval == (boost::winapi::wait_object_0 + 1u))
+ {
+ // Wait was interrupted
+ return false;
+ }
+ else if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess event object", (err));
+ }
+
+ return true;
+ }
+
+ void swap(interprocess_event& that) BOOST_NOEXCEPT
+ {
+ m_event.swap(that.m_event);
+ }
+};
+
+//! Interprocess semaphore object
+class interprocess_semaphore
+{
+private:
+ typedef boost::winapi::DWORD_ NTSTATUS_;
+ struct semaphore_basic_information
+ {
+ boost::winapi::ULONG_ current_count; // current semaphore count
+ boost::winapi::ULONG_ maximum_count; // max semaphore count
+ };
+ typedef NTSTATUS_ (__stdcall *nt_query_semaphore_t)(boost::winapi::HANDLE_ h, unsigned int info_class, semaphore_basic_information* pinfo, boost::winapi::ULONG_ info_size, boost::winapi::ULONG_* ret_len);
+ typedef bool (*is_semaphore_zero_count_t)(boost::winapi::HANDLE_ h);
+
+private:
+ auto_handle m_sem;
+
+ static boost::atomic< is_semaphore_zero_count_t > is_semaphore_zero_count;
+ static nt_query_semaphore_t nt_query_semaphore;
+
+public:
+ void create_or_open(const wchar_t* name, permissions const& perms = permissions());
+ void open(const wchar_t* name);
+
+ boost::winapi::HANDLE_ get_handle() const BOOST_NOEXCEPT { return m_sem.get(); }
+
+ void post(uint32_t count)
+ {
+ BOOST_ASSERT(count <= static_cast< uint32_t >((std::numeric_limits< boost::winapi::LONG_ >::max)()));
+
+ if (BOOST_UNLIKELY(!boost::winapi::ReleaseSemaphore(m_sem.get(), static_cast< boost::winapi::LONG_ >(count), NULL)))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to post on an interprocess semaphore object", (err));
+ }
+ }
+
+ bool is_zero_count() const
+ {
+ return is_semaphore_zero_count.load(boost::memory_order_acquire)(m_sem.get());
+ }
+
+ void wait()
+ {
+ const boost::winapi::DWORD_ retval = boost::winapi::WaitForSingleObject(m_sem.get(), boost::winapi::infinite);
+ if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess semaphore object", (err));
+ }
+ }
+
+ bool wait(boost::winapi::HANDLE_ abort_handle)
+ {
+ boost::winapi::HANDLE_ handles[2u] = { m_sem.get(), abort_handle };
+ const boost::winapi::DWORD_ retval = boost::winapi::WaitForMultipleObjects(2u, handles, false, boost::winapi::infinite);
+ if (retval == (boost::winapi::wait_object_0 + 1u))
+ {
+ // Wait was interrupted
+ return false;
+ }
+ else if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess semaphore object", (err));
+ }
+
+ return true;
+ }
+
+ void swap(interprocess_semaphore& that) BOOST_NOEXCEPT
+ {
+ m_sem.swap(that.m_sem);
+ }
+
+private:
+ static bool is_semaphore_zero_count_init(boost::winapi::HANDLE_ h);
+ static bool is_semaphore_zero_count_nt_query_semaphore(boost::winapi::HANDLE_ h);
+ static bool is_semaphore_zero_count_emulated(boost::winapi::HANDLE_ h);
+};
+
+//! Interprocess mutex. Implementation adopted from Boost.Sync.
+class interprocess_mutex
+{
+public:
+ //! Shared state that should be visible to all processes using the mutex
+ struct shared_state
+ {
+ boost::atomic< uint32_t > m_lock_state;
+
+ shared_state() BOOST_NOEXCEPT : m_lock_state(0u)
+ {
+ }
+ };
+
+ struct auto_unlock
+ {
+ explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
+ ~auto_unlock() { m_mutex.unlock(); }
+
+ BOOST_DELETED_FUNCTION(auto_unlock(auto_unlock const&))
+ BOOST_DELETED_FUNCTION(auto_unlock& operator=(auto_unlock const&))
+
+ private:
+ interprocess_mutex& m_mutex;
+ };
+
+ struct optional_unlock
+ {
+ optional_unlock() BOOST_NOEXCEPT : m_mutex(NULL) {}
+ explicit optional_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(&mutex) {}
+ ~optional_unlock() { if (m_mutex) m_mutex->unlock(); }
+
+ interprocess_mutex* disengage() BOOST_NOEXCEPT
+ {
+ interprocess_mutex* p = m_mutex;
+ m_mutex = NULL;
+ return p;
+ }
+
+ void engage(interprocess_mutex& mutex) BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT(!m_mutex);
+ m_mutex = &mutex;
+ }
+
+ BOOST_DELETED_FUNCTION(optional_unlock(optional_unlock const&))
+ BOOST_DELETED_FUNCTION(optional_unlock& operator=(optional_unlock const&))
+
+ private:
+ interprocess_mutex* m_mutex;
+ };
+
+private:
+ interprocess_event m_event;
+ shared_state* m_shared_state;
+
+#if !defined(BOOST_MSVC) || _MSC_VER >= 1800
+ static BOOST_CONSTEXPR_OR_CONST uint32_t lock_flag_bit = 31u;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t event_set_flag_bit = 30u;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t lock_flag_value = 1u << lock_flag_bit;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t event_set_flag_value = 1u << event_set_flag_bit;
+ static BOOST_CONSTEXPR_OR_CONST uint32_t waiter_count_mask = event_set_flag_value - 1u;
+#else
+ // MSVC 8-11, inclusively, fail to link if these constants are declared as static constants instead of an enum
+ enum
+ {
+ lock_flag_bit = 31u,
+ event_set_flag_bit = 30u,
+ lock_flag_value = 1u << lock_flag_bit,
+ event_set_flag_value = 1u << event_set_flag_bit,
+ waiter_count_mask = event_set_flag_value - 1u
+ };
+#endif
+
+public:
+ interprocess_mutex() BOOST_NOEXCEPT : m_shared_state(NULL)
+ {
+ }
+
+ void create(const wchar_t* name, shared_state* shared, permissions const& perms = permissions())
+ {
+ m_event.create(name, false, perms);
+ m_shared_state = shared;
+ }
+
+ void open(const wchar_t* name, shared_state* shared)
+ {
+ m_event.open(name);
+ m_shared_state = shared;
+ }
+
+ bool try_lock()
+ {
+ return !m_shared_state->m_lock_state.bit_test_and_set(lock_flag_bit, boost::memory_order_acquire);
+ }
+
+ void lock()
+ {
+ if (BOOST_UNLIKELY(!try_lock()))
+ lock_slow();
+ }
+
+ bool lock(boost::winapi::HANDLE_ abort_handle)
+ {
+ if (BOOST_LIKELY(try_lock()))
+ return true;
+ return lock_slow(abort_handle);
+ }
+
+ void unlock() BOOST_NOEXCEPT
+ {
+ const uint32_t old_count = m_shared_state->m_lock_state.fetch_add(lock_flag_value, boost::memory_order_release);
+ if ((old_count & event_set_flag_value) == 0u && (old_count > lock_flag_value))
+ {
+ if (!m_shared_state->m_lock_state.bit_test_and_set(event_set_flag_bit, boost::memory_order_relaxed))
+ {
+ m_event.set_noexcept();
+ }
+ }
+ }
+
+ BOOST_DELETED_FUNCTION(interprocess_mutex(interprocess_mutex const&))
+ BOOST_DELETED_FUNCTION(interprocess_mutex& operator=(interprocess_mutex const&))
+
+private:
+ void lock_slow();
+ bool lock_slow(boost::winapi::HANDLE_ abort_handle);
+ void mark_waiting_and_try_lock(uint32_t& old_state);
+ void clear_waiting_and_try_lock(uint32_t& old_state);
+};
+
+//! A simple clock that corresponds to GetTickCount/GetTickCount64 timeline
+struct tick_count_clock
+{
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ typedef boost::winapi::ULONGLONG_ time_point;
+#else
+ typedef boost::winapi::DWORD_ time_point;
+#endif
+
+ static time_point now() BOOST_NOEXCEPT
+ {
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ return boost::winapi::GetTickCount64();
+#else
+ return boost::winapi::GetTickCount();
+#endif
+ }
+};
+
+//! Interprocess condition variable
+class interprocess_condition_variable
+{
+private:
+ typedef boost::intrusive::list_base_hook<
+ boost::intrusive::tag< struct for_sem_order_by_usage >,
+ boost::intrusive::link_mode< boost::intrusive::safe_link >
+ > semaphore_info_list_hook_t;
+
+ typedef boost::intrusive::set_base_hook<
+ boost::intrusive::tag< struct for_sem_lookup_by_id >,
+ boost::intrusive::link_mode< boost::intrusive::safe_link >,
+ boost::intrusive::optimize_size< true >
+ > semaphore_info_set_hook_t;
+
+ //! Information about a semaphore object
+ struct semaphore_info :
+ public semaphore_info_list_hook_t,
+ public semaphore_info_set_hook_t
+ {
+ struct order_by_id
+ {
+ typedef bool result_type;
+
+ result_type operator() (semaphore_info const& left, semaphore_info const& right) const BOOST_NOEXCEPT
+ {
+ return left.m_id < right.m_id;
+ }
+ result_type operator() (semaphore_info const& left, uint32_t right) const BOOST_NOEXCEPT
+ {
+ return left.m_id < right;
+ }
+ result_type operator() (uint32_t left, semaphore_info const& right) const BOOST_NOEXCEPT
+ {
+ return left < right.m_id;
+ }
+ };
+
+ //! The semaphore
+ interprocess_semaphore m_semaphore;
+ //! Timestamp of the moment when the semaphore was checked for zero count and it was not zero. In milliseconds since epoch.
+ tick_count_clock::time_point m_last_check_for_zero;
+ //! The flag indicates that the semaphore has been checked for zero count and it was not zero
+ bool m_checked_for_zero;
+ //! The semaphore id
+ const uint32_t m_id;
+
+ explicit semaphore_info(uint32_t id) BOOST_NOEXCEPT : m_last_check_for_zero(0u), m_id(id)
+ {
+ }
+
+ //! Checks if the semaphore is in 'non-zero' state for too long
+ bool check_non_zero_timeout(tick_count_clock::time_point now) BOOST_NOEXCEPT
+ {
+ if (!m_checked_for_zero)
+ {
+ m_last_check_for_zero = now;
+ m_checked_for_zero = true;
+ return false;
+ }
+
+ return (now - m_last_check_for_zero) >= 2000u;
+ }
+
+ BOOST_DELETED_FUNCTION(semaphore_info(semaphore_info const&))
+ BOOST_DELETED_FUNCTION(semaphore_info& operator=(semaphore_info const&))
+ };
+
+ typedef boost::intrusive::list<
+ semaphore_info,
+ boost::intrusive::base_hook< semaphore_info_list_hook_t >,
+ boost::intrusive::constant_time_size< false >
+ > semaphore_info_list;
+
+ typedef boost::intrusive::set<
+ semaphore_info,
+ boost::intrusive::base_hook< semaphore_info_set_hook_t >,
+ boost::intrusive::compare< semaphore_info::order_by_id >,
+ boost::intrusive::constant_time_size< false >
+ > semaphore_info_set;
+
+public:
+ struct shared_state
+ {
+ //! Number of waiters blocked on the semaphore if >0, 0 if no threads are blocked, <0 when the blocked threads were signalled
+ int32_t m_waiters;
+ //! The semaphore generation
+ uint32_t m_generation;
+ //! Id of the semaphore which is used to block threads on
+ uint32_t m_semaphore_id;
+
+ shared_state() BOOST_NOEXCEPT :
+ m_waiters(0),
+ m_generation(0u),
+ m_semaphore_id(0u)
+ {
+ }
+ };
+
+private:
+ //! The list of semaphores used for blocking. The list is in the order at which the semaphores are considered to be picked for being used.
+ semaphore_info_list m_semaphore_info_list;
+ //! The list of semaphores used for blocking. Used for searching for a particular semaphore by id.
+ semaphore_info_set m_semaphore_info_set;
+ //! The semaphore that is currently being used for blocking
+ semaphore_info* m_current_semaphore;
+ //! A string storage for formatting a semaphore name
+ std::wstring m_semaphore_name;
+ //! Permissions used to create new semaphores
+ permissions m_perms;
+ //! Process-shared state
+ shared_state* m_shared_state;
+ //! The next id for creating a new semaphore
+ uint32_t m_next_semaphore_id;
+
+public:
+ interprocess_condition_variable() BOOST_NOEXCEPT :
+ m_current_semaphore(NULL),
+ m_shared_state(NULL),
+ m_next_semaphore_id(0u)
+ {
+ }
+
+ ~interprocess_condition_variable()
+ {
+ m_semaphore_info_set.clear();
+ m_semaphore_info_list.clear_and_dispose(boost::checked_deleter< semaphore_info >());
+ }
+
+ void init(const wchar_t* name, shared_state* shared, permissions const& perms = permissions())
+ {
+ m_perms = perms;
+ m_shared_state = shared;
+
+ m_semaphore_name = name;
+ // Reserve space for generate_semaphore_name()
+ m_semaphore_name.append(L".sem00000000");
+
+ m_current_semaphore = get_semaphore(m_shared_state->m_semaphore_id);
+ }
+
+ void notify_all()
+ {
+ const int32_t waiters = m_shared_state->m_waiters;
+ if (waiters > 0)
+ {
+ const uint32_t id = m_shared_state->m_semaphore_id;
+ if (m_current_semaphore->m_id != id)
+ m_current_semaphore = get_semaphore(id);
+
+ m_current_semaphore->m_semaphore.post(waiters);
+ m_shared_state->m_waiters = -waiters;
+ }
+ }
+
+ bool wait(interprocess_mutex::optional_unlock& lock, boost::winapi::HANDLE_ abort_handle);
+
+ BOOST_DELETED_FUNCTION(interprocess_condition_variable(interprocess_condition_variable const&))
+ BOOST_DELETED_FUNCTION(interprocess_condition_variable& operator=(interprocess_condition_variable const&))
+
+private:
+ //! Finds or opens a semaphore with the specified id
+ semaphore_info* get_semaphore(uint32_t id);
+ //! Finds or creates a semaphore with zero counter
+ semaphore_info* get_unused_semaphore();
+
+ //! Marks the semaphore info as unused and moves to the end of list
+ void mark_unused(semaphore_info& info) BOOST_NOEXCEPT;
+
+ //! Generates semaphore name according to id
+ void generate_semaphore_name(uint32_t id) BOOST_NOEXCEPT;
+
+ //! Returns \c true if \a left is less than \a right considering possible integer overflow
+ static bool is_overflow_less(uint32_t left, uint32_t right) BOOST_NOEXCEPT
+ {
+ return ((left - right) & 0x80000000u) != 0u;
+ }
+};
+
+} // namespace aux
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WINDOWS_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/windows/light_rw_mutex.cpp b/src/boost/libs/log/src/windows/light_rw_mutex.cpp
new file mode 100644
index 000000000..885dc1752
--- /dev/null
+++ b/src/boost/libs/log/src/windows/light_rw_mutex.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file light_rw_mutex.cpp
+ * \author Andrey Semashev
+ * \date 19.06.2010
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/log/detail/light_rw_mutex.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+#if !defined(BOOST_LOG_LWRWMUTEX_USE_PTHREAD) && !defined(BOOST_LOG_LWRWMUTEX_USE_SRWLOCK)
+
+#include <cstddef>
+#include <new>
+#include <boost/assert.hpp>
+#include <boost/align/aligned_alloc.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/log/utility/once_block.hpp>
+
+#include <boost/winapi/basic_types.hpp>
+#include <boost/winapi/dll.hpp>
+
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+struct BOOST_LOG_MAY_ALIAS mutex_impl { void* p; }; // has the same layout as SRWLOCK and light_rw_mutex::m_Mutex
+
+typedef void (BOOST_WINAPI_WINAPI_CC *init_fun_t)(mutex_impl*);
+typedef void (BOOST_WINAPI_WINAPI_CC *destroy_fun_t)(mutex_impl*);
+typedef void (BOOST_WINAPI_WINAPI_CC *lock_exclusive_fun_t)(mutex_impl*);
+typedef void (BOOST_WINAPI_WINAPI_CC *lock_shared_fun_t)(mutex_impl*);
+typedef void (BOOST_WINAPI_WINAPI_CC *unlock_exclusive_fun_t)(mutex_impl*);
+typedef void (BOOST_WINAPI_WINAPI_CC *unlock_shared_fun_t)(mutex_impl*);
+
+//! A complement stub function for InitializeSRWLock
+void BOOST_WINAPI_WINAPI_CC DeinitializeSRWLock(mutex_impl*)
+{
+}
+
+// The Boost.Thread-based implementation
+void BOOST_WINAPI_WINAPI_CC InitializeSharedMutex(mutex_impl* mtx)
+{
+ // To avoid cache line aliasing we do aligned memory allocation here
+ enum
+ {
+ // Allocation size is the minimum number of cache lines to accommodate shared_mutex
+ size =
+ (
+ (sizeof(shared_mutex) + BOOST_LOG_CPU_CACHE_LINE_SIZE - 1u) / BOOST_LOG_CPU_CACHE_LINE_SIZE
+ )
+ * BOOST_LOG_CPU_CACHE_LINE_SIZE
+ };
+ mtx->p = alignment::aligned_alloc(BOOST_LOG_CPU_CACHE_LINE_SIZE, size);
+ BOOST_ASSERT(mtx->p != NULL);
+ new (mtx->p) shared_mutex();
+}
+
+void BOOST_WINAPI_WINAPI_CC DeinitializeSharedMutex(mutex_impl* mtx)
+{
+ static_cast< shared_mutex* >(mtx->p)->~shared_mutex();
+ alignment::aligned_free(mtx->p);
+ mtx->p = NULL;
+}
+
+void BOOST_WINAPI_WINAPI_CC ExclusiveLockSharedMutex(mutex_impl* mtx)
+{
+ static_cast< shared_mutex* >(mtx->p)->lock();
+}
+
+void BOOST_WINAPI_WINAPI_CC SharedLockSharedMutex(mutex_impl* mtx)
+{
+ static_cast< shared_mutex* >(mtx->p)->lock_shared();
+}
+
+void BOOST_WINAPI_WINAPI_CC ExclusiveUnlockSharedMutex(mutex_impl* mtx)
+{
+ static_cast< shared_mutex* >(mtx->p)->unlock();
+}
+
+void BOOST_WINAPI_WINAPI_CC SharedUnlockSharedMutex(mutex_impl* mtx)
+{
+ static_cast< shared_mutex* >(mtx->p)->unlock_shared();
+}
+
+// Pointers to the actual implementation functions
+init_fun_t g_pInitializeLWRWMutex = NULL;
+destroy_fun_t g_pDestroyLWRWMutex = NULL;
+lock_exclusive_fun_t g_pLockExclusiveLWRWMutex = NULL;
+lock_shared_fun_t g_pLockSharedLWRWMutex = NULL;
+unlock_exclusive_fun_t g_pUnlockExclusiveLWRWMutex = NULL;
+unlock_shared_fun_t g_pUnlockSharedLWRWMutex = NULL;
+
+//! The function dynamically initializes the implementation pointers
+void init_light_rw_mutex_impl()
+{
+ boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ {
+ g_pInitializeLWRWMutex =
+ (init_fun_t)boost::winapi::get_proc_address(hKernel32, "InitializeSRWLock");
+ if (g_pInitializeLWRWMutex)
+ {
+ g_pLockExclusiveLWRWMutex =
+ (lock_exclusive_fun_t)boost::winapi::get_proc_address(hKernel32, "AcquireSRWLockExclusive");
+ if (g_pLockExclusiveLWRWMutex)
+ {
+ g_pUnlockExclusiveLWRWMutex =
+ (unlock_exclusive_fun_t)boost::winapi::get_proc_address(hKernel32, "ReleaseSRWLockExclusive");
+ if (g_pUnlockExclusiveLWRWMutex)
+ {
+ g_pLockSharedLWRWMutex =
+ (lock_shared_fun_t)boost::winapi::get_proc_address(hKernel32, "AcquireSRWLockShared");
+ if (g_pLockSharedLWRWMutex)
+ {
+ g_pUnlockSharedLWRWMutex =
+ (unlock_shared_fun_t)boost::winapi::get_proc_address(hKernel32, "ReleaseSRWLockShared");
+ if (g_pUnlockSharedLWRWMutex)
+ {
+ g_pDestroyLWRWMutex = &DeinitializeSRWLock;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Current OS doesn't have support for SRWLOCK, use Boost.Thread instead
+ g_pInitializeLWRWMutex = &InitializeSharedMutex;
+ g_pDestroyLWRWMutex = &DeinitializeSharedMutex;
+ g_pLockExclusiveLWRWMutex = &ExclusiveLockSharedMutex;
+ g_pUnlockExclusiveLWRWMutex = &ExclusiveUnlockSharedMutex;
+ g_pLockSharedLWRWMutex = &SharedLockSharedMutex;
+ g_pUnlockSharedLWRWMutex = &SharedUnlockSharedMutex;
+}
+
+} // namespace
+
+BOOST_LOG_API light_rw_mutex::light_rw_mutex()
+{
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ init_light_rw_mutex_impl();
+ }
+ g_pInitializeLWRWMutex((mutex_impl*)&m_Mutex);
+}
+
+BOOST_LOG_API light_rw_mutex::~light_rw_mutex()
+{
+ g_pDestroyLWRWMutex((mutex_impl*)&m_Mutex);
+}
+
+BOOST_LOG_API void light_rw_mutex::lock_shared()
+{
+ g_pLockSharedLWRWMutex((mutex_impl*)&m_Mutex);
+}
+
+BOOST_LOG_API void light_rw_mutex::unlock_shared()
+{
+ g_pUnlockSharedLWRWMutex((mutex_impl*)&m_Mutex);
+}
+
+BOOST_LOG_API void light_rw_mutex::lock()
+{
+ g_pLockExclusiveLWRWMutex((mutex_impl*)&m_Mutex);
+}
+
+BOOST_LOG_API void light_rw_mutex::unlock()
+{
+ g_pUnlockExclusiveLWRWMutex((mutex_impl*)&m_Mutex);
+}
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // !defined(BOOST_LOG_LWRWMUTEX_USE_PTHREAD) && !defined(BOOST_LOG_LWRWMUTEX_USE_SRWLOCK)
+
+#endif // !defined(BOOST_LOG_NO_THREADS)
diff --git a/src/boost/libs/log/src/windows/mapped_shared_memory.cpp b/src/boost/libs/log/src/windows/mapped_shared_memory.cpp
new file mode 100644
index 000000000..4586c1d81
--- /dev/null
+++ b/src/boost/libs/log/src/windows/mapped_shared_memory.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/mapped_shared_memory.cpp
+ * \author Andrey Semashev
+ * \date 13.02.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <boost/winapi/basic_types.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/winapi/file_mapping.hpp>
+#include <boost/winapi/page_protection_flags.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#include <windows.h> // for error codes
+#include <cstddef>
+#include <limits>
+#include <string>
+#include <sstream>
+#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/permissions.hpp>
+#include "windows/mapped_shared_memory.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+namespace aux {
+
+boost::atomic< mapped_shared_memory::nt_query_section_t > mapped_shared_memory::nt_query_section(static_cast< mapped_shared_memory::nt_query_section_t >(NULL));
+
+mapped_shared_memory::~mapped_shared_memory()
+{
+ if (m_mapped_address)
+ unmap();
+
+ if (m_handle)
+ {
+ BOOST_VERIFY(boost::winapi::CloseHandle(m_handle) != 0);
+ m_handle = NULL;
+ }
+}
+
+//! Creates a new file mapping for the shared memory segment or opens the existing one
+void mapped_shared_memory::create(const wchar_t* name, std::size_t size, permissions const& perms)
+{
+ BOOST_ASSERT(m_handle == NULL);
+
+ const uint64_t size64 = static_cast< uint64_t >(size);
+
+ // Unlike other create functions, this function opens the existing mapping, if one already exists
+ boost::winapi::HANDLE_ h = boost::winapi::CreateFileMappingW
+ (
+ boost::winapi::INVALID_HANDLE_VALUE_,
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ boost::winapi::PAGE_READWRITE_ | boost::winapi::SEC_COMMIT_,
+ static_cast< boost::winapi::DWORD_ >(size64 >> 32u),
+ static_cast< boost::winapi::DWORD_ >(size64),
+ name
+ );
+
+ boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ if (BOOST_UNLIKELY(h == NULL || err != ERROR_SUCCESS))
+ {
+ if (h != NULL)
+ boost::winapi::CloseHandle(h);
+ std::ostringstream strm;
+ strm << "Failed to create a shared memory segment of " << size << " bytes";
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, strm.str(), (err));
+ }
+
+ m_handle = h;
+ m_size = size;
+}
+
+//! Creates a new file mapping for the shared memory segment or opens the existing one. Returns \c true if the region was created and \c false if an existing one was opened.
+bool mapped_shared_memory::create_or_open(const wchar_t* name, std::size_t size, permissions const& perms)
+{
+ BOOST_ASSERT(m_handle == NULL);
+
+ const uint64_t size64 = static_cast< uint64_t >(size);
+
+ // Unlike other create functions, this function opens the existing mapping, if one already exists
+ boost::winapi::HANDLE_ h = boost::winapi::CreateFileMappingW
+ (
+ boost::winapi::INVALID_HANDLE_VALUE_,
+ reinterpret_cast< boost::winapi::SECURITY_ATTRIBUTES_* >(perms.get_native()),
+ boost::winapi::PAGE_READWRITE_ | boost::winapi::SEC_COMMIT_,
+ static_cast< boost::winapi::DWORD_ >(size64 >> 32u),
+ static_cast< boost::winapi::DWORD_ >(size64),
+ name
+ );
+
+ boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ if (BOOST_UNLIKELY(h == NULL))
+ {
+ std::ostringstream strm;
+ strm << "Failed to create or open a shared memory segment of " << size << " bytes";
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, strm.str(), (err));
+ }
+
+ const bool created = (err != ERROR_ALREADY_EXISTS);
+ try
+ {
+ if (created)
+ {
+ m_size = size;
+ }
+ else
+ {
+ // If an existing segment was opened, determine its size
+ m_size = obtain_size(h);
+ }
+ }
+ catch (...)
+ {
+ boost::winapi::CloseHandle(h);
+ throw;
+ }
+
+ m_handle = h;
+
+ return created;
+}
+
+//! Opens the existing file mapping for the shared memory segment
+void mapped_shared_memory::open(const wchar_t* name)
+{
+ BOOST_ASSERT(m_handle == NULL);
+
+ // Note: FILE_MAP_WRITE implies reading permission as well
+ boost::winapi::HANDLE_ h = boost::winapi::OpenFileMappingW(boost::winapi::FILE_MAP_WRITE_ | boost::winapi::SECTION_QUERY_, false, name);
+
+ if (BOOST_UNLIKELY(h == NULL))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to create a shared memory segment", (err));
+ }
+
+ try
+ {
+ m_size = obtain_size(h);
+ }
+ catch (...)
+ {
+ boost::winapi::CloseHandle(h);
+ throw;
+ }
+
+ m_handle = h;
+}
+
+//! Maps the file mapping into the current process memory
+void mapped_shared_memory::map()
+{
+ BOOST_ASSERT(m_handle != NULL);
+ BOOST_ASSERT(m_mapped_address == NULL);
+
+ // Note: FILE_MAP_WRITE implies reading permission as well
+ m_mapped_address = boost::winapi::MapViewOfFile
+ (
+ m_handle,
+ boost::winapi::FILE_MAP_WRITE_ | boost::winapi::SECTION_QUERY_,
+ 0u,
+ 0u,
+ m_size
+ );
+
+ if (BOOST_UNLIKELY(m_mapped_address == NULL))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to map the shared memory segment into the process address space", (err));
+ }
+}
+
+//! Unmaps the file mapping
+void mapped_shared_memory::unmap()
+{
+ BOOST_ASSERT(m_mapped_address != NULL);
+
+ BOOST_VERIFY(boost::winapi::UnmapViewOfFile(m_mapped_address) != 0);
+ m_mapped_address = NULL;
+}
+
+//! Returns the size of the file mapping identified by the handle
+std::size_t mapped_shared_memory::obtain_size(boost::winapi::HANDLE_ h)
+{
+ nt_query_section_t query_section = nt_query_section.load(boost::memory_order_acquire);
+
+ if (BOOST_UNLIKELY(query_section == NULL))
+ {
+ // Check if ntdll.dll provides NtQuerySection, see: http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FSection%2FNtQuerySection.html
+ boost::winapi::HMODULE_ ntdll = boost::winapi::GetModuleHandleW(L"ntdll.dll");
+ if (BOOST_UNLIKELY(ntdll == NULL))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain a handle to ntdll.dll", (err));
+ }
+
+ query_section = (nt_query_section_t)boost::winapi::get_proc_address(ntdll, "NtQuerySection");
+ if (BOOST_UNLIKELY(query_section == NULL))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain the NtQuerySection function", (err));
+ }
+
+ nt_query_section.store(query_section, boost::memory_order_release);
+ }
+
+ section_basic_information info = {};
+ boost::winapi::NTSTATUS_ err = query_section
+ (
+ h,
+ 0u, // SectionBasicInformation
+ &info,
+ sizeof(info),
+ NULL
+ );
+ if (BOOST_UNLIKELY(err != 0u))
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to test obtain size of the shared memory segment", (ERROR_INVALID_HANDLE));
+ }
+
+ return static_cast< std::size_t >(info.section_size.QuadPart);
+}
+
+} // namespace aux
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/windows/mapped_shared_memory.hpp b/src/boost/libs/log/src/windows/mapped_shared_memory.hpp
new file mode 100644
index 000000000..1b5b85e5b
--- /dev/null
+++ b/src/boost/libs/log/src/windows/mapped_shared_memory.hpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/mapped_shared_memory.hpp
+ * \author Andrey Semashev
+ * \date 13.02.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WINDOWS_MAPPED_SHARED_MEMORY_HPP_INCLUDED_
+#define BOOST_LOG_WINDOWS_MAPPED_SHARED_MEMORY_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <boost/winapi/basic_types.hpp>
+#include <cstddef>
+#include <boost/assert.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/log/utility/permissions.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+namespace aux {
+
+/*!
+ * A replacement for to \c mapped_shared_memory and \c mapped_region from Boost.Interprocess.
+ * The significant difference is that the shared memory name is passed as a UTF-16 string and
+ * errors are reported as Boost.Log exceptions.
+ */
+class mapped_shared_memory
+{
+private:
+ struct section_basic_information
+ {
+ void* base_address;
+ boost::winapi::ULONG_ section_attributes;
+ boost::winapi::LARGE_INTEGER_ section_size;
+ };
+ typedef boost::winapi::NTSTATUS_ (__stdcall *nt_query_section_t)(boost::winapi::HANDLE_ h, unsigned int info_class, section_basic_information* pinfo, boost::winapi::ULONG_ info_size, boost::winapi::ULONG_* ret_len);
+
+private:
+ boost::winapi::HANDLE_ m_handle;
+ void* m_mapped_address;
+ std::size_t m_size;
+ static boost::atomic< nt_query_section_t > nt_query_section;
+
+public:
+ BOOST_CONSTEXPR mapped_shared_memory() BOOST_NOEXCEPT :
+ m_handle(NULL),
+ m_mapped_address(NULL),
+ m_size(0u)
+ {
+ }
+
+ ~mapped_shared_memory();
+
+ //! Creates a new file mapping for the shared memory segment
+ void create(const wchar_t* name, std::size_t size, permissions const& perms = permissions());
+ //! Creates a new file mapping for the shared memory segment or opens the existing one. Returns \c true if the region was created and \c false if an existing one was opened.
+ bool create_or_open(const wchar_t* name, std::size_t size, permissions const& perms = permissions());
+ //! Opens the existing file mapping for the shared memory segment
+ void open(const wchar_t* name);
+
+ //! Maps the file mapping into the current process memory
+ void map();
+ //! Unmaps the file mapping
+ void unmap();
+
+ //! Returns the size of the opened shared memory segment
+ std::size_t size() const BOOST_NOEXCEPT { return m_size; }
+ //! Returns the address of the mapped shared memory
+ void* address() const BOOST_NOEXCEPT { return m_mapped_address; }
+
+ BOOST_DELETED_FUNCTION(mapped_shared_memory(mapped_shared_memory const&))
+ BOOST_DELETED_FUNCTION(mapped_shared_memory& operator=(mapped_shared_memory const&))
+
+private:
+ //! Returns the size of the file mapping identified by the handle
+ static std::size_t obtain_size(boost::winapi::HANDLE_ h);
+};
+
+} // namespace aux
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WINDOWS_MAPPED_SHARED_MEMORY_HPP_INCLUDED_
diff --git a/src/boost/libs/log/src/windows/object_name.cpp b/src/boost/libs/log/src/windows/object_name.cpp
new file mode 100644
index 000000000..5b56a0352
--- /dev/null
+++ b/src/boost/libs/log/src/windows/object_name.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/object_name.cpp
+ * \author Andrey Semashev
+ * \date 06.03.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#include <boost/log/detail/config.hpp>
+#include <cstddef>
+#include <cstdlib>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#include <windows.h>
+#include <lmcons.h>
+#include <security.h>
+#include "windows/auto_handle.hpp"
+#include "windows/utf_code_conversion.hpp"
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace ipc {
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+class auto_boundary_descriptor
+{
+private:
+ HANDLE m_handle;
+
+public:
+ explicit auto_boundary_descriptor(HANDLE h = NULL) BOOST_NOEXCEPT : m_handle(h)
+ {
+ }
+
+ ~auto_boundary_descriptor() BOOST_NOEXCEPT
+ {
+ if (m_handle)
+ DeleteBoundaryDescriptor(m_handle);
+ }
+
+ void init(HANDLE h) BOOST_NOEXCEPT
+ {
+ BOOST_ASSERT(m_handle == NULL);
+ m_handle = h;
+ }
+
+ HANDLE get() const BOOST_NOEXCEPT { return m_handle; }
+ HANDLE* get_ptr() BOOST_NOEXCEPT { return &m_handle; }
+
+ void swap(auto_boundary_descriptor& that) BOOST_NOEXCEPT
+ {
+ HANDLE h = m_handle;
+ m_handle = that.m_handle;
+ that.m_handle = h;
+ }
+
+ BOOST_DELETED_FUNCTION(auto_boundary_descriptor(auto_boundary_descriptor const&))
+ BOOST_DELETED_FUNCTION(auto_boundary_descriptor& operator=(auto_boundary_descriptor const&))
+};
+
+//! Handle for the private namespace for \c user scope
+static boost::atomic< HANDLE > g_user_private_namespace;
+
+//! Closes the private namespace on process exit
+void close_user_namespace()
+{
+ HANDLE h = g_user_private_namespace.load(boost::memory_order_acquire);
+ if (h)
+ {
+ ClosePrivateNamespace(h, 0);
+ g_user_private_namespace.store((HANDLE)NULL, boost::memory_order_release);
+ }
+}
+
+//! Attempts to create or open the private namespace
+bool init_user_namespace()
+{
+ HANDLE h = g_user_private_namespace.load(boost::memory_order_acquire);
+ if (BOOST_UNLIKELY(!h))
+ {
+ // Obtain the current user SID
+ boost::log::ipc::aux::auto_handle h_process_token;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, h_process_token.get_ptr()))
+ return false;
+
+ DWORD token_user_size = 0;
+ GetTokenInformation(h_process_token.get(), TokenUser, NULL, 0u, &token_user_size);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || token_user_size < sizeof(TOKEN_USER))
+ return false;
+ std::vector< unsigned char > token_user_storage(static_cast< std::size_t >(token_user_size), static_cast< unsigned char >(0u));
+ if (!GetTokenInformation(h_process_token.get(), TokenUser, &token_user_storage[0], token_user_size, &token_user_size))
+ return false;
+
+ TOKEN_USER const& token_user = *reinterpret_cast< const TOKEN_USER* >(&token_user_storage[0]);
+ if (!token_user.User.Sid)
+ return false;
+
+ // Create a boundary descriptor with the user's SID
+ auto_boundary_descriptor h_boundary(CreateBoundaryDescriptorW(L"User", 0));
+ if (!h_boundary.get())
+ return false;
+
+ if (!AddSIDToBoundaryDescriptor(h_boundary.get_ptr(), token_user.User.Sid))
+ return false;
+
+ // Create or open a namespace for kernel objects
+ h = CreatePrivateNamespaceW(NULL, h_boundary.get(), L"User");
+ if (!h)
+ h = OpenPrivateNamespaceW(h_boundary.get(), L"User");
+
+ if (h)
+ {
+ HANDLE expected = NULL;
+ if (g_user_private_namespace.compare_exchange_strong(expected, h, boost::memory_order_acq_rel, boost::memory_order_acquire))
+ {
+ std::atexit(&close_user_namespace);
+ }
+ else
+ {
+ // Another thread must have opened the namespace
+ ClosePrivateNamespace(h, 0);
+ h = expected;
+ }
+ }
+ }
+
+ return !!h;
+}
+
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+//! Returns a prefix string for a shared resource according to the scope
+std::string get_scope_prefix(object_name::scope ns)
+{
+ std::string prefix;
+ switch (ns)
+ {
+ case object_name::process_group:
+ {
+ // For now consider all processes as members of the common process group. It may change if there is found
+ // a way to get a process group id (i.e. id of the closest parent process that was created with the CREATE_NEW_PROCESS_GROUP flag).
+ prefix = "Local\\boost.log.process_group";
+ }
+ break;
+
+ case object_name::session:
+ {
+ prefix = "Local\\boost.log.session";
+ }
+ break;
+
+ case object_name::user:
+ {
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ if (init_user_namespace())
+ {
+ prefix = "User\\boost.log.user";
+ }
+ else
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+ {
+ wchar_t buf[UNLEN + 1u];
+ ULONG len = sizeof(buf) / sizeof(*buf);
+ if (BOOST_UNLIKELY(!GetUserNameExW(NameSamCompatible, buf, &len)))
+ {
+ const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain the current user name", (err));
+ }
+
+ std::replace(buf, buf + len, L'\\', L'.');
+
+ prefix = "Local\\boost.log.user." + boost::log::aux::utf16_to_utf8(buf);
+ }
+ }
+ break;
+
+ default:
+ prefix = "Global\\boost.log.global";
+ break;
+ }
+
+ prefix.push_back('.');
+
+ return BOOST_LOG_NRVO_RESULT(prefix);
+}
+
+} // namespace
+
+//! Constructor from the object name
+BOOST_LOG_API object_name::object_name(scope ns, const char* str) :
+ m_name(get_scope_prefix(ns) + str)
+{
+}
+
+//! Constructor from the object name
+BOOST_LOG_API object_name::object_name(scope ns, std::string const& str) :
+ m_name(get_scope_prefix(ns) + str)
+{
+}
+
+} // namespace ipc
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
diff --git a/src/boost/libs/log/src/windows/simple_event_log.mc b/src/boost/libs/log/src/windows/simple_event_log.mc
new file mode 100644
index 000000000..f26eda9ff
--- /dev/null
+++ b/src/boost/libs/log/src/windows/simple_event_log.mc
@@ -0,0 +1,58 @@
+;/*
+; * Copyright Andrey Semashev 2007 - 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)
+; *
+; * This file is the Boost.Log library implementation, see the library documentation
+; * at http://www.boost.org/libs/log/doc/log.html.
+; */
+;
+;/* --------------------------------------------------------
+; * HEADER SECTION
+; */
+SeverityNames=(Debug=0x0:BOOST_LOG_SEVERITY_DEBUG
+ Info=0x1:BOOST_LOG_SEVERITY_INFO
+ Warning=0x2:BOOST_LOG_SEVERITY_WARNING
+ Error=0x3:BOOST_LOG_SEVERITY_ERROR
+ )
+;
+;
+;
+;/* ------------------------------------------------------------------
+; * MESSAGE DEFINITION SECTION
+; */
+
+MessageIdTypedef=DWORD
+
+MessageId=0x100
+Severity=Debug
+Facility=Application
+SymbolicName=BOOST_LOG_MSG_DEBUG
+Language=English
+%1
+.
+
+MessageId=0x101
+Severity=Info
+Facility=Application
+SymbolicName=BOOST_LOG_MSG_INFO
+Language=English
+%1
+.
+
+MessageId=0x102
+Severity=Warning
+Facility=Application
+SymbolicName=BOOST_LOG_MSG_WARNING
+Language=English
+%1
+.
+
+MessageId=0x103
+Severity=Error
+Facility=Application
+SymbolicName=BOOST_LOG_MSG_ERROR
+Language=English
+%1
+.
diff --git a/src/boost/libs/log/src/windows/utf_code_conversion.hpp b/src/boost/libs/log/src/windows/utf_code_conversion.hpp
new file mode 100644
index 000000000..7b00f13d7
--- /dev/null
+++ b/src/boost/libs/log/src/windows/utf_code_conversion.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file windows/utf_code_conversion.hpp
+ * \author Andrey Semashev
+ * \date 22.02.2016
+ *
+ * \brief This header is the Boost.Log library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
+ */
+
+#ifndef BOOST_LOG_WINDOWS_UTF_CODE_CONVERSION_HPP_INCLUDED_
+#define BOOST_LOG_WINDOWS_UTF_CODE_CONVERSION_HPP_INCLUDED_
+
+#include <boost/log/detail/config.hpp>
+#include <string>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+//! Converts UTF-8 to UTF-16
+std::wstring utf8_to_utf16(const char* str);
+//! Converts UTF-16 to UTF-8
+std::string utf16_to_utf8(const wchar_t* str);
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>
+
+#endif // BOOST_LOG_WINDOWS_UTF_CODE_CONVERSION_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/Jamfile.v2 b/src/boost/libs/log/test/Jamfile.v2
new file mode 100644
index 000000000..112469323
--- /dev/null
+++ b/src/boost/libs/log/test/Jamfile.v2
@@ -0,0 +1,123 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+# The file was adapted from libs/tr2/test/Jamfile.v2 by John Maddock.
+
+import testing ;
+import path ;
+import regex ;
+import os ;
+import ../build/log-platform-config ;
+
+project
+ : requirements
+ <conditional>@log-platform-config.set-platform-defines
+
+ <include>common
+
+ # Disable warnings about using 'insecure' standard C functions
+ <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_SCL_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_SCL_SECURE_NO_DEPRECATE
+ <toolset>intel-win:<define>_CRT_SECURE_NO_WARNINGS
+ <toolset>intel-win:<define>_CRT_SECURE_NO_DEPRECATE
+
+ <toolset>msvc:<cxxflags>/bigobj
+ <toolset>msvc:<cxxflags>/wd4503 # decorated name length exceeded, name was truncated
+ <toolset>msvc:<cxxflags>/wd4456 # declaration of 'A' hides previous local declaration
+ <toolset>msvc:<cxxflags>/wd4459 # declaration of 'A' hides global declaration
+ <toolset>msvc:<cxxflags>/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion
+ <toolset>msvc:<cxxflags>/wd4355 # 'this' : used in base member initializer list
+
+ # Disable Intel warnings:
+ # warning #177: function "X" was declared but never referenced
+ # warning #780: using-declaration ignored -- it refers to the current namespace
+ # warning #2196: routine is both "inline" and "noinline"
+ # remark #1782: #pragma once is obsolete. Use #ifndef guard instead.
+ # remark #193: zero used for undefined preprocessing identifier "X"
+ # remark #304: access control not specified ("public" by default)
+ # remark #981: operands are evaluated in unspecified order
+ # remark #1418: external function definition with no prior declaration
+ # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"...
+ # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible
+ # warning #279: controlling expression is constant
+ <toolset>intel-win:<cxxflags>"/Qwd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-linux:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+ <toolset>intel-darwin:<cxxflags>"-wd177,780,2196,1782,193,304,981,1418,411,734,279"
+
+ <toolset>darwin:<cxxflags>-ftemplate-depth-1024
+ <toolset>gcc:<cxxflags>-ftemplate-depth-1024
+
+ <toolset>gcc:<cxxflags>-fno-strict-aliasing # avoids strict aliasing violations in other Boost components
+
+ # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76
+ <target-os>cygwin:<define>BOOST_LOG_WITHOUT_IPC
+
+ <library>/boost/log//boost_log
+ <library>/boost/log//boost_log_setup
+ <library>/boost/date_time//boost_date_time
+ <library>/boost/regex//boost_regex
+ <library>/boost/filesystem//boost_filesystem
+ <library>/boost/test//boost_unit_test_framework
+ <threading>single:<define>BOOST_LOG_NO_THREADS
+ <threading>multi:<library>/boost/thread//boost_thread
+ : default-build
+ # Testers typically don't specify threading environment and the library can be built and tested for single and multi. I'm more interested in multi though.
+ <threading>multi
+# <link>static
+ ;
+
+# this rule enumerates through all the sources and invokes
+# the run rule for each source, the result is a list of all
+# the run rules, which we can pass on to the test_suite rule:
+rule test_all
+{
+ local all_rules ;
+ local file ;
+
+ if ! [ os.environ BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS ]
+ {
+ local headers_path = [ path.make $(BOOST_ROOT)/libs/log/include/boost/log ] ;
+ for file in [ path.glob-tree $(headers_path) : *.hpp : detail ]
+ {
+ local rel_file = [ path.relative-to $(headers_path) $(file) ] ;
+ # Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end.
+ # All '/' are replaced with '-' because apparently test scripts have a problem with test names containing slashes.
+ local test_name = [ regex.replace ~hdr/$(rel_file) "/" "-" ] ;
+ #ECHO $(rel_file) ;
+ all_rules += [ compile compile/self_contained_header.cpp : <define>"BOOST_LOG_TEST_HEADER=$(rel_file)" <dependency>$(file) : $(test_name) ] ;
+ }
+ }
+
+ for file in [ glob compile/*.cpp ]
+ {
+ if [ path.basename $(file) ] != "self_contained_header.cpp"
+ {
+ all_rules += [ compile $(file) ] ;
+ }
+ }
+ for file in [ glob compile_fail/*.cpp ]
+ {
+ all_rules += [ compile-fail $(file) ] ;
+ }
+ for file in [ glob run/*.cpp ]
+ {
+ all_rules += [ run $(file) ] ;
+ }
+
+ if ! [ os.environ BOOST_LOG_TEST_WITHOUT_EXAMPLES ]
+ {
+ all_rules += [ build-project ../example ] ;
+ }
+
+ #ECHO All rules: $(all_rules) ;
+ return $(all_rules) ;
+}
+
+test-suite log : [ test_all ] ;
diff --git a/src/boost/libs/log/test/common/attr_comparison.hpp b/src/boost/libs/log/test/common/attr_comparison.hpp
new file mode 100644
index 000000000..b4be4f484
--- /dev/null
+++ b/src/boost/libs/log/test/common/attr_comparison.hpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_comparison.hpp
+ * \author Andrey Semashev
+ * \date 06.08.2010
+ *
+ * \brief This header contains tools for attribute comparison in attribute-related tests.
+ */
+
+#ifndef BOOST_LOG_TESTS_ATTR_COMPARISON_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_ATTR_COMPARISON_HPP_INCLUDED_
+
+#include <ostream>
+#include <boost/log/attributes/attribute.hpp>
+
+class attribute_factory_helper :
+ public boost::log::attribute
+{
+ typedef boost::log::attribute base_type;
+
+public:
+ attribute_factory_helper(base_type const& that) : base_type(that)
+ {
+ }
+
+ impl* get_impl() const
+ {
+ return base_type::get_impl();
+ }
+};
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+inline bool operator== (attribute const& left, attribute const& right)
+{
+ return attribute_factory_helper(left).get_impl() == attribute_factory_helper(right).get_impl();
+}
+inline bool operator!= (attribute const& left, attribute const& right)
+{
+ return attribute_factory_helper(left).get_impl() != attribute_factory_helper(right).get_impl();
+}
+
+inline std::ostream& operator<< (std::ostream& strm, attribute const& val)
+{
+ strm << attribute_factory_helper(val).get_impl();
+ return strm;
+}
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#endif // BOOST_LOG_TESTS_ATTR_COMPARISON_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/common/char_definitions.hpp b/src/boost/libs/log/test/common/char_definitions.hpp
new file mode 100644
index 000000000..2cf0d6640
--- /dev/null
+++ b/src/boost/libs/log/test/common/char_definitions.hpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file char_definitions.hpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains common type definitions for character type dependent tests.
+ */
+
+#ifndef BOOST_LOG_TESTS_CHAR_DEFINITIONS_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_CHAR_DEFINITIONS_HPP_INCLUDED_
+
+#include <string>
+#include <iostream>
+#include <boost/mpl/vector.hpp>
+
+namespace mpl = boost::mpl;
+
+typedef mpl::vector<
+#ifdef BOOST_LOG_USE_CHAR
+ char
+#endif
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+ ,
+#endif
+#ifdef BOOST_LOG_USE_WCHAR_T
+ wchar_t
+#endif
+>::type char_types;
+
+template< typename >
+struct test_data;
+
+
+#ifdef BOOST_LOG_USE_CHAR
+
+template< >
+struct test_data< char >
+{
+ static const char* abc() { return "abc"; }
+ static const char* ABC() { return "ABC"; }
+ static const char* some_test_string() { return "some test string"; }
+ static const char* zero_to_five() { return "012345"; }
+ static const char* def() { return "def"; }
+ static const char* aaa() { return "aaa"; }
+ static const char* abcd() { return "abcd"; }
+ static const char* zz() { return "zz"; }
+ static const char* abcdefg0123456789() { return "abcdefg0123456789"; }
+
+ static const char* attr1() { return "attr1"; }
+ static const char* attr2() { return "attr2"; }
+ static const char* attr3() { return "attr3"; }
+ static const char* attr4() { return "attr4"; }
+
+ static const char* int_format1() { return "%08d"; }
+ static const char* fp_format1() { return "%06.3f"; }
+};
+
+//! The function compares two strings and prints them if they are not equal
+inline bool equal_strings(std::string const& left, std::string const& right)
+{
+ if (left != right)
+ {
+ std::cout << "Left: \"" << left << "\"\nRight: \"" << right << "\"" << std::endl;
+ return false;
+ }
+ else
+ return true;
+}
+
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+
+template< >
+struct test_data< wchar_t >
+{
+ static const wchar_t* abc() { return L"abc"; }
+ static const wchar_t* ABC() { return L"ABC"; }
+ static const wchar_t* some_test_string() { return L"some test string"; }
+ static const wchar_t* zero_to_five() { return L"012345"; }
+ static const wchar_t* def() { return L"def"; }
+ static const wchar_t* aaa() { return L"aaa"; }
+ static const wchar_t* abcd() { return L"abcd"; }
+ static const wchar_t* zz() { return L"zz"; }
+ static const wchar_t* abcdefg0123456789() { return L"abcdefg0123456789"; }
+
+ static const char* attr1() { return "attr1"; }
+ static const char* attr2() { return "attr2"; }
+ static const char* attr3() { return "attr3"; }
+ static const char* attr4() { return "attr4"; }
+
+ static const wchar_t* int_format1() { return L"%08d"; }
+ static const wchar_t* fp_format1() { return L"%06.3f"; }
+};
+
+//! The function compares two strings and prints them if they are not equal
+inline bool equal_strings(std::wstring const& left, std::wstring const& right)
+{
+ if (left != right)
+ {
+ std::wcout << L"Left: \"" << left << L"\"\nRight: \"" << right << L"\"" << std::endl;
+ return false;
+ }
+ else
+ return true;
+}
+
+#endif // BOOST_LOG_USE_WCHAR_T
+
+#endif // BOOST_LOG_TESTS_CHAR_DEFINITIONS_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/common/make_record.hpp b/src/boost/libs/log/test/common/make_record.hpp
new file mode 100644
index 000000000..9d1f028df
--- /dev/null
+++ b/src/boost/libs/log/test/common/make_record.hpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file make_record.hpp
+ * \author Andrey Semashev
+ * \date 18.03.2009
+ *
+ * \brief This header contains a helper function make_record that creates a log record with the specified attributes.
+ */
+
+#ifndef BOOST_LOG_TESTS_MAKE_RECORD_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_MAKE_RECORD_HPP_INCLUDED_
+
+#include <boost/move/utility_core.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+
+inline boost::log::record make_record(boost::log::attribute_set const& src_attrs = boost::log::attribute_set())
+{
+ return boost::log::core::get()->open_record(src_attrs);
+}
+
+inline boost::log::record_view make_record_view(boost::log::attribute_set const& src_attrs = boost::log::attribute_set())
+{
+ return make_record(src_attrs).lock();
+}
+
+#endif // BOOST_LOG_TESTS_MAKE_RECORD_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/common/test_sink.hpp b/src/boost/libs/log/test/common/test_sink.hpp
new file mode 100644
index 000000000..da88830ec
--- /dev/null
+++ b/src/boost/libs/log/test/common/test_sink.hpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file test_sink.hpp
+ * \author Andrey Semashev
+ * \date 18.03.2009
+ *
+ * \brief This header contains a test sink frontend that is used through various tests.
+ */
+
+#ifndef BOOST_LOG_TESTS_TEST_SINK_HPP_INCLUDED_
+#define BOOST_LOG_TESTS_TEST_SINK_HPP_INCLUDED_
+
+#include <cstddef>
+#include <map>
+#include <boost/log/core/record_view.hpp>
+#include <boost/log/attributes/attribute_name.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/sinks/sink.hpp>
+#include <boost/log/expressions/filter.hpp>
+
+//! A sink implementation for testing purpose
+struct test_sink :
+ public boost::log::sinks::sink
+{
+public:
+ typedef boost::log::attribute_value_set attribute_values;
+ typedef boost::log::record_view record_type;
+ typedef boost::log::filter filter_type;
+ typedef attribute_values::key_type key_type;
+
+ struct key_type_order
+ {
+ typedef bool result_type;
+
+ result_type operator() (key_type const& left, key_type const& right) const
+ {
+ return left.id() < right.id();
+ }
+ };
+
+ typedef std::map< key_type, std::size_t, key_type_order > attr_counters_map;
+
+public:
+ filter_type m_Filter;
+ attr_counters_map m_Consumed;
+ std::size_t m_RecordCounter;
+
+public:
+ test_sink() : boost::log::sinks::sink(false), m_RecordCounter(0) {}
+
+ void set_filter(filter_type const& f)
+ {
+ m_Filter = f;
+ }
+
+ void reset_filter()
+ {
+ m_Filter.reset();
+ }
+
+ bool will_consume(attribute_values const& attributes)
+ {
+ return m_Filter(attributes);
+ }
+
+ void consume(record_type const& record)
+ {
+ ++m_RecordCounter;
+ attribute_values::const_iterator
+ it = record.attribute_values().begin(),
+ end = record.attribute_values().end();
+ for (; it != end; ++it)
+ ++m_Consumed[it->first];
+ }
+
+ void flush()
+ {
+ }
+
+ void clear()
+ {
+ m_RecordCounter = 0;
+ m_Consumed.clear();
+ }
+};
+
+#endif // BOOST_LOG_TESTS_TEST_SINK_HPP_INCLUDED_
diff --git a/src/boost/libs/log/test/compile/current_function_support.cpp b/src/boost/libs/log/test/compile/current_function_support.cpp
new file mode 100644
index 000000000..cdcd1051a
--- /dev/null
+++ b/src/boost/libs/log/test/compile/current_function_support.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file current_function_support.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2010
+ *
+ * \brief This test checks that the BOOST_CURRENT_FUNCTION macro has semantics
+ * compatible with Boost.Log on the current platform.
+ *
+ * The point of this test is to determine whether the macro unfolds into a string literal
+ * rather than a pointer to a string. This is critical because BOOST_LOG_WFUNCTION
+ * relies on this fact - it determines the length of the literal by applying sizeof to it.
+ */
+
+#define BOOST_TEST_MODULE current_function_support
+
+#include <boost/current_function.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_array.hpp>
+
+template< typename T >
+void check(T& param)
+{
+ BOOST_STATIC_ASSERT(boost::is_array< T >::value);
+}
+
+int main(int, char*[])
+{
+ check(BOOST_CURRENT_FUNCTION);
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/self_contained_header.cpp b/src/boost/libs/log/test/compile/self_contained_header.cpp
new file mode 100644
index 000000000..8e3a2c5a0
--- /dev/null
+++ b/src/boost/libs/log/test/compile/self_contained_header.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file self_contained_header.cpp
+ * \author Andrey Semashev
+ * \date 15.03.2014
+ *
+ * \brief This file contains a test boilerplate for checking that every public header is self-contained and does not have any missing #includes.
+ */
+
+#define BOOST_LOG_TEST_INCLUDE_HEADER() <boost/log/BOOST_LOG_TEST_HEADER>
+
+#include BOOST_LOG_TEST_INCLUDE_HEADER()
+
+int main(int, char*[])
+{
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/src_logger_assignable.cpp b/src/boost/libs/log/test/compile/src_logger_assignable.cpp
new file mode 100644
index 000000000..d1d51f57e
--- /dev/null
+++ b/src/boost/libs/log/test/compile/src_logger_assignable.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file src_logger_assignable.cpp
+ * \author Andrey Semashev
+ * \date 16.05.2011
+ *
+ * \brief This header contains a test for logger assignability.
+ */
+
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/sources/severity_logger.hpp>
+#include <boost/log/sources/channel_logger.hpp>
+#include <boost/log/sources/severity_channel_logger.hpp>
+
+template< typename LoggerT >
+void test()
+{
+ LoggerT lg1, lg2;
+
+ // Loggers must be assignable. The assignment operator must be taken
+ // from the composite_logger class and not auto-generated (in which
+ // case it will fail to compile because assignment in basic_logger is private).
+ lg1 = lg2;
+}
+
+int main(int, char*[])
+{
+ test< boost::log::sources::logger >();
+ test< boost::log::sources::severity_logger< > >();
+ test< boost::log::sources::channel_logger< > >();
+ test< boost::log::sources::severity_channel_logger< > >();
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/src_logger_get_attributes.cpp b/src/boost/libs/log/test/compile/src_logger_get_attributes.cpp
new file mode 100644
index 000000000..b837917a7
--- /dev/null
+++ b/src/boost/libs/log/test/compile/src_logger_get_attributes.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file src_logger_get_attributes.cpp
+ * \author Andrey Semashev
+ * \date 01.03.2014
+ *
+ * \brief This header contains a test for logger \c get_attributes method.
+ */
+
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/sources/severity_logger.hpp>
+#include <boost/log/sources/channel_logger.hpp>
+#include <boost/log/sources/severity_channel_logger.hpp>
+
+template< typename LoggerT >
+void test()
+{
+ LoggerT lg;
+
+ // Test that get_attributes(), which is a const method, can acquire the internal mutex in the threading model.
+ lg.get_attributes();
+}
+
+int main(int, char*[])
+{
+ test< boost::log::sources::logger >();
+ test< boost::log::sources::severity_logger< > >();
+ test< boost::log::sources::channel_logger< > >();
+ test< boost::log::sources::severity_channel_logger< > >();
+
+#if !defined(BOOST_LOG_NO_THREADS)
+ test< boost::log::sources::logger_mt >();
+ test< boost::log::sources::severity_logger_mt< > >();
+ test< boost::log::sources::channel_logger_mt< > >();
+ test< boost::log::sources::severity_channel_logger_mt< > >();
+#endif
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile/util_unique_identifier.cpp b/src/boost/libs/log/test/compile/util_unique_identifier.cpp
new file mode 100644
index 000000000..50e7ee032
--- /dev/null
+++ b/src/boost/libs/log/test/compile/util_unique_identifier.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_unique_identifier.cpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains tests for the unique identifier name generator.
+ */
+
+#include <boost/log/utility/unique_identifier_name.hpp>
+
+// Some hints to avoid warnings about unused variables in this test
+#if defined(__GNUC__)
+#define BOOST_LOG_AUX_UNUSED_ATTR __attribute__((unused))
+#else
+#define BOOST_LOG_AUX_UNUSED_ATTR
+#endif
+
+int main(int, char*[])
+{
+ // Names with the same prefixes may coexist in different lines
+ BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var) = 0;
+ BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var) = 0;
+
+ // Names with different prefixes may coexist on the same line
+ BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var1) = 0; BOOST_LOG_AUX_UNUSED_ATTR int BOOST_LOG_UNIQUE_IDENTIFIER_NAME(var2) = 0;
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp b/src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp
new file mode 100644
index 000000000..5ad7a5997
--- /dev/null
+++ b/src/boost/libs/log/test/compile_fail/attr_functor_void_return.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_functor_void_return.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This test checks that it is not possible to create a functor attribute
+ * with a void-returning functor.
+ */
+
+#define BOOST_TEST_MODULE attr_functor_void_return
+
+#include <boost/utility/result_of.hpp>
+#include <boost/log/attributes/attribute.hpp>
+#include <boost/log/attributes/function.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // A test function that returns an attribute value
+ void get_attr_value() {}
+
+} // namespace
+
+int main(int, char*[])
+{
+ logging::attribute attr1 =
+#ifndef BOOST_NO_RESULT_OF
+ attrs::make_function(&get_attr_value);
+#else
+ attrs::make_function< void >(&get_attr_value);
+#endif
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/performance/Jamfile.v2 b/src/boost/libs/log/test/performance/Jamfile.v2
new file mode 100644
index 000000000..036ed6e0b
--- /dev/null
+++ b/src/boost/libs/log/test/performance/Jamfile.v2
@@ -0,0 +1,15 @@
+#
+# Copyright Andrey Semashev 2007 - 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)
+#
+
+exe record_emission
+ : record_emission.cpp ../../build//boost_log
+ ;
+
+exe dump
+ : dump.cpp ../../build//boost_log
+ ;
+
diff --git a/src/boost/libs/log/test/performance/dump.cpp b/src/boost/libs/log/test/performance/dump.cpp
new file mode 100644
index 000000000..b19b161ac
--- /dev/null
+++ b/src/boost/libs/log/test/performance/dump.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file dump.cpp
+ * \author Andrey Semashev
+ * \date 05.05.2013
+ *
+ * \brief This code measures performance dumping binary data
+ */
+
+#include <cstdlib>
+#include <iomanip>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <algorithm>
+
+#include <boost/cstdint.hpp>
+#include <boost/date_time/microsec_time_clock.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/dump.hpp>
+
+namespace logging = boost::log;
+
+const unsigned int base_loop_count = 10000;
+
+void test(std::size_t block_size)
+{
+ std::cout << "Block size: " << block_size << " bytes.";
+
+ std::vector< boost::uint8_t > data;
+ data.resize(block_size);
+ std::generate_n(data.begin(), block_size, &std::rand);
+
+ std::string str;
+ logging::formatting_ostream strm(str);
+
+ const boost::uint8_t* const p = &data[0];
+
+ boost::uint64_t data_processed = 0, duration = 0;
+ boost::posix_time::ptime start, end;
+ start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+ do
+ {
+ for (unsigned int i = 0; i < base_loop_count; ++i)
+ {
+ strm << logging::dump(p, block_size);
+ str.clear();
+ }
+ end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+ data_processed += base_loop_count * block_size;
+ duration = (end - start).total_microseconds();
+ }
+ while (duration < 2000000);
+
+ std::cout << " Test duration: " << duration << " us ("
+ << std::fixed << std::setprecision(3) << static_cast< double >(data_processed) / (static_cast< double >(duration) * (1048576.0 / 1000000.0))
+ << " MiB per second)" << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ test(32);
+ test(128);
+ test(1024);
+ test(16384);
+ test(1048576);
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/performance/record_emission.cpp b/src/boost/libs/log/test/performance/record_emission.cpp
new file mode 100644
index 000000000..0dd388cb0
--- /dev/null
+++ b/src/boost/libs/log/test/performance/record_emission.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file record_emission.cpp
+ * \author Andrey Semashev
+ * \date 22.03.2009
+ *
+ * \brief This code measures performance of log record emission
+ */
+
+// #define BOOST_LOG_USE_CHAR
+// #define BOOST_ALL_DYN_LINK 1
+// #define BOOST_LOG_DYN_LINK 1
+#define BOOST_NO_DYN_LINK 1
+
+#include <iomanip>
+#include <iostream>
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/smart_ptr/make_shared_object.hpp>
+#include <boost/date_time/microsec_time_clock.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/log/core.hpp>
+#include <boost/log/common.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks.hpp>
+#include <boost/log/sinks/basic_sink_backend.hpp>
+#include <boost/log/sources/logger.hpp>
+
+#include <boost/log/expressions.hpp>
+
+#include <boost/log/attributes/scoped_attribute.hpp>
+
+enum config
+{
+ RECORD_COUNT = 20000000,
+ THREAD_COUNT = 8,
+ SINK_COUNT = 3
+};
+
+namespace logging = boost::log;
+namespace expr = boost::log::expressions;
+namespace sinks = boost::log::sinks;
+namespace attrs = boost::log::attributes;
+namespace src = boost::log::sources;
+namespace keywords = boost::log::keywords;
+
+enum severity_level
+{
+ normal,
+ warning,
+ error
+};
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)
+
+namespace {
+
+ //! A fake sink backend that receives log records
+ class fake_backend :
+ public sinks::basic_sink_backend< sinks::concurrent_feeding >
+ {
+ public:
+ void consume(logging::record_view const& rec)
+ {
+ }
+ };
+
+} // namespace
+
+void test(unsigned int record_count, boost::barrier& bar)
+{
+ BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
+ src::severity_logger< severity_level > slg;
+// src::logger lg;
+ bar.wait();
+
+ for (unsigned int i = 0; i < record_count; ++i)
+ {
+ BOOST_LOG_SEV(slg, warning) << "Test record";
+// BOOST_LOG(lg) << "Test record";
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ std::cout << "Test config: " << THREAD_COUNT << " threads, " << SINK_COUNT << " sinks, " << RECORD_COUNT << " records" << std::endl;
+//__debugbreak();
+// typedef sinks::unlocked_sink< fake_backend > fake_sink;
+// typedef sinks::synchronous_sink< fake_backend > fake_sink;
+ typedef sinks::asynchronous_sink< fake_backend > fake_sink;
+ for (unsigned int i = 0; i < SINK_COUNT; ++i)
+ logging::core::get()->add_sink(boost::make_shared< fake_sink >());
+
+ logging::core::get()->add_global_attribute("LineID", attrs::counter< unsigned int >(1));
+ logging::core::get()->add_global_attribute("TimeStamp", attrs::local_clock());
+ logging::core::get()->add_global_attribute("Scope", attrs::named_scope());
+
+// logging::core::get()->set_filter(severity > normal); // all records pass the filter
+// logging::core::get()->set_filter(severity > error); // all records don't pass the filter
+
+// logging::core::get()->set_filter(severity > error); // all records don't pass the filter
+
+ const unsigned int record_count = RECORD_COUNT / THREAD_COUNT;
+ boost::barrier bar(THREAD_COUNT);
+ boost::thread_group threads;
+
+ for (unsigned int i = 1; i < THREAD_COUNT; ++i)
+ threads.create_thread(boost::bind(&test, record_count, boost::ref(bar)));
+
+ boost::posix_time::ptime start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time(), end;
+ test(record_count, bar);
+ if (THREAD_COUNT > 1)
+ threads.join_all();
+ end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+
+ unsigned long long duration = (end - start).total_microseconds();
+
+ std::cout << "Test duration: " << duration << " us ("
+ << std::fixed << std::setprecision(3) << static_cast< double >(RECORD_COUNT) / (static_cast< double >(duration) / 1000000.0)
+ << " records per second)" << std::endl;
+
+ return 0;
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_set.cpp b/src/boost/libs/log/test/run/attr_attribute_set.cpp
new file mode 100644
index 000000000..669f4d099
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_set.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_attribute_set.cpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains tests for the attribute set class.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_set
+
+#include <list>
+#include <vector>
+#include <string>
+#include <utility>
+#include <iterator>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include "char_definitions.hpp"
+#include "attr_comparison.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+// The test checks construction and assignment
+BOOST_AUTO_TEST_CASE(construction)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+ BOOST_CHECK(set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 0UL);
+
+ attr_set set2 = set1;
+ BOOST_CHECK(set2.empty());
+ BOOST_CHECK_EQUAL(set2.size(), 0UL);
+
+ set2[data::attr1()] = attr1;
+ set2[data::attr2()] = attr2;
+ BOOST_CHECK(set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 0UL);
+ BOOST_CHECK(!set2.empty());
+ BOOST_CHECK_EQUAL(set2.size(), 2UL);
+
+ attr_set set3 = set2;
+ BOOST_CHECK(!set3.empty());
+ BOOST_CHECK_EQUAL(set3.size(), 2UL);
+ BOOST_CHECK_EQUAL(set3.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set3.count(data::attr2()), 1UL);
+ BOOST_CHECK_EQUAL(set3.count(data::attr3()), 0UL);
+
+ set1[data::attr3()] = attr3;
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(data::attr3()), 1UL);
+
+ set2 = set1;
+ BOOST_REQUIRE_EQUAL(set1.size(), set2.size());
+ BOOST_CHECK(std::equal(set1.begin(), set1.end(), set2.begin()));
+}
+
+// The test checks lookup methods
+BOOST_AUTO_TEST_CASE(lookup)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+ typedef std::basic_string< char > string;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ // Traditional find methods
+ attr_set::iterator it = set1.find(data::attr1());
+ BOOST_CHECK(it != set1.end());
+ BOOST_CHECK_EQUAL(it->second, attr1);
+
+ string s1 = data::attr2();
+ it = set1.find(s1);
+ BOOST_CHECK(it != set1.end());
+ BOOST_CHECK_EQUAL(it->second, attr2);
+
+ it = set1.find(data::attr1());
+ BOOST_CHECK(it != set1.end());
+ BOOST_CHECK_EQUAL(it->second, attr1);
+
+ it = set1.find(data::attr3());
+ BOOST_CHECK(it == set1.end());
+
+ // Subscript operator
+ logging::attribute p = set1[data::attr1()];
+ BOOST_CHECK_EQUAL(p, attr1);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ p = set1[s1];
+ BOOST_CHECK_EQUAL(p, attr2);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ p = set1[data::attr1()];
+ BOOST_CHECK_EQUAL(p, attr1);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ p = set1[data::attr3()];
+ BOOST_CHECK(!p);
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ // Counting elements
+ BOOST_CHECK_EQUAL(set1.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(s1), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set1.count(data::attr3()), 0UL);
+}
+
+// The test checks insertion methods
+BOOST_AUTO_TEST_CASE(insertion)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+ typedef std::basic_string< char > string;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+
+ // Traditional insert methods
+ std::pair< attr_set::iterator, bool > res = set1.insert(data::attr1(), attr1);
+ BOOST_CHECK(res.second);
+ BOOST_CHECK(res.first != set1.end());
+ BOOST_CHECK(res.first->first == data::attr1());
+ BOOST_CHECK_EQUAL(res.first->second, attr1);
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 1UL);
+
+ res = set1.insert(std::make_pair(attr_set::key_type(data::attr2()), attr2));
+ BOOST_CHECK(res.second);
+ BOOST_CHECK(res.first != set1.end());
+ BOOST_CHECK(res.first->first == data::attr2());
+ BOOST_CHECK_EQUAL(res.first->second, attr2);
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ // Insertion attempt of an attribute with the name of an already existing attribute
+ res = set1.insert(std::make_pair(attr_set::key_type(data::attr2()), attr3));
+ BOOST_CHECK(!res.second);
+ BOOST_CHECK(res.first != set1.end());
+ BOOST_CHECK(res.first->first == data::attr2());
+ BOOST_CHECK_EQUAL(res.first->second, attr2);
+ BOOST_CHECK(!set1.empty());
+ BOOST_CHECK_EQUAL(set1.size(), 2UL);
+
+ // Mass insertion
+ typedef attr_set::key_type key_type;
+ std::list< std::pair< key_type, logging::attribute > > elems;
+ elems.push_back(std::make_pair(key_type(data::attr2()), attr2));
+ elems.push_back(std::make_pair(key_type(data::attr1()), attr1));
+ elems.push_back(std::make_pair(key_type(data::attr3()), attr3));
+ // ... with element duplication
+ elems.push_back(std::make_pair(key_type(data::attr1()), attr3));
+
+ attr_set set2;
+ set2.insert(elems.begin(), elems.end());
+ BOOST_CHECK(!set2.empty());
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+ typedef attr_set::mapped_type mapped_type;
+ BOOST_CHECK_EQUAL(static_cast< mapped_type >(set2[data::attr1()]), attr1);
+ BOOST_CHECK_EQUAL(static_cast< mapped_type >(set2[data::attr2()]), attr2);
+ BOOST_CHECK_EQUAL(static_cast< mapped_type >(set2[data::attr3()]), attr3);
+
+ // The same, but with insertion results collection
+ std::vector< std::pair< attr_set::iterator, bool > > results;
+
+ attr_set set3;
+ set3.insert(elems.begin(), elems.end(), std::back_inserter(results));
+ BOOST_REQUIRE_EQUAL(results.size(), elems.size());
+ BOOST_CHECK(!set3.empty());
+ BOOST_REQUIRE_EQUAL(set3.size(), 3UL);
+ attr_set::iterator it = set3.find(data::attr1());
+ BOOST_REQUIRE(it != set3.end());
+ BOOST_CHECK(it->first == data::attr1());
+ BOOST_CHECK_EQUAL(it->second, attr1);
+ BOOST_CHECK(it == results[1].first);
+ it = set3.find(data::attr2());
+ BOOST_REQUIRE(it != set3.end());
+ BOOST_CHECK(it->first == data::attr2());
+ BOOST_CHECK_EQUAL(it->second, attr2);
+ BOOST_CHECK(it == results[0].first);
+ it = set3.find(data::attr3());
+ BOOST_REQUIRE(it != set3.end());
+ BOOST_CHECK(it->first == data::attr3());
+ BOOST_CHECK_EQUAL(it->second, attr3);
+ BOOST_CHECK(it == results[2].first);
+
+ BOOST_CHECK(results[0].second);
+ BOOST_CHECK(results[1].second);
+ BOOST_CHECK(results[2].second);
+ BOOST_CHECK(!results[3].second);
+
+ // Subscript operator
+ attr_set set4;
+
+ logging::attribute& p1 = (set4[data::attr1()] = attr1);
+ BOOST_CHECK_EQUAL(set4.size(), 1UL);
+ BOOST_CHECK_EQUAL(p1, attr1);
+
+ logging::attribute& p2 = (set4[string(data::attr2())] = attr2);
+ BOOST_CHECK_EQUAL(set4.size(), 2UL);
+ BOOST_CHECK_EQUAL(p2, attr2);
+
+ logging::attribute& p3 = (set4[key_type(data::attr3())] = attr3);
+ BOOST_CHECK_EQUAL(set4.size(), 3UL);
+ BOOST_CHECK_EQUAL(p3, attr3);
+
+ // subscript operator can replace existing elements
+ logging::attribute& p4 = (set4[data::attr3()] = attr1);
+ BOOST_CHECK_EQUAL(set4.size(), 3UL);
+ BOOST_CHECK_EQUAL(p4, attr1);
+}
+
+// The test checks erasure methods
+BOOST_AUTO_TEST_CASE(erasure)
+{
+ typedef logging::attribute_set attr_set;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_set set2 = set1;
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+
+ BOOST_CHECK_EQUAL(set2.erase(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set2.size(), 2UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr1()), 0UL);
+
+ BOOST_CHECK_EQUAL(set2.erase(data::attr1()), 0UL);
+ BOOST_CHECK_EQUAL(set2.size(), 2UL);
+
+ set2.erase(set2.begin());
+ BOOST_CHECK_EQUAL(set2.size(), 1UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr2()), 0UL);
+
+ set2 = set1;
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+
+ attr_set::iterator it = set2.begin();
+ set2.erase(++it, set2.end());
+ BOOST_CHECK_EQUAL(set2.size(), 1UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr2()), 0UL);
+ BOOST_CHECK_EQUAL(set2.count(data::attr3()), 0UL);
+
+ set2 = set1;
+ BOOST_REQUIRE_EQUAL(set2.size(), 3UL);
+
+ set2.clear();
+ BOOST_CHECK(set2.empty());
+ BOOST_CHECK_EQUAL(set2.size(), 0UL);
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp b/src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp
new file mode 100644
index 000000000..142307d90
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_set_ticket11106.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_attribute_set_ticket11106.cpp
+ * \author Andrey Semashev
+ * \date 15.03.2015
+ *
+ * \brief This header contains a test for the fix for https://svn.boost.org/trac/boost/ticket/11106.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_set_ticket11106
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+
+// The test checks that insertion does not invalidate existing elements in the container
+BOOST_AUTO_TEST_CASE(ticket11106)
+{
+ boost::log::attribute_set set;
+
+ unsigned int i = 0;
+ while (i < 100)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+ boost::log::attribute_name name = strm.str();
+
+ std::pair< boost::log::attribute_set::iterator, bool > res = set.insert(name, boost::log::attributes::make_constant(5));
+ ++i;
+
+ BOOST_CHECK(res.second); // check that insertion succeeded
+ BOOST_CHECK(set.find(res.first->first) != set.end()); // check that lookup works
+
+ // Now check that all previously inserted elements are still findable
+ unsigned int j = 0;
+ for (boost::log::attribute_set::const_iterator it = set.begin(), end = set.end(); it != end; ++it, ++j)
+ {
+ boost::log::attribute_name key = it->first;
+ BOOST_CHECK(set.find(key) != set.end());
+ }
+ BOOST_CHECK_EQUAL(j, i);
+ }
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_value_impl.cpp b/src/boost/libs/log/test/run/attr_attribute_value_impl.cpp
new file mode 100644
index 000000000..682b2e486
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_value_impl.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_attribute_value_impl.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This header contains tests for the basic attribute value class.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_value_impl
+
+#include <string>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools//floating_point_comparison.hpp>
+#include <boost/log/attributes/attribute_value.hpp>
+#include <boost/log/attributes/attribute_value_impl.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+#include <boost/log/utility/functional/bind_assign.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // Type dispatcher for the supported types
+ struct my_dispatcher :
+ public logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ >
+ {
+ typedef logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ > base_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_dispatcher() :
+ base_type(*this),
+ m_Expected(none_expected),
+ m_Int(0),
+ m_Double(0.0)
+ {
+ }
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (double const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void operator() (std::string const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test verifies that type dispatching works
+BOOST_AUTO_TEST_CASE(type_dispatching)
+{
+ my_dispatcher disp;
+ logging::attribute_value p1(attrs::make_attribute_value< int >(10));
+ logging::attribute_value p2(attrs::make_attribute_value< double > (5.5));
+ logging::attribute_value p3(attrs::make_attribute_value< std::string >(std::string("Hello, world!")));
+ logging::attribute_value p4(attrs::make_attribute_value< float >(static_cast< float >(-7.2)));
+
+ disp.set_expected(10);
+ BOOST_CHECK(p1.dispatch(disp));
+ BOOST_CHECK(p1.dispatch(disp)); // check that the contained value doesn't change over time or upon dispatching
+
+ disp.set_expected(5.5);
+ BOOST_CHECK(p2.dispatch(disp));
+
+ disp.set_expected("Hello, world!");
+ BOOST_CHECK(p3.dispatch(disp));
+
+ disp.set_expected();
+ BOOST_CHECK(!p4.dispatch(disp));
+}
+
+// The test verifies that value extraction works
+BOOST_AUTO_TEST_CASE(value_extraction)
+{
+ logging::attribute_value p1(attrs::make_attribute_value< int >(10));
+ logging::attribute_value p2(attrs::make_attribute_value< double >(5.5));
+
+ logging::value_ref< int > val1 = p1.extract< int >();
+ BOOST_CHECK(!!val1);
+ BOOST_CHECK_EQUAL(val1.get(), 10);
+
+ logging::value_ref< double > val2 = p1.extract< double >();
+ BOOST_CHECK(!val2);
+
+ double val3 = 0.0;
+ BOOST_CHECK(p2.visit< double >(logging::bind_assign(val3)));
+ BOOST_CHECK_CLOSE(val3, 5.5, 0.001);
+}
+
+// The test verifies that the detach_from_thread returns a valid pointer
+BOOST_AUTO_TEST_CASE(detaching_from_thread)
+{
+ boost::intrusive_ptr< logging::attribute_value::impl > p1(new attrs::attribute_value_impl< int >(10));
+ boost::intrusive_ptr< logging::attribute_value::impl > p2 = p1->detach_from_thread();
+ BOOST_CHECK(!!p2);
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_value_set.cpp b/src/boost/libs/log/test/run/attr_attribute_value_set.cpp
new file mode 100644
index 000000000..1b8067387
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_value_set.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_attribute_value_set.cpp
+ * \author Andrey Semashev
+ * \date 24.01.2009
+ *
+ * \brief This header contains tests for the attribute value set.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_value_set
+
+#include <vector>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <iterator>
+#include <boost/config.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools//floating_point_comparison.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ //! A simple attribute value receiver functional object
+ template< typename T >
+ struct receiver
+ {
+ typedef void result_type;
+ receiver(T& val) : m_Val(val) {}
+ result_type operator() (T const& val) const
+ {
+ m_Val = val;
+ }
+
+ private:
+ T& m_Val;
+ };
+
+ //! The function extracts attribute value
+ template< typename T >
+ inline bool get_attr_value(logging::attribute_value const& val, T& res)
+ {
+ receiver< T > r(res);
+ logging::static_type_dispatcher< T > disp(r);
+ return val.dispatch(disp);
+ }
+
+} // namespace
+
+// The test checks construction and assignment
+BOOST_AUTO_TEST_CASE(construction)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+ attrs::constant< char > attr4('L');
+
+ {
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ BOOST_CHECK(!view1.empty());
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ }
+ {
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set2[data::attr2()] = attr2;
+ set3[data::attr3()] = attr3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ BOOST_CHECK(!view1.empty());
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+
+ attr_values view2 = view1;
+ BOOST_CHECK(!view2.empty());
+ BOOST_CHECK_EQUAL(view2.size(), 3UL);
+ }
+
+ // Check that the more prioritized attributes replace the less ones
+ {
+ attrs::constant< int > attr2_2(20);
+ attrs::constant< double > attr4_2(10.3);
+ attrs::constant< float > attr3_3(static_cast< float >(-7.2));
+ attrs::constant< unsigned int > attr4_3(5);
+
+ attr_set set1, set2, set3;
+ set3[data::attr1()] = attr1;
+ set3[data::attr2()] = attr2;
+ set3[data::attr3()] = attr3;
+ set3[data::attr4()] = attr4;
+
+ set2[data::attr2()] = attr2_2;
+ set2[data::attr4()] = attr4_2;
+
+ set1[data::attr3()] = attr3_3;
+ set1[data::attr4()] = attr4_3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ BOOST_CHECK(!view1.empty());
+ BOOST_CHECK_EQUAL(view1.size(), 4UL);
+
+ int n = 0;
+ BOOST_CHECK(logging::visit< int >(data::attr1(), view1, receiver< int >(n)));
+ BOOST_CHECK_EQUAL(n, 10);
+
+ BOOST_CHECK(logging::visit< int >(data::attr2(), view1, receiver< int >(n)));
+ BOOST_CHECK_EQUAL(n, 20);
+
+ float f = static_cast< float >(0.0);
+ BOOST_CHECK(logging::visit< float >(data::attr3(), view1, receiver< float >(f)));
+ BOOST_CHECK_CLOSE(f, static_cast< float >(-7.2), static_cast< float >(0.001));
+
+ unsigned int m = 0;
+ BOOST_CHECK(logging::visit< unsigned int >(data::attr4(), view1, receiver< unsigned int >(m)));
+ BOOST_CHECK_EQUAL(m, 5U);
+ }
+}
+
+// The test checks lookup methods
+BOOST_AUTO_TEST_CASE(lookup)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+ typedef std::basic_string< char > string;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values view1(set1, set2, set3);
+ view1.freeze();
+
+ // Traditional find methods
+ attr_values::const_iterator it = view1.find(data::attr1());
+ BOOST_CHECK(it != view1.end());
+ BOOST_CHECK(it->first == data::attr1());
+ int val1 = 0;
+ BOOST_CHECK(get_attr_value(it->second, val1));
+ BOOST_CHECK_EQUAL(val1, 10);
+
+ string s1 = data::attr2();
+ it = view1.find(s1);
+ BOOST_CHECK(it != view1.end());
+ BOOST_CHECK(it->first == data::attr2());
+ double val2 = 0;
+ BOOST_CHECK(get_attr_value(it->second, val2));
+ BOOST_CHECK_CLOSE(val2, 5.5, 0.001);
+
+ it = view1.find(data::attr3());
+ BOOST_CHECK(it != view1.end());
+ BOOST_CHECK(it->first == data::attr3());
+ std::string val3;
+ BOOST_CHECK(get_attr_value(it->second, val3));
+ BOOST_CHECK_EQUAL(val3, "Hello, world!");
+
+ // make an additional check that the result is absent if the value type does not match the requested type
+ BOOST_CHECK(!get_attr_value(it->second, val2));
+
+ it = view1.find(data::attr4());
+ BOOST_CHECK(it == view1.end());
+
+ // Subscript operator
+ logging::attribute_value p = view1[data::attr1()];
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ BOOST_CHECK(!!p);
+ BOOST_CHECK(get_attr_value(p, val1));
+ BOOST_CHECK_EQUAL(val1, 10);
+
+ p = view1[s1];
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ BOOST_CHECK(!!p);
+ BOOST_CHECK(get_attr_value(p, val2));
+ BOOST_CHECK_CLOSE(val2, 5.5, 0.001);
+
+ p = view1[data::attr3()];
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+ BOOST_CHECK(!!p);
+ BOOST_CHECK(get_attr_value(p, val3));
+ BOOST_CHECK_EQUAL(val3, "Hello, world!");
+
+ p = view1[data::attr4()];
+ BOOST_CHECK(!p);
+ BOOST_CHECK_EQUAL(view1.size(), 3UL);
+
+ // Counting elements
+ BOOST_CHECK_EQUAL(view1.count(data::attr1()), 1UL);
+ BOOST_CHECK_EQUAL(view1.count(s1), 1UL);
+ BOOST_CHECK_EQUAL(view1.count(data::attr3()), 1UL);
+ BOOST_CHECK_EQUAL(view1.count(data::attr4()), 0UL);
+}
+
+// The test checks size method
+BOOST_AUTO_TEST_CASE(size)
+{
+ typedef logging::attribute_value_set attr_values;
+ attrs::constant< int > attr1(10);
+
+ attr_values view;
+ view.freeze();
+
+ unsigned int i = 0;
+ for (; i < 100; ++i)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+
+ view.insert(attr_values::key_type(strm.str()), attr1.get_value());
+ }
+
+ BOOST_CHECK_EQUAL(view.size(), i);
+}
diff --git a/src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp b/src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp
new file mode 100644
index 000000000..d5a0388f8
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_attribute_value_set_ticket11190.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_attribute_value_set_ticket11190.cpp
+ * \author Andrey Semashev
+ * \date 25.04.2015
+ *
+ * \brief This header contains a test for the fix for https://svn.boost.org/trac/boost/ticket/11190.
+ */
+
+#define BOOST_TEST_MODULE attr_attribute_value_set_ticket11190
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+
+// The test checks that insertion does not invalidate existing elements in the container
+BOOST_AUTO_TEST_CASE(ticket11190)
+{
+ boost::log::attribute_set set, dummy;
+
+ unsigned int i = 0;
+ while (i < 100)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+ boost::log::attribute_name name = strm.str();
+
+ std::pair< boost::log::attribute_set::iterator, bool > res = set.insert(name, boost::log::attributes::make_constant(5));
+ ++i;
+
+ BOOST_CHECK(res.second); // check that insertion succeeded
+ // check that lookup works
+ boost::log::attribute_set::iterator find_result = set.find(name);
+ BOOST_CHECK(find_result != set.end());
+ BOOST_CHECK(find_result == res.first);
+ }
+
+ boost::log::attribute_value_set vset(set, dummy, dummy);
+ BOOST_CHECK_EQUAL(vset.size(), set.size());
+
+ // Check that all inserted elements are findable
+ unsigned int j = 0;
+ for (boost::log::attribute_value_set::const_iterator it = vset.begin(), end = vset.end(); it != end; ++it, ++j)
+ {
+ boost::log::attribute_name key = it->first;
+ BOOST_CHECK(vset.find(key) != vset.end());
+ }
+
+ // Check that vset.size() is valid
+ BOOST_CHECK_EQUAL(j, i);
+}
diff --git a/src/boost/libs/log/test/run/attr_function.cpp b/src/boost/libs/log/test/run/attr_function.cpp
new file mode 100644
index 000000000..014097f71
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_function.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_function.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This header contains tests for the function attribute.
+ */
+
+#define BOOST_TEST_MODULE attr_function
+
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/utility/result_of.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/function.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // Type dispatcher for the supported types
+ struct my_dispatcher :
+ public logging::static_type_dispatcher<
+ boost::mpl::vector< int, std::string >
+ >
+ {
+ typedef logging::static_type_dispatcher<
+ boost::mpl::vector< int, std::string >
+ > base_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ string_expected
+ };
+
+ my_dispatcher() : base_type(*this), m_Expected(none_expected), m_Int(0) {}
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (std::string const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ std::string m_String;
+ };
+
+ // A test function that returns an attribute value
+ int get_attr_value()
+ {
+ return 10;
+ }
+
+ // A test functional object that returns an attribute value
+ struct attr_value_generator
+ {
+ typedef std::string result_type;
+
+ explicit attr_value_generator(unsigned int& count) : m_CallsCount(count) {}
+ result_type operator() () const
+ {
+ ++m_CallsCount;
+ return "Hello, world!";
+ }
+
+ private:
+ unsigned int& m_CallsCount;
+ };
+
+} // namespace
+
+// The test verifies that the attribute calls the specified functor and returns the value returned by the functor
+BOOST_AUTO_TEST_CASE(calling)
+{
+ unsigned int call_count = 0;
+ my_dispatcher disp;
+
+ logging::attribute attr1 =
+#ifndef BOOST_NO_RESULT_OF
+ attrs::make_function(&get_attr_value);
+#else
+ attrs::make_function< int >(&get_attr_value);
+#endif
+
+ logging::attribute attr2 =
+#ifndef BOOST_NO_RESULT_OF
+ attrs::make_function(attr_value_generator(call_count));
+#else
+ attrs::make_function< std::string >(attr_value_generator(call_count));
+#endif
+
+ logging::attribute_value p1(attr1.get_value());
+ logging::attribute_value p2(attr2.get_value());
+ BOOST_CHECK_EQUAL(call_count, 1u);
+ logging::attribute_value p3(attr2.get_value());
+ BOOST_CHECK_EQUAL(call_count, 2u);
+
+ disp.set_expected(10);
+ BOOST_CHECK(p1.dispatch(disp));
+ BOOST_CHECK(p1.dispatch(disp)); // check that the contained value doesn't change over time or upon dispatching
+
+ disp.set_expected("Hello, world!");
+ BOOST_CHECK(p2.dispatch(disp));
+ BOOST_CHECK(p3.dispatch(disp));
+}
diff --git a/src/boost/libs/log/test/run/attr_named_scope.cpp b/src/boost/libs/log/test/run/attr_named_scope.cpp
new file mode 100644
index 000000000..9429a36c4
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_named_scope.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_named_scope.cpp
+ * \author Andrey Semashev
+ * \date 25.01.2009
+ *
+ * \brief This header contains tests for the named scope attribute.
+ */
+
+#define BOOST_TEST_MODULE attr_named_scope
+
+#include <sstream>
+#include <boost/mpl/vector.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/attribute.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+#include <boost/log/attributes/attribute_value.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/value_ref.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ template< typename >
+ struct scope_test_data;
+
+ template< >
+ struct scope_test_data< char >
+ {
+ static logging::string_literal scope1() { return logging::str_literal("scope1"); }
+ static logging::string_literal scope2() { return logging::str_literal("scope2"); }
+ static logging::string_literal file() { return logging::str_literal(__FILE__); }
+ };
+
+} // namespace
+
+// The test verifies that the scope macros are defined
+BOOST_AUTO_TEST_CASE(macros)
+{
+#ifdef BOOST_LOG_USE_CHAR
+ BOOST_CHECK(BOOST_IS_DEFINED(BOOST_LOG_NAMED_SCOPE(name)));
+ BOOST_CHECK(BOOST_IS_DEFINED(BOOST_LOG_FUNCTION()));
+#endif // BOOST_LOG_USE_CHAR
+}
+
+// The test checks that scope tracking works correctly
+BOOST_AUTO_TEST_CASE(scope_tracking)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef attrs::named_scope_list scopes;
+ typedef attrs::named_scope_entry scope;
+ typedef scope_test_data< char > scope_data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(scope_data::scope1(), scope_data::file(), line1);
+
+ BOOST_CHECK(!named_scope::get_scopes().empty());
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 1UL);
+
+ logging::attribute_value val = attr.get_value();
+ BOOST_REQUIRE(!!val);
+
+ logging::value_ref< scopes > sc = val.extract< scopes >();
+ BOOST_REQUIRE(!!sc);
+ BOOST_REQUIRE(!sc->empty());
+ BOOST_CHECK_EQUAL(sc->size(), 1UL);
+
+ scope const& s1 = sc->front();
+ BOOST_CHECK(s1.scope_name == scope_data::scope1());
+ BOOST_CHECK(s1.file_name == scope_data::file());
+ BOOST_CHECK(s1.line == line1);
+
+ // Second scope
+ const unsigned int line2 = __LINE__;
+ scope new_scope(scope_data::scope2(), scope_data::file(), line2);
+ named_scope::push_scope(new_scope);
+
+ BOOST_CHECK(!named_scope::get_scopes().empty());
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 2UL);
+
+ val = attr.get_value();
+ BOOST_REQUIRE(!!val);
+
+ sc = val.extract< scopes >();
+ BOOST_REQUIRE(!!sc);
+ BOOST_REQUIRE(!sc->empty());
+ BOOST_CHECK_EQUAL(sc->size(), 2UL);
+
+ scopes::const_iterator it = sc->begin();
+ scope const& s2 = *(it++);
+ BOOST_CHECK(s2.scope_name == scope_data::scope1());
+ BOOST_CHECK(s2.file_name == scope_data::file());
+ BOOST_CHECK(s2.line == line1);
+
+ scope const& s3 = *(it++);
+ BOOST_CHECK(s3.scope_name == scope_data::scope2());
+ BOOST_CHECK(s3.file_name == scope_data::file());
+ BOOST_CHECK(s3.line == line2);
+
+ BOOST_CHECK(it == sc->end());
+
+ // Second scope goes out
+ named_scope::pop_scope();
+
+ BOOST_CHECK(!named_scope::get_scopes().empty());
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 1UL);
+
+ val = attr.get_value();
+ BOOST_REQUIRE(!!val);
+
+ sc = val.extract< scopes >();
+ BOOST_REQUIRE(!!sc);
+ BOOST_REQUIRE(!sc->empty());
+ BOOST_CHECK_EQUAL(sc->size(), 1UL);
+
+ scope const& s4 = sc->back(); // should be the same as front
+ BOOST_CHECK(s4.scope_name == scope_data::scope1());
+ BOOST_CHECK(s4.file_name == scope_data::file());
+ BOOST_CHECK(s4.line == line1);
+}
+
+// The test checks that detaching from thread works correctly
+BOOST_AUTO_TEST_CASE(detaching_from_thread)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef attrs::named_scope_list scopes;
+ typedef scope_test_data< char > scope_data;
+
+ named_scope attr;
+
+ sentry scope1(scope_data::scope1(), scope_data::file(), __LINE__);
+ logging::attribute_value val1 = attr.get_value();
+ val1.detach_from_thread();
+
+ sentry scope2(scope_data::scope2(), scope_data::file(), __LINE__);
+ logging::attribute_value val2 = attr.get_value();
+ val2.detach_from_thread();
+
+ logging::value_ref< scopes > sc1 = val1.extract< scopes >(), sc2 = val2.extract< scopes >();
+ BOOST_REQUIRE(!!sc1);
+ BOOST_REQUIRE(!!sc2);
+ BOOST_CHECK_EQUAL(sc1->size(), 1UL);
+ BOOST_CHECK_EQUAL(sc2->size(), 2UL);
+}
+
+// The test checks that output streaming is possible
+BOOST_AUTO_TEST_CASE(ostreaming)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef scope_test_data< char > scope_data;
+
+ sentry scope1(scope_data::scope1(), scope_data::file(), __LINE__);
+ sentry scope2(scope_data::scope2(), scope_data::file(), __LINE__);
+
+ std::basic_ostringstream< char > strm;
+ strm << named_scope::get_scopes();
+
+ BOOST_CHECK(!strm.str().empty());
+}
+
+// The test checks that the scope list becomes thread-independent after copying
+BOOST_AUTO_TEST_CASE(copying)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+ typedef attrs::named_scope_list scopes;
+ typedef scope_test_data< char > scope_data;
+
+ sentry scope1(scope_data::scope1(), scope_data::file(), __LINE__);
+ scopes sc = named_scope::get_scopes();
+ sentry scope2(scope_data::scope2(), scope_data::file(), __LINE__);
+ BOOST_CHECK_EQUAL(sc.size(), 1UL);
+ BOOST_CHECK_EQUAL(named_scope::get_scopes().size(), 2UL);
+}
diff --git a/src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp b/src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp
new file mode 100644
index 000000000..46fc6a1c6
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_sets_insertion_lookup.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_sets_insertion_lookup.cpp
+ * \author Andrey Semashev
+ * \date 21.06.2014
+ *
+ * \brief This header contains tests for the attribute and attribute value sets. This test performs special checks
+ * for insert() and find() methods that depend on the attribute name ids and the order in which
+ * insert() operations are invoked, see https://sourceforge.net/p/boost-log/discussion/710022/thread/e883db9a/.
+ */
+
+#define BOOST_TEST_MODULE attr_sets_insertion_lookup
+
+#include <string>
+#include <sstream>
+#include <boost/config.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+template< typename SetT, typename ValueT >
+void test_insertion_lookup(SetT& values, ValueT const& value)
+{
+ // Initialize attribute names. Each name will gain a consecutive id.
+ logging::attribute_name names[20];
+ for (unsigned int i = 0; i < sizeof(names) / sizeof(*names); ++i)
+ {
+ std::ostringstream strm;
+ strm << "Attr" << i;
+ names[i] = logging::attribute_name(strm.str());
+ }
+
+ // Insert attribute values in this exact order so that different cases in the hash table implementation are tested.
+ values.insert(names[17], value);
+ values.insert(names[1], value);
+ values.insert(names[8], value);
+ values.insert(names[9], value);
+ values.insert(names[10], value);
+ values.insert(names[16], value);
+ values.insert(names[0], value);
+ values.insert(names[11], value);
+ values.insert(names[12], value);
+ values.insert(names[13], value);
+ values.insert(names[14], value);
+ values.insert(names[15], value);
+ values.insert(names[18], value);
+ values.insert(names[19], value);
+ values.insert(names[4], value);
+ values.insert(names[5], value);
+ values.insert(names[7], value);
+ values.insert(names[6], value);
+ values.insert(names[2], value);
+ values.insert(names[3], value);
+
+ // Check that all values are accessible through iteration and find()
+ for (unsigned int i = 0; i < sizeof(names) / sizeof(*names); ++i)
+ {
+ BOOST_CHECK_MESSAGE(values.find(names[i]) != values.end(), "Attribute " << names[i] << " (id: " << names[i].id() << ") not found by find()");
+
+ bool found_by_iteration = false;
+ for (typename SetT::const_iterator it = values.begin(), end = values.end(); it != end; ++it)
+ {
+ if (it->first == names[i])
+ {
+ found_by_iteration = true;
+ break;
+ }
+ }
+
+ BOOST_CHECK_MESSAGE(found_by_iteration, "Attribute " << names[i] << " (id: " << names[i].id() << ") not found by iteration");
+ }
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(attributes)
+{
+ logging::attribute_set values;
+ attrs::constant< int > attr(10);
+
+ test_insertion_lookup(values, attr);
+}
+
+BOOST_AUTO_TEST_CASE(attribute_values)
+{
+ logging::attribute_value_set values;
+ attrs::constant< int > attr(10);
+
+ test_insertion_lookup(values, attr.get_value());
+}
diff --git a/src/boost/libs/log/test/run/attr_value_visitation.cpp b/src/boost/libs/log/test/run/attr_value_visitation.cpp
new file mode 100644
index 000000000..f057fb17b
--- /dev/null
+++ b/src/boost/libs/log/test/run/attr_value_visitation.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file attr_value_visitation.cpp
+ * \author Andrey Semashev
+ * \date 21.01.2009
+ *
+ * \brief This header contains tests for the attribute value extraction helpers.
+ */
+
+#define BOOST_TEST_MODULE attr_value_visitation
+
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools/floating_point_comparison.hpp>
+#include <boost/log/attributes/value_visitation.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include "char_definitions.hpp"
+
+namespace mpl = boost::mpl;
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+namespace {
+
+ // The receiver functional object that verifies the extracted attribute values
+ struct my_receiver
+ {
+ typedef void result_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_receiver() : m_Expected(none_expected), m_Int(0), m_Double(0.0) {}
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (double const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void operator() (std::string const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+ void operator() (char value)
+ {
+ // This one should not be called
+ BOOST_ERROR("The unexpected operator() has been called");
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test checks invokers specialized on a single attribute value type
+BOOST_AUTO_TEST_CASE(single_type)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ my_receiver recv;
+
+ logging::value_visitor_invoker< int > invoker1;
+ logging::value_visitor_invoker< double > invoker2;
+ logging::value_visitor_invoker< std::string > invoker3;
+ logging::value_visitor_invoker< char > invoker4;
+
+ // These two extractors will find their values in the set
+ recv.set_expected(10);
+ BOOST_CHECK(invoker1(data::attr1(), values1, recv));
+
+ recv.set_expected(5.5);
+ BOOST_CHECK(invoker2(data::attr2(), values1, recv));
+
+ // This one will not
+ recv.set_expected();
+ BOOST_CHECK(!invoker3(data::attr3(), values1, recv));
+
+ // But it will find it in this set
+ set1[data::attr3()] = attr3;
+
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ recv.set_expected("Hello, world!");
+ BOOST_CHECK(invoker3(data::attr3(), values2, recv));
+
+ // This one will find the sought attribute value, but it will have an incorrect type
+ recv.set_expected();
+ BOOST_CHECK(!invoker4(data::attr1(), values1, recv));
+
+ // This one is the same, but there is a value of the requested type in the set
+ BOOST_CHECK(!invoker1(data::attr2(), values1, recv));
+}
+
+
+// The test checks invokers specialized with type lists
+BOOST_AUTO_TEST_CASE(multiple_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+ typedef mpl::vector< int, double, std::string, char >::type types;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ my_receiver recv;
+
+ logging::value_visitor_invoker< types > invoker;
+
+ // These two extractors will find their values in the set
+ recv.set_expected(10);
+ BOOST_CHECK(invoker(data::attr1(), values1, recv));
+
+ recv.set_expected(5.5);
+ BOOST_CHECK(invoker(data::attr2(), values1, recv));
+
+ // This one will not
+ recv.set_expected();
+ BOOST_CHECK(!invoker(data::attr3(), values1, recv));
+
+ // But it will find it in this set
+ set1[data::attr3()] = attr3;
+
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ recv.set_expected("Hello, world!");
+ BOOST_CHECK(invoker(data::attr3(), values2, recv));
+}
+
+// The test verifies the visit function
+BOOST_AUTO_TEST_CASE(visit_function)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef test_data< char > data;
+ typedef mpl::vector< int, double, std::string, char >::type types;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ my_receiver recv;
+
+ // These two extractors will find their values in the set
+ recv.set_expected(10);
+ BOOST_CHECK(logging::visit< types >(data::attr1(), values1, recv));
+
+ recv.set_expected(5.5);
+ BOOST_CHECK(logging::visit< double >(data::attr2(), values1, recv));
+
+ // These will not
+ recv.set_expected();
+ BOOST_CHECK(!logging::visit< types >(data::attr3(), values1, recv));
+ BOOST_CHECK(!logging::visit< char >(data::attr1(), values1, recv));
+
+ // But it will find it in this set
+ set1[data::attr3()] = attr3;
+
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ recv.set_expected("Hello, world!");
+ BOOST_CHECK(logging::visit< std::string >(data::attr3(), values2, recv));
+}
diff --git a/src/boost/libs/log/test/run/core.cpp b/src/boost/libs/log/test/run/core.cpp
new file mode 100644
index 000000000..69b42647a
--- /dev/null
+++ b/src/boost/libs/log/test/run/core.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file core.cpp
+ * \author Andrey Semashev
+ * \date 08.02.2009
+ *
+ * \brief This header contains tests for the logging core.
+ */
+
+#define BOOST_TEST_MODULE core
+
+#include <cstddef>
+#include <map>
+#include <string>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/move/utility_core.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/core/core.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/sinks/sink.hpp>
+#include <boost/log/core/record.hpp>
+#ifndef BOOST_LOG_NO_THREADS
+#include <boost/thread/thread.hpp>
+#endif // BOOST_LOG_NO_THREADS
+#include "char_definitions.hpp"
+#include "test_sink.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace sinks = logging::sinks;
+namespace expr = logging::expressions;
+
+// The test checks that message filtering works
+BOOST_AUTO_TEST_CASE(filtering)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::core core;
+ typedef logging::record record_type;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ boost::shared_ptr< core > pCore = core::get();
+ boost::shared_ptr< test_sink > pSink(new test_sink());
+ pCore->add_sink(pSink);
+
+ // No filtering at all
+ {
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+
+ // Core-level filtering
+ {
+ pCore->set_filter(expr::has_attr(data::attr3()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_CHECK(!rec);
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+ {
+ pCore->set_filter(expr::has_attr(data::attr2()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+
+ // Sink-level filtering
+ {
+ pCore->reset_filter();
+ pSink->set_filter(expr::has_attr(data::attr2()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+ {
+ pSink->set_filter(expr::has_attr(data::attr3()));
+ record_type rec = pCore->open_record(set1);
+ BOOST_CHECK(!rec);
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ pSink->reset_filter();
+ }
+ // Only one sink of the two accepts the record
+ {
+ pSink->set_filter(expr::has_attr(data::attr2()));
+
+ boost::shared_ptr< test_sink > pSink2(new test_sink());
+ pCore->add_sink(pSink2);
+ pSink2->set_filter(expr::has_attr(data::attr3()));
+
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+
+ BOOST_CHECK_EQUAL(pSink2->m_RecordCounter, 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr2()], 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink2->m_Consumed[data::attr4()], 0UL);
+ pCore->remove_sink(pSink2);
+ }
+
+ pCore->remove_sink(pSink);
+ pCore->reset_filter();
+}
+
+#ifndef BOOST_LOG_NO_THREADS
+namespace {
+
+ //! A test routine that runs in a separate thread
+ void thread_attributes_test()
+ {
+ typedef test_data< char > data;
+ typedef logging::core core;
+ typedef logging::record record_type;
+ typedef logging::attribute_set attr_set;
+ attrs::constant< short > attr4(255);
+
+ boost::shared_ptr< core > pCore = core::get();
+ pCore->add_thread_attribute(data::attr4(), attr4);
+
+ attr_set set1;
+ record_type rec = pCore->open_record(set1);
+ BOOST_CHECK(rec);
+ if (rec)
+ pCore->push_record(boost::move(rec));
+ }
+
+} // namespace
+#endif // BOOST_LOG_NO_THREADS
+
+// The test checks that global and thread-specific attributes work
+BOOST_AUTO_TEST_CASE(attributes)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::core core;
+ typedef logging::record record_type;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ boost::shared_ptr< core > pCore = core::get();
+ boost::shared_ptr< test_sink > pSink(new test_sink());
+ pCore->add_sink(pSink);
+
+ attr_set::iterator itGlobal = pCore->add_global_attribute(data::attr2(), attr2).first;
+ attr_set::iterator itThread = pCore->add_thread_attribute(data::attr3(), attr3).first;
+
+ {
+ attr_set glob = pCore->get_global_attributes();
+ BOOST_CHECK_EQUAL(glob.size(), 1UL);
+ BOOST_CHECK_EQUAL(glob.count(data::attr2()), 1UL);
+
+ attr_set thr = pCore->get_thread_attributes();
+ BOOST_CHECK_EQUAL(thr.size(), 1UL);
+ BOOST_CHECK_EQUAL(thr.count(data::attr3()), 1UL);
+ }
+ {
+ record_type rec = pCore->open_record(set1);
+ BOOST_REQUIRE(rec);
+ pCore->push_record(boost::move(rec));
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 0UL);
+ pSink->clear();
+ }
+#ifndef BOOST_LOG_NO_THREADS
+ {
+ boost::thread th(&thread_attributes_test);
+ th.join();
+ BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr2()], 1UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr3()], 0UL);
+ BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr4()], 1UL);
+ pSink->clear();
+
+ // Thread-specific attributes must not interfere
+ attr_set thr = pCore->get_thread_attributes();
+ BOOST_CHECK_EQUAL(thr.size(), 1UL);
+ BOOST_CHECK_EQUAL(thr.count(data::attr3()), 1UL);
+ }
+#endif // BOOST_LOG_NO_THREADS
+
+ pCore->remove_global_attribute(itGlobal);
+ pCore->remove_thread_attribute(itThread);
+ pCore->remove_sink(pSink);
+}
diff --git a/src/boost/libs/log/test/run/filt_attr.cpp b/src/boost/libs/log/test/run/filt_attr.cpp
new file mode 100644
index 000000000..237908129
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_attr.cpp
@@ -0,0 +1,403 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_attr.cpp
+ * \author Andrey Semashev
+ * \date 31.01.2009
+ *
+ * \brief This header contains tests for the \c attr filter.
+ */
+
+#define BOOST_TEST_MODULE filt_attr
+
+#include <memory>
+#include <string>
+#include <algorithm>
+#include <boost/regex.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/phoenix/bind.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/support/regex.hpp>
+#include <boost/log/expressions.hpp>
+#include "char_definitions.hpp"
+
+namespace phoenix = boost::phoenix;
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that general conditions work
+BOOST_AUTO_TEST_CASE(general_conditions)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::attr< int >(data::attr1()) == 10;
+ BOOST_CHECK(f(values1));
+
+ f = expr::attr< int >(data::attr1()) < 0;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< float >(data::attr1()).or_throw() > 0;
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = expr::attr< float >(data::attr1()) > 0;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< int >(data::attr4()).or_throw() >= 1;
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = expr::attr< int >(data::attr4()) >= 1;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< int >(data::attr4()) < 1;
+ BOOST_CHECK(!f(values1));
+
+ f = expr::attr< logging::numeric_types >(data::attr2()) > 5;
+ BOOST_CHECK(f(values1));
+
+ f = expr::attr< std::string >(data::attr3()) == "Hello, world!";
+ BOOST_CHECK(f(values1));
+
+ f = expr::attr< std::string >(data::attr3()) > "AAA";
+ BOOST_CHECK(f(values1));
+}
+
+// The test checks that is_in_range condition works
+BOOST_AUTO_TEST_CASE(in_range_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::is_in_range(expr::attr< int >(data::attr1()), 5, 20);
+ BOOST_CHECK(f(values1));
+
+ f = expr::is_in_range(expr::attr< int >(data::attr1()), 5, 10);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::is_in_range(expr::attr< int >(data::attr1()), 10, 20);
+ BOOST_CHECK(f(values1));
+
+ f = expr::is_in_range(expr::attr< logging::numeric_types >(data::attr2()), 5, 6);
+ BOOST_CHECK(f(values1));
+
+ f = expr::is_in_range(expr::attr< std::string >(data::attr3()), "AAA", "zzz");
+ BOOST_CHECK(f(values1));
+
+ // Check that strings are saved into the filter by value
+ char buf1[128];
+ char buf2[128];
+ std::strcpy(buf1, "AAA");
+ std::strcpy(buf2, "zzz");
+ f = expr::is_in_range(expr::attr< std::string >(data::attr3()), buf1, buf2);
+ std::fill_n(buf1, sizeof(buf1), static_cast< char >(0));
+ std::fill_n(buf2, sizeof(buf2), static_cast< char >(0));
+ BOOST_CHECK(f(values1));
+
+ std::strcpy(buf1, "AAA");
+ std::strcpy(buf2, "zzz");
+ f = expr::is_in_range(expr::attr< std::string >(data::attr3()),
+ static_cast< const char* >(buf1), static_cast< const char* >(buf2));
+ std::fill_n(buf1, sizeof(buf1), static_cast< char >(0));
+ std::fill_n(buf2, sizeof(buf2), static_cast< char >(0));
+ BOOST_CHECK(f(values1));
+}
+
+namespace {
+
+ struct predicate
+ {
+ typedef bool result_type;
+
+ explicit predicate(unsigned int& present_counter, bool& result) :
+ m_PresentCounter(present_counter),
+ m_Result(result)
+ {
+ }
+
+ template< typename T, typename TagT >
+ result_type operator() (logging::value_ref< T, TagT > const& val) const
+ {
+ m_PresentCounter += !val.empty();
+ return m_Result;
+ }
+
+ private:
+ unsigned int& m_PresentCounter;
+ bool& m_Result;
+ };
+
+} // namespace
+
+// The test checks that phoenix::bind interaction works
+BOOST_AUTO_TEST_CASE(bind_support_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ unsigned int present_counter = 0;
+ bool predicate_result = false;
+
+ filter f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr1()));
+ BOOST_CHECK_EQUAL(f(values1), predicate_result);
+ BOOST_CHECK_EQUAL(present_counter, 1U);
+
+ predicate_result = true;
+ BOOST_CHECK_EQUAL(f(values1), predicate_result);
+ BOOST_CHECK_EQUAL(present_counter, 2U);
+
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< logging::numeric_types >(data::attr2()));
+ BOOST_CHECK_EQUAL(f(values1), predicate_result);
+ BOOST_CHECK_EQUAL(present_counter, 3U);
+
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr2()).or_throw());
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr2()));
+ BOOST_CHECK_EQUAL(f(values1), true);
+ BOOST_CHECK_EQUAL(present_counter, 3U);
+
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr4()).or_throw());
+ BOOST_CHECK_THROW(f(values1), logging::runtime_error);
+ f = phoenix::bind(predicate(present_counter, predicate_result), expr::attr< int >(data::attr4()));
+ BOOST_CHECK_EQUAL(f(values1), true);
+ BOOST_CHECK_EQUAL(present_counter, 3U);
+}
+
+// The test checks that begins_with condition works
+BOOST_AUTO_TEST_CASE(begins_with_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::begins_with(expr::attr< std::string >(data::attr3()), "Hello");
+ BOOST_CHECK(f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr3()), "hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr3()).or_throw(), "Bye");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr3()).or_throw(), "world!");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr2()), "Hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::begins_with(expr::attr< std::string >(data::attr4()), "Hello");
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that ends_with condition works
+BOOST_AUTO_TEST_CASE(ends_with_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::ends_with(expr::attr< std::string >(data::attr3()), "world!");
+ BOOST_CHECK(f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr3()), "World!");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr3()).or_throw(), "Bye");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr3()).or_throw(), "Hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr2()), "world!");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::ends_with(expr::attr< std::string >(data::attr4()), "world!");
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that contains condition works
+BOOST_AUTO_TEST_CASE(contains_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::contains(expr::attr< std::string >(data::attr3()), "Hello");
+ BOOST_CHECK(f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr3()), "hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr3()).or_throw(), "o, w");
+ BOOST_CHECK(f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr3()).or_throw(), "world!");
+ BOOST_CHECK(f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr2()), "Hello");
+ BOOST_CHECK(!f(values1));
+
+ f = expr::contains(expr::attr< std::string >(data::attr4()), "Hello");
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that matches condition works
+BOOST_AUTO_TEST_CASE(matches_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ boost::regex rex("hello");
+ filter f = expr::matches(expr::attr< std::string >(data::attr3()), rex);
+ BOOST_CHECK(!f(values1));
+
+ rex = ".*world.*";
+ f = expr::matches(expr::attr< std::string >(data::attr3()).or_throw(), rex);
+ BOOST_CHECK(f(values1));
+
+ rex = ".*";
+ f = expr::matches(expr::attr< std::string >(data::attr2()), rex);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches(expr::attr< std::string >(data::attr4()), rex);
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f =
+ expr::attr< int >(data::attr1()) <= 10 ||
+ expr::is_in_range(expr::attr< double >(data::attr2()), 2.2, 7.7);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::attr< int >(data::attr1()) == 10 &&
+ expr::begins_with(expr::attr< std::string >(data::attr3()), "Hello");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_has_attr.cpp b/src/boost/libs/log/test/run/filt_has_attr.cpp
new file mode 100644
index 000000000..01d2d10a1
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_has_attr.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_has_attr.cpp
+ * \author Andrey Semashev
+ * \date 31.01.2009
+ *
+ * \brief This header contains tests for the \c has_attr filter.
+ */
+
+#define BOOST_TEST_MODULE filt_has_attr
+
+#include <string>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that the filter detects the attribute value presence
+BOOST_AUTO_TEST_CASE(presence_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::has_attr(data::attr1());
+ BOOST_CHECK(f(values1));
+
+ f = expr::has_attr(data::attr4());
+ BOOST_CHECK(!f(values1));
+
+ f = expr::has_attr< double >(data::attr2());
+ BOOST_CHECK(f(values1));
+
+ f = expr::has_attr< double >(data::attr3());
+ BOOST_CHECK(!f(values1));
+
+ typedef mpl::vector< unsigned int, char, std::string >::type value_types;
+ f = expr::has_attr< value_types >(data::attr3());
+ BOOST_CHECK(f(values1));
+
+ f = expr::has_attr< value_types >(data::attr1());
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::has_attr(data::attr1()) || expr::has_attr< double >(data::attr2());
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::has_attr(data::attr1()) && expr::has_attr< double >(data::attr2());
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_boost_regex.cpp b/src/boost/libs/log/test/run/filt_matches_boost_regex.cpp
new file mode 100644
index 000000000..c34fc731e
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_boost_regex.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_matches_boost_regex.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Regex backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_boost_regex
+
+#include <string>
+#include <boost/regex.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/regex.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("[a-z]*"));
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), regex_type("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), regex_type(".*"));
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) || expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) && expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp b/src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp
new file mode 100644
index 000000000..5e3ca0443
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_spirit_classic.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_matches_spirit_classic.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Spirit.Classic backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_spirit_classic
+
+#include <boost/log/detail/config.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+#define BOOST_SPIRIT_THREADSAFE 1
+#endif
+
+#include <string>
+#include <boost/spirit/include/classic_core.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/spirit_classic.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace spirit = boost::spirit::classic;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), spirit::uint_p >> '.' >> spirit::uint_p >> '.' >> spirit::uint_p >> '.' >> spirit::uint_p);
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), *spirit::lower_p);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >> *spirit::alpha_p);
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), spirit::str_p("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), *spirit::anychar_p);
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >> *spirit::alpha_p);
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p)
+ || expr::matches< logging::string_literal >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >> *spirit::alpha_p);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p >> '.' >> +spirit::digit_p)
+ && expr::matches< logging::string_literal >(data::attr2(), *spirit::upper_p >> spirit::space_p >> *spirit::lower_p >> spirit::space_p >>*spirit::alpha_p);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp b/src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp
new file mode 100644
index 000000000..c85ca011d
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_spirit_qi.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_matches_spirit_qi.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Spirit.Qi backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_spirit_qi
+
+#include <string>
+#include <boost/spirit/include/qi_core.hpp>
+#include <boost/spirit/include/qi_rule.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/spirit_qi.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace spirit = boost::spirit::qi;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_);
+ BOOST_CHECK(f(values1));
+
+ // Make sure rules also work
+ f = expr::matches< std::string >(data::attr1(), spirit::rule< std::string::const_iterator, void() >(spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_ >> '.' >> spirit::uint_));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), *spirit::lower);
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), spirit::lit("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), *spirit::char_);
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit)
+ || expr::matches< logging::string_literal >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit >> '.' >> +spirit::digit)
+ && expr::matches< logging::string_literal >(data::attr2(), *spirit::upper >> spirit::space >> *spirit::lower >> spirit::space >> *spirit::alpha);
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/filt_matches_std_regex.cpp b/src/boost/libs/log/test/run/filt_matches_std_regex.cpp
new file mode 100644
index 000000000..224551754
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_std_regex.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_matches_std_regex.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with \c std::regex backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_std_regex
+
+#include <boost/config.hpp>
+
+#if !defined(BOOST_NO_CXX11_HDR_REGEX)
+
+#include <string>
+#include <regex>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/std_regex.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef std::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("[a-z]*"));
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), regex_type("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), regex_type(".*"));
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef std::regex regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) || expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type("\\d+\\.\\d+\\.\\d+\\.\\d+")) && expr::matches< logging::string_literal >(data::attr2(), regex_type("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
+
+#else // !defined(BOOST_NO_CXX11_HDR_REGEX)
+
+int main(int, char*[])
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_NO_CXX11_HDR_REGEX)
diff --git a/src/boost/libs/log/test/run/filt_matches_xpressive.cpp b/src/boost/libs/log/test/run/filt_matches_xpressive.cpp
new file mode 100644
index 000000000..44ee0a618
--- /dev/null
+++ b/src/boost/libs/log/test/run/filt_matches_xpressive.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file filt_matches_xpressive.cpp
+ * \author Andrey Semashev
+ * \date 30.03.2014
+ *
+ * \brief This header contains tests for the \c matches filter with Boost.Xpressive backend.
+ */
+
+#define BOOST_TEST_MODULE filt_matches_xpressive
+
+#include <string>
+#include <boost/xpressive/xpressive_dynamic.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/xpressive.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that string matching works
+BOOST_AUTO_TEST_CASE(matching_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::xpressive::basic_regex< const char* > regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type::compile("\\d+\\.\\d+\\.\\d+\\.\\d+"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type::compile("[a-z]*"));
+ BOOST_CHECK(!f(values1));
+
+ f = expr::matches< logging::string_literal >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(f(values1));
+
+ f = expr::matches< std::string >(data::attr3(), regex_type::compile("Hello, world!"));
+ BOOST_CHECK(f(values1));
+
+ // Attribute value not present
+ f = expr::matches< std::string >(data::attr4(), regex_type::compile(".*"));
+ BOOST_CHECK(!f(values1));
+
+ // Attribute value type does not match
+ f = expr::matches< std::string >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+}
+
+// The test checks that the filter composition works
+BOOST_AUTO_TEST_CASE(composition_check)
+{
+ typedef logging::attribute_set attr_set;
+ typedef logging::attribute_value_set attr_values;
+ typedef logging::filter filter;
+ typedef test_data< char > data;
+ typedef boost::xpressive::basic_regex< const char* > regex_type;
+
+ attrs::constant< std::string > attr1("127.0.0.1");
+ attrs::constant< logging::string_literal > attr2(logging::str_literal("BIG brown FoX"));
+ attrs::constant< std::string > attr3("Hello, world!");
+
+ attr_set set1, set2, set3;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+ set1[data::attr2()] = attr2;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+ set1[data::attr3()] = attr3;
+ set1[data::attr1()] = attr1;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ filter f = expr::matches< std::string >(data::attr1(), regex_type::compile("\\d+\\.\\d+\\.\\d+\\.\\d+")) || expr::matches< logging::string_literal >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+
+ f = expr::matches< std::string >(data::attr1(), regex_type::compile("\\d+\\.\\d+\\.\\d+\\.\\d+")) && expr::matches< logging::string_literal >(data::attr2(), regex_type::compile("[A-Z]* [a-z]* [A-Za-z]*"));
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+}
diff --git a/src/boost/libs/log/test/run/form_attr.cpp b/src/boost/libs/log/test/run/form_attr.cpp
new file mode 100644
index 000000000..ef2deab7b
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_attr.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_attr.cpp
+ * \author Andrey Semashev
+ * \date 01.02.2009
+ *
+ * \brief This header contains tests for the \c attr formatter.
+ */
+
+#define BOOST_TEST_MODULE form_attr
+
+#include <memory>
+#include <string>
+#include <iomanip>
+#include <ostream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+ class my_class
+ {
+ int m_Data;
+
+ public:
+ explicit my_class(int data) : m_Data(data) {}
+
+ template< typename CharT, typename TraitsT >
+ friend std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_class const& obj)
+ {
+ strm << "[data: " << obj.m_Data << "]";
+ return strm;
+ }
+ };
+
+} // namespace
+
+// The test checks that default formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(default_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+ attrs::constant< my_class > attr3(my_class(77));
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::attr3()] = attr3;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various modes of attribute value type specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::attr< int >(data::attr1()) << expr::attr< double >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::attr< logging::numeric_types >(data::attr1()) << expr::attr< logging::numeric_types >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Check that custom types as attribute values are also supported
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::attr< my_class >(data::attr3());
+ f(rec, strm1);
+ strm2 << my_class(77);
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Check how missing attribute values are handled
+ {
+ string str1;
+ osstream strm1(str1);
+ formatter f = expr::stream
+ << expr::attr< int >(data::attr1())
+ << expr::attr< int >(data::attr4()).or_throw()
+ << expr::attr< double >(data::attr2());
+ BOOST_CHECK_THROW(f(rec, strm1), logging::runtime_error);
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream
+ << expr::attr< int >(data::attr1())
+ << expr::attr< int >(data::attr4())
+ << expr::attr< double >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_auto_newline.cpp b/src/boost/libs/log/test/run/form_auto_newline.cpp
new file mode 100644
index 000000000..0ce38e67a
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_auto_newline.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright Andrey Semashev 2019.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ */
+/*!
+ * \file form_auto_newline.cpp
+ * \author Andrey Semashev
+ * \date 23.06.2019
+ *
+ * \brief This header contains tests for the auto_newline formatter.
+ */
+
+#define BOOST_TEST_MODULE form_auto_newline
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace expr = logging::expressions;
+
+// Test appending a newline to a non-empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_non_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< char_type > formatter;
+
+ record_view rec = make_record_view();
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ formatter f = expr::stream << "Hello" << expr::auto_newline;
+ f(rec, strm_fmt);
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test appending a newline to an empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< char_type > formatter;
+
+ record_view rec = make_record_view();
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ formatter f = expr::stream << expr::auto_newline;
+ f(rec, strm_fmt);
+
+ ostream_type strm_correct;
+ strm_correct << "\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test not appending a newline to a non-empty string which already ends with a newline
+BOOST_AUTO_TEST_CASE_TEMPLATE(not_append_if_ends_with_a_newline, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< char_type > formatter;
+
+ record_view rec = make_record_view();
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ formatter f = expr::stream << "Hello\n" << expr::auto_newline;
+ f(rec, strm_fmt);
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
diff --git a/src/boost/libs/log/test/run/form_c_decor.cpp b/src/boost/libs/log/test/run/form_c_decor.cpp
new file mode 100644
index 000000000..442a93923
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_c_decor.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_c_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c c_decor and \c c_ascii_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_c_decor
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/c_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* chars() { return "\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return "\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&\\'()*+,-./0123456789:;<=>\\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+
+ static const char* special_chars() { return "\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82"; }
+ static const char* escaped_special_chars() { return "\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* chars() { return L"\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&\\'()*+,-./0123456789:;<=>\\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+
+ static const wchar_t* special_chars() { return L"\a\b\f\n\r\t\v !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82"; }
+ static const wchar_t* escaped_special_chars()
+ {
+ if (sizeof(wchar_t) == 1)
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82";
+ if (sizeof(wchar_t) == 2)
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x007f\\x0080\\x0081\\x0082";
+ if (sizeof(wchar_t) == 4)
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x0000007f\\x00000080\\x00000081\\x00000082";
+
+ return L"\\a\\b\\f\\n\\r\\t\\v !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x000000000000007f\\x0000000000000080\\x0000000000000081\\x0000000000000082";
+ }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(c_decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_c_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(c_ascii_decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_c_ascii_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_char_decor.cpp b/src/boost/libs/log/test/run/form_char_decor.cpp
new file mode 100644
index 000000000..7ef45b967
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_char_decor.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_char_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c char_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_char_decor
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/char_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@aBBBDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`123defghijklmnopqrstuvwxyz{|}~"; }
+
+ static std::vector< std::string > patterns()
+ {
+ std::vector< std::string > v;
+ v.push_back("A");
+ v.push_back("B");
+ v.push_back("C");
+ v.push_back("abc");
+ return v;
+ }
+
+ static std::vector< std::string > replacements()
+ {
+ std::vector< std::string > v;
+ v.push_back("a");
+ v.push_back("BBB");
+ v.push_back("");
+ v.push_back("123");
+ return v;
+ }
+
+ static std::vector< std::pair< std::string, std::string > > decorations()
+ {
+ typedef std::pair< std::string, std::string > element;
+ std::vector< element > v;
+ v.push_back(element("A", "a"));
+ v.push_back(element("B", "BBB"));
+ v.push_back(element("C", ""));
+ v.push_back(element("abc", "123"));
+ return v;
+ }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@aBBBDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`123defghijklmnopqrstuvwxyz{|}~"; }
+
+ static std::vector< std::wstring > patterns()
+ {
+ std::vector< std::wstring > v;
+ v.push_back(L"A");
+ v.push_back(L"B");
+ v.push_back(L"C");
+ v.push_back(L"abc");
+ return v;
+ }
+
+ static std::vector< std::wstring > replacements()
+ {
+ std::vector< std::wstring > v;
+ v.push_back(L"a");
+ v.push_back(L"BBB");
+ v.push_back(L"");
+ v.push_back(L"123");
+ return v;
+ }
+
+ static std::vector< std::pair< std::wstring, std::wstring > > decorations()
+ {
+ typedef std::pair< std::wstring, std::wstring > element;
+ std::vector< element > v;
+ v.push_back(element(L"A", L"a"));
+ v.push_back(element(L"B", L"BBB"));
+ v.push_back(element(L"C", L""));
+ v.push_back(element(L"abc", L"123"));
+ return v;
+ }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::char_decor(data::patterns(), data::replacements())[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(zip_decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::char_decor(data::decorations())[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_csv_decor.cpp b/src/boost/libs/log/test/run/form_csv_decor.cpp
new file mode 100644
index 000000000..714a91bb9
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_csv_decor.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_csv_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c csv_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_csv_decor
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/csv_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return " !\"\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L" !\"\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_csv_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_date_time.cpp b/src/boost/libs/log/test/run/form_date_time.cpp
new file mode 100644
index 000000000..28a3b2dd6
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_date_time.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_date_time.cpp
+ * \author Andrey Semashev
+ * \date 07.02.2009
+ *
+ * \brief This header contains tests for the date and time formatters.
+ */
+
+#define BOOST_TEST_MODULE form_date_time
+
+#include <memory>
+#include <locale>
+#include <string>
+#include <iomanip>
+#include <ostream>
+#include <algorithm>
+#include <boost/date_time.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/support/date_time.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+namespace keywords = logging::keywords;
+
+typedef boost::posix_time::ptime ptime;
+typedef boost::gregorian::date gdate;
+typedef ptime::time_duration_type duration;
+
+namespace {
+
+ template< typename CharT >
+ struct date_time_formats;
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct date_time_formats< char >
+ {
+ typedef logging::basic_string_literal< char > string_literal_type;
+
+ static string_literal_type default_date_format() { return logging::str_literal("%Y-%b-%d"); }
+ static string_literal_type default_time_format() { return logging::str_literal("%H:%M:%S.%f"); }
+ static string_literal_type default_date_time_format() { return logging::str_literal("%Y-%b-%d %H:%M:%S.%f"); }
+ static string_literal_type default_time_duration_format() { return logging::str_literal("%-%H:%M:%S.%f"); }
+
+ static string_literal_type date_format() { return logging::str_literal("%d/%m/%Y"); }
+ static string_literal_type time_format() { return logging::str_literal("%H.%M.%S"); }
+ static string_literal_type date_time_format() { return logging::str_literal("%d/%m/%Y %H.%M.%S"); }
+ static string_literal_type time_duration_format() { return logging::str_literal("%+%H.%M.%S.%f"); }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct date_time_formats< wchar_t >
+ {
+ typedef logging::basic_string_literal< wchar_t > string_literal_type;
+
+ static string_literal_type default_date_format() { return logging::str_literal(L"%Y-%b-%d"); }
+ static string_literal_type default_time_format() { return logging::str_literal(L"%H:%M:%S.%f"); }
+ static string_literal_type default_date_time_format() { return logging::str_literal(L"%Y-%b-%d %H:%M:%S.%f"); }
+ static string_literal_type default_time_duration_format() { return logging::str_literal(L"%-%H:%M:%S.%f"); }
+
+ static string_literal_type date_format() { return logging::str_literal(L"%d/%m/%Y"); }
+ static string_literal_type time_format() { return logging::str_literal(L"%H.%M.%S"); }
+ static string_literal_type date_time_format() { return logging::str_literal(L"%d/%m/%Y %H.%M.%S"); }
+ static string_literal_type time_duration_format() { return logging::str_literal(L"%+%H.%M.%S.%f"); }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace
+
+// The test checks that date_time formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(date_time, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+ typedef date_time_formats< CharT > formats;
+ typedef boost::date_time::time_facet< ptime, CharT > facet;
+
+ ptime t1(gdate(2009, 2, 7), ptime::time_duration_type(14, 40, 15));
+ attrs::constant< ptime > attr1(t1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various formats specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< ptime >(data::attr1(), formats::default_date_time_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::default_date_time_format().c_str())));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< ptime >(data::attr1(), formats::date_time_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::date_time_format().c_str())));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+// The test checks that date formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(date, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+ typedef date_time_formats< CharT > formats;
+ typedef boost::date_time::date_facet< gdate, CharT > facet;
+
+ gdate d1(2009, 2, 7);
+ attrs::constant< gdate > attr1(d1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various formats specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< gdate >(data::attr1(), formats::default_date_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::default_date_format().c_str())));
+ strm2 << d1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< gdate >(data::attr1(), formats::date_format().c_str());
+ f(rec, strm1);
+ strm2.imbue(std::locale(strm2.getloc(), new facet(formats::date_format().c_str())));
+ strm2 << d1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+// The test checks that time_duration formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(time_duration, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+ typedef date_time_formats< CharT > formats;
+ typedef boost::date_time::time_facet< ptime, CharT > facet;
+
+ duration t1(14, 40, 15);
+ attrs::constant< duration > attr1(t1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various formats specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< duration >(data::attr1(), formats::default_time_duration_format().c_str());
+ f(rec, strm1);
+ facet* fac = new facet();
+ fac->time_duration_format(formats::default_time_duration_format().c_str());
+ strm2.imbue(std::locale(strm2.getloc(), fac));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_date_time< duration >(data::attr1(), formats::time_duration_format().c_str());
+ f(rec, strm1);
+ facet* fac = new facet();
+ fac->time_duration_format(formats::time_duration_format().c_str());
+ strm2.imbue(std::locale(strm2.getloc(), fac));
+ strm2 << t1;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_format.cpp b/src/boost/libs/log/test/run/form_format.cpp
new file mode 100644
index 000000000..af2496907
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_format.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_format.cpp
+ * \author Andrey Semashev
+ * \date 07.02.2009
+ *
+ * \brief This header contains tests for the Boost.Format-style formatting.
+ */
+
+#define BOOST_TEST_MODULE form_format
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+ template< typename >
+ struct format_test_data;
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct format_test_data< char > :
+ public test_data< char >
+ {
+ static const char* format1() { return "%1%, %2%"; }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct format_test_data< wchar_t > :
+ public test_data< wchar_t >
+ {
+ static const wchar_t* format1() { return L"%1%, %2%"; }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace
+
+// The test checks that Boost.Format formatting works
+BOOST_AUTO_TEST_CASE_TEMPLATE(formatting, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef format_test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::format(data::format1()) % expr::attr< int >(data::attr1()) % expr::attr< double >(data::attr2());
+ f(rec, strm1);
+ strm2 << 10 << ", " << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_if.cpp b/src/boost/libs/log/test/run/form_if.cpp
new file mode 100644
index 000000000..88f44c497
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_if.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_if.cpp
+ * \author Andrey Semashev
+ * \date 05.02.2009
+ *
+ * \brief This header contains tests for the \c if_ formatter.
+ */
+
+#define BOOST_TEST_MODULE form_if
+
+#include <string>
+#include <ostream>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+// The test checks that conditional formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(conditional_formatting, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ // Check for various modes of attribute value type specification
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr1()))
+ [
+ expr::stream << expr::attr< int >(data::attr1())
+ ];
+ f(rec, strm1);
+ strm2 << 10;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1;
+ osstream strm1(str1);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr2()))
+ [
+ expr::stream << expr::attr< int >(data::attr2())
+ ];
+ f(rec, strm1);
+ BOOST_CHECK(equal_strings(strm1.str(), string()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr1()))
+ [
+ expr::stream << expr::attr< int >(data::attr1())
+ ]
+ .else_
+ [
+ expr::stream << expr::attr< double >(data::attr2())
+ ];
+ f(rec, strm1);
+ strm2 << 10;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream <<
+ expr::if_(expr::has_attr< int >(data::attr2()))
+ [
+ expr::stream << expr::attr< int >(data::attr1())
+ ]
+ .else_
+ [
+ expr::stream << expr::attr< double >(data::attr2())
+ ];
+ f(rec, strm1);
+ strm2 << 5.5;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_max_size_decor.cpp b/src/boost/libs/log/test/run/form_max_size_decor.cpp
new file mode 100644
index 000000000..772f23744
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_max_size_decor.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file form_max_size_decor.cpp
+ * \author Andrey Semashev
+ * \date 09.08.2016
+ *
+ * \brief This header contains tests for the \c max_size_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_max_size_decor
+
+#include <string>
+#include <locale>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/max_size_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/phoenix/operator.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+#define BOOST_UTF8_DECL
+#define BOOST_UTF8_BEGIN_NAMESPACE namespace {
+#define BOOST_UTF8_END_NAMESPACE }
+
+#include <boost/detail/utf8_codecvt_facet.hpp>
+#include <boost/detail/utf8_codecvt_facet.ipp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* overflow_marker() { return ">>>"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* overflow_marker() { return L">>>"; }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Test output truncation
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor< CharT >(10)[ expr::stream << expr::attr< string >(data::attr1()) << data::some_test_string() << 1234 << data::abc() ];
+ f(rec, strm1);
+ strm2 << string(data::printable_chars(), 10);
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test output truncation with a marker
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) << data::some_test_string() << 1234 << data::abc() ];
+ f(rec, strm1);
+ strm2 << string(data::printable_chars(), 7) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test nested decorators, when the outer decorator enforces the limit that includes the inner decorator
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor(35, data::overflow_marker())[
+ expr::stream << data::abcdefg0123456789() << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ] << data::abcdefg0123456789()
+ ];
+ f(rec, strm1);
+ strm2 << data::abcdefg0123456789() << string(data::printable_chars(), 7) << data::overflow_marker() << string(data::abcdefg0123456789(), 5) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test nested decorators, when the outer decorator enforces the limit that also limits the inner decorator
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::max_size_decor(25, data::overflow_marker())[
+ expr::stream << data::abcdefg0123456789() << expr::max_size_decor(10, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ] << data::abcdefg0123456789()
+ ];
+ f(rec, strm1);
+ strm2 << data::abcdefg0123456789() << string(data::printable_chars(), 5) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+namespace {
+
+const char narrow_chars[] = "\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(character_boundary_maintenance)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< char > string;
+ typedef logging::basic_formatting_ostream< char > osstream;
+ typedef logging::basic_formatter< char > formatter;
+ typedef test_strings< char > data;
+
+ std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
+
+ attrs::constant< string > attr1(narrow_chars);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ // Test that output truncation does not happen in the middle of a multibyte character
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ strm1.imbue(loc);
+ strm2.imbue(loc);
+ formatter f = expr::stream << expr::max_size_decor< char >(7)[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << string(narrow_chars, 6);
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ // Test output truncation with a marker, when the marker length would have caused truncation in the middle of a multibyte character
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ strm1.imbue(loc);
+ strm2.imbue(loc);
+ formatter f = expr::stream << expr::max_size_decor(6, data::overflow_marker())[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << string(narrow_chars, 2) << data::overflow_marker();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_message.cpp b/src/boost/libs/log/test/run/form_message.cpp
new file mode 100644
index 000000000..4fd946bf1
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_message.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_message.cpp
+ * \author Andrey Semashev
+ * \date 01.02.2009
+ *
+ * \brief This header contains tests for the \c message formatter.
+ */
+
+#define BOOST_TEST_MODULE form_message
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+ template< typename CharT >
+ struct message_test_data;
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct message_test_data< char > :
+ public test_data< char >
+ {
+ static expr::smessage_type message() { return expr::smessage; }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct message_test_data< wchar_t > :
+ public test_data< wchar_t >
+ {
+ static expr::wmessage_type message() { return expr::wmessage; }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+} // namespace
+
+// The test checks that message formatting work
+BOOST_AUTO_TEST_CASE_TEMPLATE(message_formatting, CharT, char_types)
+{
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef message_test_data< CharT > data;
+
+ attrs::constant< int > attr1(10);
+ attrs::constant< double > attr2(5.5);
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+ set1[data::attr2()] = attr2;
+ set1[data::message().get_name()] = attrs::constant< string >(data::some_test_string());
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << data::message();
+ f(rec, strm1);
+ strm2 << data::some_test_string();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_named_scope.cpp b/src/boost/libs/log/test/run/form_named_scope.cpp
new file mode 100644
index 000000000..3b61e36e5
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_named_scope.cpp
@@ -0,0 +1,537 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_named_scope.cpp
+ * \author Andrey Semashev
+ * \date 07.02.2009
+ *
+ * \brief This header contains tests for the \c named_scope formatter.
+ */
+
+#define BOOST_TEST_MODULE form_named_scope
+
+#include <string>
+#include <boost/config.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/string_literal.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+namespace keywords = logging::keywords;
+
+namespace {
+
+ template< typename CharT >
+ struct named_scope_test_data;
+
+ struct named_scope_test_data_base
+ {
+ static logging::string_literal scope1() { return logging::str_literal("scope1"); }
+ static logging::string_literal scope2() { return logging::str_literal("scope2"); }
+
+ static logging::string_literal file() { return logging::str_literal(__FILE__); }
+ static logging::string_literal posix_file() { return logging::str_literal("/home/user/posix_file.cpp"); }
+ static logging::string_literal windows_file1() { return logging::str_literal("C:\\user\\windows_file1.cpp"); }
+ static logging::string_literal windows_file2() { return logging::str_literal("C:/user/windows_file2.cpp"); }
+ };
+
+#ifdef BOOST_LOG_USE_CHAR
+ template< >
+ struct named_scope_test_data< char > :
+ public test_data< char >,
+ public named_scope_test_data_base
+ {
+ static logging::string_literal default_format() { return logging::str_literal("%n"); }
+ static logging::string_literal full_format() { return logging::str_literal("%n (%f:%l)"); }
+ static logging::string_literal short_filename_format() { return logging::str_literal("%n (%F:%l)"); }
+ static logging::string_literal scope_function_name_format() { return logging::str_literal("%c"); }
+ static logging::string_literal function_name_format() { return logging::str_literal("%C"); }
+ static logging::string_literal delimiter1() { return logging::str_literal("|"); }
+ static logging::string_literal incomplete_marker() { return logging::str_literal("<<and more>>"); }
+ static logging::string_literal empty_marker() { return logging::str_literal("[empty]"); }
+ };
+#endif // BOOST_LOG_USE_CHAR
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ template< >
+ struct named_scope_test_data< wchar_t > :
+ public test_data< wchar_t >,
+ public named_scope_test_data_base
+ {
+ static logging::wstring_literal default_format() { return logging::str_literal(L"%n"); }
+ static logging::wstring_literal full_format() { return logging::str_literal(L"%n (%f:%l)"); }
+ static logging::wstring_literal short_filename_format() { return logging::str_literal(L"%n (%F:%l)"); }
+ static logging::wstring_literal scope_function_name_format() { return logging::str_literal(L"%c"); }
+ static logging::wstring_literal function_name_format() { return logging::str_literal(L"%C"); }
+ static logging::wstring_literal delimiter1() { return logging::str_literal(L"|"); }
+ static logging::wstring_literal incomplete_marker() { return logging::str_literal(L"<<and more>>"); }
+ static logging::wstring_literal empty_marker() { return logging::str_literal(L"[empty]"); }
+ };
+#endif // BOOST_LOG_USE_WCHAR_T
+
+ template< typename CharT >
+ inline bool check_formatting(logging::basic_string_literal< CharT > const& format, logging::record_view const& rec, std::basic_string< CharT > const& expected)
+ {
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef named_scope_test_data< CharT > data;
+
+ string str;
+ osstream strm(str);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(), keywords::format = format.c_str());
+ f(rec, strm);
+ return equal_strings(strm.str(), expected);
+ }
+
+} // namespace
+
+// The test checks that named scopes stack formatting works
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::file(), line1);
+ const unsigned int line2 = __LINE__;
+ sentry scope2(data::scope2(), data::file(), line2);
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ // Default format
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << "->" << data::scope2();
+ BOOST_CHECK(check_formatting(data::default_format(), rec, strm.str()));
+ }
+ // Full format
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << " (" << data::file() << ":" << line1 << ")->"
+ << data::scope2() << " (" << data::file() << ":" << line2 << ")";
+ BOOST_CHECK(check_formatting(data::full_format(), rec, strm.str()));
+ }
+ // Different delimiter
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str());
+ f(rec, strm1);
+ strm2 << data::scope1() << "|" << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Different direction
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "<-" << data::scope1();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str(),
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "|" << data::scope1();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ // Limiting the number of scopes
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::depth = 1);
+ f(rec, strm1);
+ strm2 << "..." << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::depth = 1,
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "...";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str(),
+ keywords::depth = 1);
+ f(rec, strm1);
+ strm2 << "..." << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::delimiter = data::delimiter1().c_str(),
+ keywords::depth = 1,
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "...";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::incomplete_marker = data::incomplete_marker().c_str(),
+ keywords::depth = 1);
+ f(rec, strm1);
+ strm2 << "<<and more>>" << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::incomplete_marker = data::incomplete_marker().c_str(),
+ keywords::depth = 1,
+ keywords::iteration = expr::reverse);
+ f(rec, strm1);
+ strm2 << data::scope2() << "<<and more>>";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+// The test checks that empty named scopes stack formatting works
+BOOST_AUTO_TEST_CASE_TEMPLATE(empty_scopes_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ formatter f = expr::stream << expr::format_named_scope(data::attr1(),
+ keywords::format = data::default_format().c_str(),
+ keywords::empty_marker = data::empty_marker().c_str());
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "[empty]";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::file(), line1);
+ const unsigned int line2 = __LINE__;
+ sentry scope2(data::scope2(), data::file(), line2);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << data::scope1() << "->" << data::scope2();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_filename_formatting_posix, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::posix_file(), line1);
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ // File names without the full path
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << " (posix_file.cpp:" << line1 << ")";
+ BOOST_CHECK(check_formatting(data::short_filename_format(), rec, strm.str()));
+ }
+}
+
+#if defined(BOOST_WINDOWS)
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_filename_formatting_windows, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+ sentry scope1(data::scope1(), data::windows_file1(), line1);
+ const unsigned int line2 = __LINE__;
+ sentry scope2(data::scope2(), data::windows_file2(), line2);
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ // File names without the full path
+ {
+ string str;
+ osstream strm(str);
+ strm << data::scope1() << " (windows_file1.cpp:" << line1 << ")->"
+ << data::scope2() << " (windows_file2.cpp:" << line2 << ")";
+ BOOST_CHECK(check_formatting(data::short_filename_format(), rec, strm.str()));
+ }
+}
+
+#endif // defined(BOOST_WINDOWS)
+
+namespace {
+
+struct named_scope_test_case
+{
+ logging::string_literal scope_name;
+ const char* function_name;
+ const char* function_name_no_scope;
+};
+
+const named_scope_test_case named_scope_test_cases[] =
+{
+ // Generic signatures
+ { logging::str_literal("int main(int, char *[])"), "main", "main" },
+ { logging::str_literal("namespace_name::type foo()"), "foo", "foo" },
+ { logging::str_literal("namespace_name::type& foo::bar(int[], std::string const&)"), "foo::bar", "bar" },
+ { logging::str_literal("void* namespc::foo<char>::bar()"), "namespc::foo<char>::bar", "bar" },
+ { logging::str_literal("void* namespc::foo<char>::bar<int>(int) const"), "namespc::foo<char>::bar<int>", "bar<int>" },
+
+ // MSVC-specific
+ { logging::str_literal("int __cdecl main(int, char *[])"), "main", "main" },
+ { logging::str_literal("struct namespc::strooct __cdecl foo3(int [])"), "foo3", "foo3" },
+ { logging::str_literal("void (__cdecl *__cdecl foo4(void))(void)"), "foo4", "foo4" }, // function returning pointer to function
+ { logging::str_literal("void (__cdecl *__cdecl foo5(void (__cdecl *)(void)))(void)"), "foo5", "foo5" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member1(void (__cdecl *)(void)))(void)"), "namespc::my_class<int>::member1", "member1" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member2<int>(int))(void)"), "namespc::my_class<int>::member2<int>", "member2<int>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member2<void(__cdecl *)(void)>(void (__cdecl *)(void)))(void)"), "namespc::my_class<int>::member2<void(__cdecl *)(void)>", "member2<void(__cdecl *)(void)>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<int>::member3<void __cdecl foo1(void)>(void))(void)"), "namespc::my_class<int>::member3<void __cdecl foo1(void)>", "member3<void __cdecl foo1(void)>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member1(void (__cdecl *)(void)))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member1", "member1" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member2<int>(int))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member2<int>", "member2<int>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member2<void(__cdecl *)(void)>(void (__cdecl *)(void)))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member2<void(__cdecl *)(void)>", "member2<void(__cdecl *)(void)>" },
+ { logging::str_literal("void (__cdecl *__cdecl namespc::my_class<void (__cdecl*)(void)>::member3<void __cdecl foo1(void)>(void))(void)"), "namespc::my_class<void (__cdecl*)(void)>::member3<void __cdecl foo1(void)>", "member3<void __cdecl foo1(void)>" },
+ { logging::str_literal("void (__cdecl namespc::my_class2::* __cdecl namespc::foo6(void (__cdecl *)(void)))(void)"), "namespc::foo6", "foo6" },
+ { logging::str_literal("struct namespc::my_class<void __cdecl(int)> __cdecl namespc::foo7(void)"), "namespc::foo7", "foo7" },
+ { logging::str_literal("void (__cdecl namespc::my_class2::* const (&__cdecl namespc::foo8(void (__cdecl *)(void)))[2])(void)"), "namespc::foo8", "foo8" },
+ { logging::str_literal("__cdecl namespc::my_class2::my_class2(void)"), "namespc::my_class2::my_class2", "my_class2" },
+ { logging::str_literal("__cdecl namespc::my_class2::~my_class2(void)"), "namespc::my_class2::~my_class2", "~my_class2" },
+ { logging::str_literal("void __cdecl namespc::my_class2::operator =(const struct namespc::my_class2 &)"), "namespc::my_class2::operator =", "operator =" },
+ { logging::str_literal("void __cdecl namespc::my_class2::operator *(void) const"), "namespc::my_class2::operator *", "operator *" },
+ { logging::str_literal("void __cdecl namespc::my_class2::operator ()(void)"), "namespc::my_class2::operator ()", "operator ()" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator <(int) const"), "namespc::my_class2::operator <", "operator <" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator >(int) const"), "namespc::my_class2::operator >", "operator >" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator <=(int) const"), "namespc::my_class2::operator <=", "operator <=" },
+ { logging::str_literal("bool __cdecl namespc::my_class2::operator >=(int) const"), "namespc::my_class2::operator >=", "operator >=" },
+ { logging::str_literal("__cdecl namespc::my_class2::operator bool(void) const"), "namespc::my_class2::operator bool", "operator bool" },
+ // MSVC generates incorrect strings in case of conversion operators to function types. We don't support these.
+// { logging::str_literal("__cdecl namespc::my_class2::operator char (__cdecl *)(double)(__cdecl *(void) const)(double)"), "namespc::my_class2::operator char (__cdecl *)(double)", "operator char (__cdecl *)(double)" },
+// { logging::str_literal("__cdecl namespc::my_class2::operator char (__cdecl namespc::my_class2::* )(double)(__cdecl namespc::my_class2::* (void) const)(double)"), "namespc::my_class2::operator char (__cdecl namespc::my_class2::* )(double)", "operator char (__cdecl namespc::my_class2::* )(double)" },
+ { logging::str_literal("class std::basic_ostream<char,struct std::char_traits<char> > &__cdecl namespc::operator <<<char,struct std::char_traits<char>>(class std::basic_ostream<char,struct std::char_traits<char> > &,const struct namespc::my_class2 &)"), "namespc::operator <<<char,struct std::char_traits<char>>", "operator <<<char,struct std::char_traits<char>>" },
+ { logging::str_literal("class std::basic_istream<char,struct std::char_traits<char> > &__cdecl namespc::operator >><char,struct std::char_traits<char>>(class std::basic_istream<char,struct std::char_traits<char> > &,struct namespc::my_class2 &)"), "namespc::operator >><char,struct std::char_traits<char>>", "operator >><char,struct std::char_traits<char>>" },
+
+ // GCC-specific
+ { logging::str_literal("namespc::strooct foo3(int*)"), "foo3", "foo3" },
+ { logging::str_literal("void (* foo4())()"), "foo4", "foo4" }, // function returning pointer to function
+ { logging::str_literal("void (* foo5(pfun2_t))()"), "foo5", "foo5" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member1(pfun2_t))() [with T = int; pfun1_t = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member1", "member1" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = int; T = int; pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = void (*)(); T = int; pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member3())() [with void (* Fun)() = foo1; T = int; pfun2_t = void (*)()]"), "namespc::my_class<T>::member3", "member3" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member1(pfun2_t))() [with T = void (*)(); pfun1_t = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member1", "member1" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = int; T = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member2(U))() [with U = void (*)(); T = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member2", "member2" },
+ { logging::str_literal("static void (* namespc::my_class<T>::member3())() [with void (* Fun)() = foo1; T = void (*)(); pfun2_t = void (*)()]"), "namespc::my_class<T>::member3", "member3" },
+ { logging::str_literal("void (namespc::my_class2::* namespc::foo6(pfun2_t))()"), "namespc::foo6", "foo6" },
+ { logging::str_literal("namespc::my_class<void(int)> namespc::foo7()"), "namespc::foo7", "foo7" },
+ { logging::str_literal("void (namespc::my_class2::* const (& namespc::foo8(pfun2_t))[2])()"), "namespc::foo8", "foo8" },
+ { logging::str_literal("namespc::my_class2::my_class2()"), "namespc::my_class2::my_class2", "my_class2" }, // constructor
+ { logging::str_literal("namespc::my_class2::~my_class2()"), "namespc::my_class2::~my_class2", "~my_class2" }, // destructor
+ { logging::str_literal("void namespc::my_class2::operator=(const namespc::my_class2&)"), "namespc::my_class2::operator=", "operator=" },
+ { logging::str_literal("void namespc::my_class2::operator*() const"), "namespc::my_class2::operator*", "operator*" },
+ { logging::str_literal("void namespc::my_class2::operator()()"), "namespc::my_class2::operator()", "operator()" },
+ { logging::str_literal("bool namespc::my_class2::operator<(int) const"), "namespc::my_class2::operator<", "operator<" },
+ { logging::str_literal("bool namespc::my_class2::operator>(int) const"), "namespc::my_class2::operator>", "operator>" },
+ { logging::str_literal("bool namespc::my_class2::operator<=(int) const"), "namespc::my_class2::operator<=", "operator<=" },
+ { logging::str_literal("bool namespc::my_class2::operator>=(int) const"), "namespc::my_class2::operator>=", "operator>=" },
+ { logging::str_literal("namespc::my_class2::operator bool() const"), "namespc::my_class2::operator bool", "operator bool" },
+ { logging::str_literal("namespc::my_class2::operator pfun1_t() const"), "namespc::my_class2::operator pfun1_t", "operator pfun1_t" },
+ { logging::str_literal("std::basic_ostream<_CharT, _Traits>& namespc::operator<<(std::basic_ostream<_CharT, _Traits>&, const namespc::my_class2&) [with CharT = char; TraitsT = std::char_traits<char>]"), "namespc::operator<<", "operator<<" },
+ { logging::str_literal("std::basic_istream<_CharT, _Traits>& namespc::operator>>(std::basic_istream<_CharT, _Traits>&, namespc::my_class2&) [with CharT = char; TraitsT = std::char_traits<char>]"), "namespc::operator>>", "operator>>" },
+
+ // BOOST_CURRENT_FUNCTION fallback value
+ { logging::str_literal("(unknown)"), "(unknown)", "(unknown)" }
+};
+
+} // namespace
+
+// Function name formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_scope_function_name_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ for (unsigned int i = 0; i < sizeof(named_scope_test_cases) / sizeof(*named_scope_test_cases); ++i)
+ {
+ sentry scope1(named_scope_test_cases[i].scope_name, data::file(), line1, attrs::named_scope_entry::function);
+ string str;
+ osstream strm(str);
+ strm << named_scope_test_cases[i].function_name;
+ BOOST_CHECK_MESSAGE(check_formatting(data::scope_function_name_format(), rec, strm.str()), "Scope name: " << named_scope_test_cases[i].scope_name);
+ }
+}
+
+// Function name without scope formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(scopes_function_name_formatting, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+ typedef named_scope::sentry sentry;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ // First scope
+ const unsigned int line1 = __LINE__;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ for (unsigned int i = 0; i < sizeof(named_scope_test_cases) / sizeof(*named_scope_test_cases); ++i)
+ {
+ sentry scope1(named_scope_test_cases[i].scope_name, data::file(), line1, attrs::named_scope_entry::function);
+ string str;
+ osstream strm(str);
+ strm << named_scope_test_cases[i].function_name_no_scope;
+ BOOST_CHECK_MESSAGE(check_formatting(data::function_name_format(), rec, strm.str()), "Scope name: " << named_scope_test_cases[i].scope_name);
+ }
+}
+
+// The test checks that function name formatters do not affect scopes denoted with BOOST_LOG_NAMED_SCOPE
+BOOST_AUTO_TEST_CASE_TEMPLATE(function_name_does_not_affect_non_function_scopes, CharT, char_types)
+{
+ typedef attrs::named_scope named_scope;
+
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::record_view record_view;
+ typedef named_scope_test_data< CharT > data;
+
+ named_scope attr;
+
+ attr_set set1;
+ set1[data::attr1()] = attr;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ BOOST_LOG_NAMED_SCOPE("void foo()");
+ string str;
+ osstream strm(str);
+ strm << "void foo()";
+ BOOST_CHECK(check_formatting(data::scope_function_name_format(), rec, strm.str()));
+ BOOST_CHECK(check_formatting(data::function_name_format(), rec, strm.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_to_log_manip.cpp b/src/boost/libs/log/test/run/form_to_log_manip.cpp
new file mode 100644
index 000000000..a7f83d369
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_to_log_manip.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_to_log_manip.cpp
+ * \author Andrey Semashev
+ * \date 05.07.2015
+ *
+ * \brief This header contains tests for support for the \c to_log_manip customization point.
+ */
+
+#define BOOST_TEST_MODULE form_to_log_manip
+
+#include <string>
+#include <ostream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/to_log.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+struct my_class
+{
+ int m_Data;
+
+ explicit my_class(int data) : m_Data(data) {}
+};
+
+} // namespace
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_my_class, "MyClass", my_class)
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_string, "String", std::string)
+
+namespace {
+
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >&
+operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, logging::to_log_manip< my_class, tag::a_my_class > const& obj)
+{
+ strm << "a_my_class: [data: " << obj.get().m_Data << "]";
+ return strm;
+}
+
+} // namespace
+
+namespace std {
+
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >&
+operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, logging::to_log_manip< std::string, tag::a_string > const& obj)
+{
+ strm << "a_string: [" << obj.get() << "]";
+ return strm;
+}
+
+} // namespace std
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overrides, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+
+ attrs::constant< my_class > attr1(my_class(77));
+ attrs::constant< std::string > attr2("Hello");
+
+ attr_set set1;
+ set1[a_my_class.get_name()] = attr1;
+ set1[a_string.get_name()] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ // Check that out custom operators are called
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << a_my_class << ", " << a_string;
+ f(rec, strm1);
+ strm2 << "a_my_class: [data: " << 77 << "], a_string: [" << "Hello" << "]";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/form_xml_decor.cpp b/src/boost/libs/log/test/run/form_xml_decor.cpp
new file mode 100644
index 000000000..416c9c4e4
--- /dev/null
+++ b/src/boost/libs/log/test/run/form_xml_decor.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file form_xml_decor.cpp
+ * \author Andrey Semashev
+ * \date 26.09.2015
+ *
+ * \brief This header contains tests for the \c xml_decor formatter.
+ */
+
+#define BOOST_TEST_MODULE form_xml_decor
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/utility/type_dispatch/standard_types.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/attr.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include <boost/log/expressions/formatters/xml_decorator.hpp>
+#include <boost/log/expressions/formatters/stream.hpp>
+#include <boost/log/core/record.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+namespace expr = logging::expressions;
+
+namespace {
+
+template< typename >
+struct test_strings;
+
+#ifdef BOOST_LOG_USE_CHAR
+template< >
+struct test_strings< char > : public test_data< char >
+{
+ static const char* printable_chars() { return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const char* escaped_chars() { return " !&quot;#$%&amp;&apos;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+template< >
+struct test_strings< wchar_t > : public test_data< wchar_t >
+{
+ static const wchar_t* printable_chars() { return L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+ static const wchar_t* escaped_chars() { return L" !&quot;#$%&amp;&apos;()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; }
+};
+#endif
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(decorator_formatting, CharT, char_types)
+{
+ typedef logging::record_view record_view;
+ typedef logging::attribute_set attr_set;
+ typedef std::basic_string< CharT > string;
+ typedef logging::basic_formatting_ostream< CharT > osstream;
+ typedef logging::basic_formatter< CharT > formatter;
+ typedef test_strings< CharT > data;
+
+ attrs::constant< string > attr1(data::printable_chars());
+
+ attr_set set1;
+ set1[data::attr1()] = attr1;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ formatter f = expr::stream << expr::make_xml_decor< CharT >()[ expr::stream << expr::attr< string >(data::attr1()) ];
+ f(rec, strm1);
+ strm2 << data::escaped_chars();
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+}
diff --git a/src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp b/src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp
new file mode 100644
index 000000000..e26f53a88
--- /dev/null
+++ b/src/boost/libs/log/test/run/sink_text_ipc_mq_backend.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright Lingxi Li 2015.
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file sink_text_ipc_mq_backend.cpp
+ * \author Lingxi Li
+ * \author Andrey Semashev
+ * \date 19.10.2015
+ *
+ * \brief The test verifies that \c text_ipc_message_queue_backend works as expected.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_IPC)
+
+#define BOOST_TEST_MODULE sink_text_ipc_mq_backend
+
+#include <boost/log/sinks/text_ipc_message_queue_backend.hpp>
+#include <boost/log/utility/ipc/reliable_message_queue.hpp>
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/log/utility/open_mode.hpp>
+#include <boost/log/core/record_view.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include "make_record.hpp"
+#include "char_definitions.hpp"
+
+const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_text_ipc_mq_backend");
+const unsigned int capacity = 512;
+const unsigned int block_size = 1024;
+const char message[] = "Hello, world!";
+
+// The test checks that `text_ipc_message_queue_backend` works.
+BOOST_AUTO_TEST_CASE(text_ipc_message_queue_backend)
+{
+ typedef boost::log::ipc::reliable_message_queue queue_t;
+ typedef boost::log::sinks::text_ipc_message_queue_backend< queue_t > backend_t;
+
+ // Do a remove in case if a previous test failed
+ queue_t::remove(ipc_queue_name);
+
+ backend_t backend;
+ BOOST_CHECK(!backend.is_open());
+
+ backend.message_queue().create(ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(backend.is_open());
+
+ queue_t queue(boost::log::open_mode::open_only, ipc_queue_name);
+ boost::log::record_view rec = make_record_view();
+ backend.consume(rec, message);
+
+ std::string msg;
+ BOOST_CHECK(queue.try_receive(msg));
+ BOOST_CHECK(equal_strings(msg, message));
+}
+
+#else // !defined(BOOST_LOG_WITHOUT_IPC)
+
+int main()
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_IPC)
diff --git a/src/boost/libs/log/test/run/src_record_ostream.cpp b/src/boost/libs/log/test/run/src_record_ostream.cpp
new file mode 100644
index 000000000..dd321f922
--- /dev/null
+++ b/src/boost/libs/log/test/run/src_record_ostream.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file src_record_ostream.cpp
+ * \author Andrey Semashev
+ * \date 23.08.2015
+ *
+ * \brief This header contains tests for the log record formatting output stream.
+ */
+
+#define BOOST_TEST_MODULE src_record_ostream
+
+#include <locale>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+#include <boost/config.hpp>
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+#include <string_view>
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/string_view.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/sources/record_ostream.hpp>
+#include <boost/log/expressions/message.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include "char_definitions.hpp"
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace expr = boost::log::expressions;
+
+namespace {
+
+struct unreferencable_data
+{
+ unsigned int m : 2;
+ unsigned int n : 6;
+
+ enum my_enum
+ {
+ one = 1,
+ two = 2
+ };
+
+ // The following static constants don't have definitions, so they can only be used in constant expressions.
+ // Trying to bind a reference to these members will result in linking errors.
+ static const int x = 7;
+ static const my_enum y = one;
+
+ unreferencable_data()
+ {
+ m = 1;
+ n = 5;
+ }
+};
+
+template< typename CharT >
+struct test_impl
+{
+ typedef CharT char_type;
+ typedef test_data< char_type > strings;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ template< typename StringT >
+ static void width_formatting()
+ {
+ // Check that widening works
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ // Check that the string is not truncated
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+ }
+
+ template< typename StringT >
+ static void fill_formatting()
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ template< typename StringT >
+ static void alignment()
+ {
+ // Left alignment
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ // Right alignment
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+ }
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template< typename StringT >
+ static void rvalue_stream()
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type(rec) << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC() << std::flush;
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+#endif
+
+ static void output_unreferencable_data()
+ {
+ unreferencable_data data;
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+ strm_fmt << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type(rec) << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y << std::flush;
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+#endif
+ }
+
+ static void formatting_params_restoring()
+ {
+ record_ostream_type strm_fmt;
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ strm_fmt.attach_record(rec);
+ strm_fmt << std::setw(8) << std::setfill(static_cast< char_type >('x')) << std::hex << 15;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+ strm_fmt.detach_from_record();
+
+ ostream_type strm_correct;
+ strm_correct << std::setw(8) << std::setfill(static_cast< char_type >('x')) << std::hex << 15;
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+
+ // Check that the formatting flags are reset for the next record
+ {
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ strm_fmt.attach_record(rec);
+ strm_fmt << 15;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+ strm_fmt.detach_from_record();
+
+ ostream_type strm_correct;
+ strm_correct << 15;
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+ }
+ }
+};
+
+} // namespace
+
+// Test support for width formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for filler character setup
+BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for text alignment
+BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE alignment< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >();
+#endif
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+// Test support for rvalue stream objects
+BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >();
+#endif
+}
+#endif
+
+// Test output of data to which a reference cannot be bound
+BOOST_AUTO_TEST_CASE_TEMPLATE(output_unreferencable_data, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::output_unreferencable_data();
+}
+
+// Test that formatting settings are reset for new log records
+BOOST_AUTO_TEST_CASE_TEMPLATE(formatting_params_restoring, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::formatting_params_restoring();
+}
+
+namespace my_namespace {
+
+class A {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*)
+{
+ strm << "B*";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*)
+{
+ strm << "const B*";
+ return strm;
+}
+
+class C {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace
+
+// Test operator forwarding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+
+ const my_namespace::A a = my_namespace::A(); // const lvalue
+ my_namespace::B b; // lvalue
+ strm_fmt << a << b << my_namespace::C(); // rvalue
+ strm_fmt << my_namespace::eee;
+ strm_fmt << &b << (my_namespace::B const*)&b;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b;
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+}
+
+namespace my_namespace2 {
+
+class A {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+class C {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+class D {};
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm,
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ D&&
+#else
+ D const&
+#endif
+ )
+{
+ strm << "D";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT >
+inline logging::basic_record_ostream< CharT >& operator<< (logging::basic_record_ostream< CharT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace2
+
+// Test operator overriding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overriding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+
+ const my_namespace2::A a = my_namespace2::A(); // const lvalue
+ my_namespace2::B b; // lvalue
+ strm_fmt << a << b << my_namespace2::C() << my_namespace2::D(); // rvalue
+ strm_fmt << my_namespace2::eee;
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << "ABCDE";
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+}
+
+// Test that operator<< returns a record_ostream
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_return_type, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_record_ostream< char_type > record_ostream_type;
+
+ logging::record rec = make_record();
+ BOOST_REQUIRE(!!rec);
+ record_ostream_type strm_fmt(rec);
+
+ // The test here verifies that the result of << "Hello" is a record_ostream, not std::ostream or logging::formatting_ostream.
+ // The subsequent << A() will only compile if the stream is record_ostream.
+ strm_fmt << "Hello " << my_namespace2::A();
+ strm_fmt.flush();
+ string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec);
+
+ ostream_type strm_correct;
+ strm_correct << "Hello A";
+
+ BOOST_CHECK(equal_strings(rec_message, strm_correct.str()));
+}
diff --git a/src/boost/libs/log/test/run/util_dynamic_type_disp.cpp b/src/boost/libs/log/test/run/util_dynamic_type_disp.cpp
new file mode 100644
index 000000000..d1d6d9f49
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_dynamic_type_disp.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_dynamic_type_disp.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the dynamic type dispatcher.
+ */
+
+#define BOOST_TEST_MODULE util_dynamic_type_disp
+
+#include <string>
+#include <boost/bind/bind.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools/floating_point_comparison.hpp>
+#include <boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp>
+
+namespace logging = boost::log;
+
+namespace {
+
+ // A simple attribute value
+ template< typename T >
+ struct my_value
+ {
+ T m_Value;
+
+ explicit my_value(T const& value) : m_Value(value) {}
+
+ // The function passes the contained type into the dispatcher
+ bool dispatch(logging::type_dispatcher& dispatcher)
+ {
+ logging::type_dispatcher::callback< T > callback = dispatcher.get_callback< T >();
+ if (callback)
+ {
+ callback(m_Value);
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ struct my_visitor
+ {
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_visitor() : m_Expected(none_expected), m_Int(0), m_Double(0.0) {}
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void on_int(int const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void on_double(double const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void on_string(std::string const& value)
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test checks that general functionality works
+BOOST_AUTO_TEST_CASE(type_dispatch)
+{
+ my_visitor vis;
+ logging::dynamic_type_dispatcher disp;
+
+ // Register type visitors
+ disp.register_type< int >(boost::bind(&my_visitor::on_int, &vis, boost::placeholders::_1));
+ disp.register_type< double >(boost::bind(&my_visitor::on_double, &vis, boost::placeholders::_1));
+
+ BOOST_CHECK(disp.registered_types_count() == 2);
+
+ // Right now strings are not supported by the dispatcher
+ my_value< std::string > val1("Hello world!");
+ BOOST_CHECK(!val1.dispatch(disp));
+
+ // And now they are
+ disp.register_type< std::string >(boost::bind(&my_visitor::on_string, &vis, boost::placeholders::_1));
+ BOOST_CHECK(disp.registered_types_count() == 3);
+
+ vis.set_expected(val1.m_Value);
+ BOOST_CHECK(val1.dispatch(disp));
+
+ my_value< double > val2(1.2);
+ vis.set_expected(val2.m_Value);
+ BOOST_CHECK(val2.dispatch(disp));
+
+ // This one is not supported
+ my_value< float > val3(static_cast< float >(-4.3));
+ vis.set_expected();
+ BOOST_CHECK(!val3.dispatch(disp));
+}
diff --git a/src/boost/libs/log/test/run/util_exception_handler.cpp b/src/boost/libs/log/test/run/util_exception_handler.cpp
new file mode 100644
index 000000000..1bdb5b412
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_exception_handler.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_exception_handler.cpp
+ * \author Andrey Semashev
+ * \date 13.07.2009
+ *
+ * \brief This header contains tests for the exception handler functional objects.
+ */
+
+#define BOOST_TEST_MODULE util_exception_handler
+
+#include <string>
+#include <typeinfo>
+#include <stdexcept>
+#include <boost/mpl/vector.hpp>
+#include <boost/smart_ptr/scoped_ptr.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/exception_handler.hpp>
+
+namespace logging = boost::log;
+
+namespace {
+
+ struct my_handler1
+ {
+ typedef void result_type;
+
+ std::type_info const*& m_pExceptionType;
+
+ my_handler1(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ };
+
+ struct my_handler2
+ {
+ typedef void result_type;
+ typedef boost::mpl::vector< std::runtime_error, std::exception >::type exception_types;
+
+ std::type_info const*& m_pExceptionType;
+
+ explicit my_handler2(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ };
+
+ struct my_handler1_nothrow
+ {
+ typedef void result_type;
+
+ std::type_info const*& m_pExceptionType;
+
+ my_handler1_nothrow(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ void operator() () const
+ {
+ m_pExceptionType = &typeid(void);
+ }
+ };
+
+ struct my_handler2_nothrow
+ {
+ typedef void result_type;
+ typedef boost::mpl::vector< std::runtime_error, std::exception >::type exception_types;
+
+ std::type_info const*& m_pExceptionType;
+
+ explicit my_handler2_nothrow(std::type_info const*& p) : m_pExceptionType(p) {}
+
+ void operator() (std::exception&) const
+ {
+ m_pExceptionType = &typeid(std::exception);
+ }
+ void operator() (std::runtime_error&) const
+ {
+ m_pExceptionType = &typeid(std::runtime_error);
+ }
+ void operator() () const
+ {
+ m_pExceptionType = &typeid(void);
+ }
+ };
+
+ struct my_exception {};
+
+ struct my_function0
+ {
+ struct impl_base
+ {
+ virtual ~impl_base() {}
+ virtual void invoke() = 0;
+ };
+
+ template< typename T >
+ struct impl : public impl_base
+ {
+ T m_Fun;
+
+ explicit impl(T const& fun) : m_Fun(fun) {}
+ void invoke() { m_Fun(); }
+ };
+
+ private:
+ boost::scoped_ptr< impl_base > m_pImpl;
+
+ public:
+ template< typename T >
+ my_function0& operator= (T const& fun)
+ {
+ m_pImpl.reset(new impl< T >(fun));
+ return *this;
+ }
+
+ void operator() () const
+ {
+ m_pImpl->invoke();
+ }
+ };
+
+} // namespace
+
+// Tests for handler with explicit exception types specification
+BOOST_AUTO_TEST_CASE(explicit_exception_types)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler<
+ std::runtime_error,
+ std::exception
+ >(my_handler1(pExceptionType));
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_THROW(handler(), my_exception);
+ }
+ BOOST_REQUIRE(pExceptionType == 0);
+
+ // Verify that exception types are checked in the specified order
+ handler = logging::make_exception_handler<
+ std::exception,
+ std::runtime_error
+ >(my_handler1(pExceptionType));
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+}
+
+// Tests for handler with explicit exception types specification (no-throw version)
+BOOST_AUTO_TEST_CASE(explicit_exception_types_nothrow)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler<
+ std::runtime_error,
+ std::exception
+ >(my_handler1_nothrow(pExceptionType), std::nothrow);
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_NO_THROW(handler());
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(void));
+ pExceptionType = 0;
+
+ // Verify that exception types are checked in the specified order
+ handler = logging::make_exception_handler<
+ std::exception,
+ std::runtime_error
+ >(my_handler1_nothrow(pExceptionType), std::nothrow);
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+}
+
+// Tests for handler with self-contained exception types
+BOOST_AUTO_TEST_CASE(self_contained_exception_types)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler(my_handler2(pExceptionType));
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_THROW(handler(), my_exception);
+ }
+ BOOST_REQUIRE(pExceptionType == 0);
+}
+
+// Tests for handler with self-contained exception types (no-throw version)
+BOOST_AUTO_TEST_CASE(self_contained_exception_types_nothrow)
+{
+ std::type_info const* pExceptionType = 0;
+ my_function0 handler;
+ handler = logging::make_exception_handler(my_handler2_nothrow(pExceptionType), std::nothrow);
+
+ try
+ {
+ throw std::runtime_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::runtime_error));
+ pExceptionType = 0;
+
+ try
+ {
+ throw std::logic_error("error");
+ }
+ catch (...)
+ {
+ handler();
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(std::exception));
+ pExceptionType = 0;
+
+ try
+ {
+ throw my_exception();
+ }
+ catch (...)
+ {
+ BOOST_CHECK_NO_THROW(handler());
+ }
+ BOOST_REQUIRE(pExceptionType != 0);
+ BOOST_CHECK(*pExceptionType == typeid(void));
+ pExceptionType = 0;
+}
diff --git a/src/boost/libs/log/test/run/util_formatting_ostream.cpp b/src/boost/libs/log/test/run/util_formatting_ostream.cpp
new file mode 100644
index 000000000..cd73bcd5f
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_formatting_ostream.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_formatting_ostream.cpp
+ * \author Andrey Semashev
+ * \date 26.05.2013
+ *
+ * \brief This header contains tests for the formatting output stream wrapper.
+ */
+
+#define BOOST_TEST_MODULE util_formatting_ostream
+
+#include <locale>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <iostream>
+#include <algorithm>
+#include <boost/config.hpp>
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+#include <string_view>
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/utility/string_view.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+#define BOOST_UTF8_DECL
+#define BOOST_UTF8_BEGIN_NAMESPACE namespace {
+#define BOOST_UTF8_END_NAMESPACE }
+
+#include <boost/detail/utf8_codecvt_facet.hpp>
+#include <boost/detail/utf8_codecvt_facet.ipp>
+
+#endif // defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+namespace logging = boost::log;
+
+namespace {
+
+struct unreferencable_data
+{
+ unsigned int m : 2;
+ unsigned int n : 6;
+
+ enum my_enum
+ {
+ one = 1,
+ two = 2
+ };
+
+ // The following static constants don't have definitions, so they can only be used in constant expressions.
+ // Trying to bind a reference to these members will result in linking errors.
+ static const int x = 7;
+ static const my_enum y = one;
+
+ unreferencable_data()
+ {
+ m = 1;
+ n = 5;
+ }
+};
+
+template< typename CharT >
+struct test_impl
+{
+ typedef CharT char_type;
+ typedef test_data< char_type > strings;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+
+ template< typename StringT >
+ static void width_formatting()
+ {
+ // Check that widening works
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+
+ // Check that the string is not truncated
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+ }
+
+ template< typename StringT >
+ static void fill_formatting()
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+
+ template< typename StringT >
+ static void alignment()
+ {
+ // Left alignment
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+
+ // Right alignment
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+ }
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template< typename StringT >
+ static void rvalue_stream()
+ {
+ string_type str_fmt;
+ formatting_ostream_type(str_fmt) << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC() << std::flush;
+
+ ostream_type strm_correct;
+ strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
+
+ BOOST_CHECK(equal_strings(str_fmt, strm_correct.str()));
+ }
+#endif
+
+ static void output_unreferencable_data()
+ {
+ unreferencable_data data;
+ {
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+ strm_fmt << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+ }
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ {
+ string_type str_fmt;
+ formatting_ostream_type(str_fmt) << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y << std::flush;
+
+ ostream_type strm_correct;
+ strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
+
+ BOOST_CHECK(equal_strings(str_fmt, strm_correct.str()));
+ }
+#endif
+ }
+};
+
+} // namespace
+
+// Test support for width formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for filler character setup
+BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >();
+#endif
+}
+
+// Test support for text alignment
+BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE alignment< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >();
+#endif
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+// Test support for rvalue stream objects
+BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >();
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >();
+#endif
+}
+#endif
+
+// Test output of data to which a reference cannot be bound
+BOOST_AUTO_TEST_CASE_TEMPLATE(output_unreferencable_data, CharT, char_types)
+{
+ typedef test_impl< CharT > test;
+ test::output_unreferencable_data();
+}
+
+namespace my_namespace {
+
+class A {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*)
+{
+ strm << "B*";
+ return strm;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*)
+{
+ strm << "const B*";
+ return strm;
+}
+
+class C {};
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace
+
+// Test operator forwarding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ const my_namespace::A a = my_namespace::A(); // const lvalue
+ my_namespace::B b; // lvalue
+ strm_fmt << a << b << my_namespace::C(); // rvalue
+ strm_fmt << my_namespace::eee;
+ strm_fmt << &b << (my_namespace::B const*)&b;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b;
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+namespace my_namespace2 {
+
+class A {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, A const&)
+{
+ strm << "A";
+ return strm;
+}
+
+class B {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, B&)
+{
+ strm << "B";
+ return strm;
+}
+
+class C {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, C const&)
+{
+ strm << "C";
+ return strm;
+}
+
+class D {};
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm,
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ D&&
+#else
+ D const&
+#endif
+ )
+{
+ strm << "D";
+ return strm;
+}
+
+enum E { eee };
+template< typename CharT, typename TraitsT, typename AllocatorT >
+inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, E)
+{
+ strm << "E";
+ return strm;
+}
+
+} // namespace my_namespace2
+
+// Test operator overriding
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overriding, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_string< char_type > string_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ const my_namespace2::A a = my_namespace2::A(); // const lvalue
+ my_namespace2::B b; // lvalue
+ strm_fmt << a << b << my_namespace2::C() << my_namespace2::D(); // rvalue
+ strm_fmt << my_namespace2::eee;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "ABCDE";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+#if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
+
+namespace {
+
+const char narrow_chars[] = "\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";
+const wchar_t wide_chars[] = { 0x041f, 0x0440, 0x0438, 0x0432, 0x0435, 0x0442, L',', L' ', 0x043c, 0x0438, 0x0440, L'!', 0 };
+
+template< typename StringT >
+void test_narrowing_code_conversion()
+{
+ std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
+
+ // Test rvalues
+ {
+ std::string str_fmt;
+ logging::formatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ strm_fmt << (StringT)wide_chars;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
+ }
+ // Test lvalues
+ {
+ std::string str_fmt;
+ logging::formatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ StringT wstr = StringT(wide_chars);
+ strm_fmt << wstr;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
+ }
+ // Test const lvalues
+ {
+ std::string str_fmt;
+ logging::formatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ const StringT wstr = StringT(wide_chars);
+ strm_fmt << wstr;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
+ }
+}
+
+template< typename StringT >
+void test_widening_code_conversion()
+{
+ std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
+
+ // Test rvalues
+ {
+ std::wstring str_fmt;
+ logging::wformatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ strm_fmt << (StringT)narrow_chars;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
+ }
+ // Test lvalues
+ {
+ std::wstring str_fmt;
+ logging::wformatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ StringT str = StringT(narrow_chars);
+ strm_fmt << str;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
+ }
+ // Test const lvalues
+ {
+ std::wstring str_fmt;
+ logging::wformatting_ostream strm_fmt(str_fmt);
+ strm_fmt.imbue(loc);
+ const StringT str = StringT(narrow_chars);
+ strm_fmt << str;
+ strm_fmt.flush();
+
+ BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
+ }
+}
+
+} // namespace
+
+// Test character code conversion
+BOOST_AUTO_TEST_CASE(character_code_conversion)
+{
+ test_narrowing_code_conversion< const wchar_t* >();
+ test_widening_code_conversion< const char* >();
+ test_narrowing_code_conversion< std::wstring >();
+ test_widening_code_conversion< std::string >();
+ test_narrowing_code_conversion< boost::wstring_view >();
+ test_widening_code_conversion< boost::string_view >();
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ test_narrowing_code_conversion< std::wstring_view >();
+ test_widening_code_conversion< std::string_view >();
+#endif
+}
+
+#endif
diff --git a/src/boost/libs/log/test/run/util_ipc_object_name.cpp b/src/boost/libs/log/test/run/util_ipc_object_name.cpp
new file mode 100644
index 000000000..11e63e852
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_ipc_object_name.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file util_ipc_object_name.cpp
+ * \author Andrey Semashev
+ * \date 07.03.2016
+ *
+ * \brief The test verifies that \c ipc::object_name works.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_IPC)
+
+#define BOOST_TEST_MODULE util_ipc_object_name
+
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <iostream>
+#include <boost/move/utility_core.hpp>
+#include "char_definitions.hpp"
+
+const char test_object_name1[] = "boost_log_test_object_name1";
+const char test_object_name2[] = "boost_log_test_object_name2";
+
+BOOST_AUTO_TEST_CASE(basic_functionality)
+{
+ // Default constructor.
+ {
+ boost::log::ipc::object_name name;
+ BOOST_CHECK(name.empty());
+ BOOST_CHECK(equal_strings(name.c_str(), ""));
+ }
+
+ // Initializing constructor
+ {
+ boost::log::ipc::object_name name(boost::log::ipc::object_name::global, test_object_name1);
+ BOOST_CHECK(!name.empty());
+ }
+
+ // Copy constructor
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2 = name1;
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+
+ // Move constructor
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ std::string name_str = name1.c_str();
+ boost::log::ipc::object_name name2 = boost::move(name1);
+ BOOST_CHECK(equal_strings(name2.c_str(), name_str.c_str()));
+ }
+
+ // Copy assignment
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2;
+ name2 = name1;
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+
+ // Move assignment
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ std::string name_str = name1.c_str();
+ boost::log::ipc::object_name name2;
+ name2 = boost::move(name1);
+ BOOST_CHECK(equal_strings(name2.c_str(), name_str.c_str()));
+ }
+
+ // Output
+ {
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::global, test_object_name1) << std::endl;
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::user, test_object_name1) << std::endl;
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::session, test_object_name1) << std::endl;
+ std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::process_group, test_object_name1) << std::endl;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(from_native)
+{
+ boost::log::ipc::object_name name = boost::log::ipc::object_name::from_native(test_object_name1);
+ BOOST_CHECK(equal_strings(name.c_str(), test_object_name1));
+}
+
+BOOST_AUTO_TEST_CASE(name_equivalence)
+{
+ // Test that the same names are equal
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::global, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::process_group, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_EQUAL(name1, name2);
+ }
+
+ // Test that different names don't clash
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::global, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::process_group, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name2);
+ BOOST_CHECK_NE(name1, name2);
+ }
+
+ // Test that same named in different scopes don't clash
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+ {
+ boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1);
+ boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1);
+ BOOST_CHECK_NE(name1, name2);
+ }
+}
+
+#else // !defined(BOOST_LOG_WITHOUT_IPC)
+
+int main()
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_IPC)
diff --git a/src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp b/src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp
new file mode 100644
index 000000000..388657293
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_ipc_reliable_mq.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright Lingxi Li 2015.
+ * Copyright Andrey Semashev 2016.
+ * 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)
+ */
+/*!
+ * \file util_ipc_reliable_mq.cpp
+ * \author Lingxi Li
+ * \author Andrey Semashev
+ * \date 19.10.2015
+ *
+ * \brief The test verifies that \c ipc::reliable_message_queue works.
+ */
+
+#if !defined(BOOST_LOG_WITHOUT_IPC)
+
+#define BOOST_TEST_MODULE util_ipc_reliable_mq
+
+#include <boost/log/utility/ipc/reliable_message_queue.hpp>
+#include <boost/log/utility/ipc/object_name.hpp>
+#include <boost/log/utility/permissions.hpp>
+#include <boost/log/utility/open_mode.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/test/unit_test.hpp>
+#include <cstddef>
+#include <cstring>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <stdexcept>
+#include <boost/move/utility_core.hpp>
+#if !defined(BOOST_LOG_NO_THREADS)
+#include <algorithm>
+#include <boost/ref.hpp>
+#include <boost/atomic/fences.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/chrono/duration.hpp>
+#endif
+#include "char_definitions.hpp"
+
+typedef boost::log::ipc::reliable_message_queue queue_t;
+typedef queue_t::size_type size_type;
+
+const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_ipc_reliable_mq");
+const unsigned int capacity = 512;
+const size_type block_size = 1024;
+const char message1[] = "Hello, world!";
+const char message2[] = "Hello, the brand new world!";
+
+BOOST_AUTO_TEST_CASE(basic_functionality)
+{
+ // Default constructor.
+ {
+ queue_t queue;
+ BOOST_CHECK(!queue.is_open());
+ }
+
+ // Do a remove in case if a previous test failed
+ queue_t::remove(ipc_queue_name);
+
+ // Opening a non-existing queue
+ try
+ {
+ queue_t queue(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_FAIL("Non-existing queue open succeeded, although it shouldn't have");
+ }
+ catch (std::exception&)
+ {
+ BOOST_TEST_PASSPOINT();
+ }
+
+ // Create constructor and destructor.
+ {
+ queue_t queue(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(equal_strings(queue.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK(queue.is_open());
+ BOOST_CHECK_EQUAL(queue.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue.block_size(), block_size);
+ }
+
+ // Creating a duplicate queue
+ try
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_t queue_b(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_FAIL("Creating a duplicate queue succeeded, although it shouldn't have");
+ }
+ catch (std::exception&)
+ {
+ BOOST_TEST_PASSPOINT();
+ }
+
+ // Opening an existing queue
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(queue_a.is_open());
+
+ queue_t queue_b(boost::log::open_mode::open_or_create, ipc_queue_name, capacity * 2u, block_size * 2u); // queue geometry differs from the existing queue
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+
+ queue_t queue_c(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_c.is_open());
+ BOOST_CHECK(equal_strings(queue_c.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_c.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_c.block_size(), block_size);
+ }
+ // Closing a queue
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ BOOST_CHECK(queue_a.is_open());
+ queue_a.close();
+ BOOST_CHECK(!queue_a.is_open());
+ // Duplicate close()
+ queue_a.close();
+ BOOST_CHECK(!queue_a.is_open());
+ }
+ // Move constructor.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_t queue_b(boost::move(queue_a));
+ BOOST_CHECK(!queue_a.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+ }
+ // Move assignment operator.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_t queue_b;
+ queue_b = boost::move(queue_a);
+ BOOST_CHECK(!queue_a.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+ }
+ // Member and non-member swaps.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size);
+ queue_a.swap(queue_a);
+ BOOST_CHECK(queue_a.is_open());
+ BOOST_CHECK(equal_strings(queue_a.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_a.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_a.block_size(), block_size);
+
+ queue_t queue_b;
+ swap(queue_a, queue_b);
+ BOOST_CHECK(!queue_a.is_open());
+ BOOST_CHECK(queue_b.is_open());
+ BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str()));
+ BOOST_CHECK_EQUAL(queue_b.capacity(), capacity);
+ BOOST_CHECK_EQUAL(queue_b.block_size(), block_size);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(message_passing)
+{
+ // try_send() and try_receive()
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_a.try_send(message1, sizeof(message1) - 1u));
+ BOOST_CHECK(!queue_a.try_send(message2, sizeof(message2) - 1u));
+ char buffer[block_size] = {};
+ size_type message_size = 0u;
+ BOOST_CHECK(queue_b.try_receive(buffer, sizeof(buffer), message_size));
+ BOOST_CHECK_EQUAL(message_size, sizeof(message1) - 1u);
+ BOOST_CHECK(std::memcmp(buffer, message1, message_size) == 0);
+ BOOST_CHECK(!queue_b.try_receive(buffer, sizeof(buffer), message_size));
+
+ BOOST_CHECK(queue_a.try_send(message2, sizeof(message2) - 1u));
+ std::string msg;
+ BOOST_CHECK(queue_b.try_receive(msg));
+ BOOST_CHECK_EQUAL(msg.size(), sizeof(message2) - 1u);
+ BOOST_CHECK_EQUAL(msg, message2);
+
+ BOOST_CHECK(queue_a.try_send(message2, sizeof(message2) - 1u));
+ std::vector< unsigned char > buf;
+ BOOST_CHECK(queue_b.try_receive(buf));
+ BOOST_CHECK_EQUAL(buf.size(), sizeof(message2) - 1u);
+ BOOST_CHECK(std::memcmp(&buf[0], message2, buf.size()) == 0);
+ }
+
+ // send() and receive() without blocking
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_a.send(message1, sizeof(message1) - 1u) == queue_t::succeeded);
+ char buffer[block_size] = {};
+ size_type message_size = 0u;
+ BOOST_CHECK(queue_b.receive(buffer, sizeof(buffer), message_size) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL(message_size, sizeof(message1) - 1u);
+ BOOST_CHECK(std::memcmp(buffer, message1, message_size) == 0);
+
+ BOOST_CHECK(queue_a.send(message2, sizeof(message2) - 1u) == queue_t::succeeded);
+ std::string msg;
+ BOOST_CHECK(queue_b.receive(msg) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL(msg.size(), sizeof(message2) - 1u);
+ BOOST_CHECK_EQUAL(msg, message2);
+
+ BOOST_CHECK(queue_a.send(message2, sizeof(message2) - 1u) == queue_t::succeeded);
+ std::vector< unsigned char > buf;
+ BOOST_CHECK(queue_b.receive(buf) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL(buf.size(), sizeof(message2) - 1u);
+ BOOST_CHECK(std::memcmp(&buf[0], message2, buf.size()) == 0);
+ }
+
+ // send() with an error code on overflow
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size, queue_t::fail_on_overflow);
+ BOOST_TEST_PASSPOINT();
+ BOOST_CHECK(queue_a.send(message1, sizeof(message1) - 1u) == queue_t::succeeded);
+ BOOST_TEST_PASSPOINT();
+
+ queue_t::operation_result res = queue_a.send(message1, sizeof(message1) - 1u);
+ BOOST_CHECK_EQUAL(res, queue_t::no_space);
+ }
+
+ // send() with an exception on overflow
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size, queue_t::throw_on_overflow);
+ BOOST_TEST_PASSPOINT();
+ BOOST_CHECK(queue_a.send(message1, sizeof(message1) - 1u) == queue_t::succeeded);
+ BOOST_TEST_PASSPOINT();
+ try
+ {
+ queue_a.send(message1, sizeof(message1) - 1u);
+ BOOST_FAIL("Owerflowing the queue succeeded, although it shouldn't have");
+ }
+ catch (boost::log::capacity_limit_reached&)
+ {
+ BOOST_TEST_PASSPOINT();
+ }
+ }
+
+ // send() and receive() for messages larger than block_size. The message size and queue capacity below are such
+ // that the last enqueued message is expected to be split in the queue storage.
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 5u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+
+ const size_type message_size = block_size * 3u / 2u;
+ std::vector< unsigned char > send_data;
+ send_data.resize(message_size);
+ for (unsigned int i = 0; i < message_size; ++i)
+ send_data[i] = static_cast< unsigned char >(i & 0xFF);
+
+ BOOST_CHECK(queue_a.send(&send_data[0], static_cast< size_type >(send_data.size())) == queue_t::succeeded);
+
+ for (unsigned int i = 0; i < 3; ++i)
+ {
+ BOOST_CHECK(queue_a.send(&send_data[0], static_cast< size_type >(send_data.size())) == queue_t::succeeded);
+
+ std::vector< unsigned char > receive_data;
+ BOOST_CHECK(queue_b.receive(receive_data) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL_COLLECTIONS(send_data.begin(), send_data.end(), receive_data.begin(), receive_data.end());
+ }
+
+ std::vector< unsigned char > receive_data;
+ BOOST_CHECK(queue_b.receive(receive_data) == queue_t::succeeded);
+ BOOST_CHECK_EQUAL_COLLECTIONS(send_data.begin(), send_data.end(), receive_data.begin(), receive_data.end());
+ }
+
+ // clear()
+ {
+ queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, 1u, block_size);
+ queue_t queue_b(boost::log::open_mode::open_only, ipc_queue_name);
+ BOOST_CHECK(queue_a.try_send(message1, sizeof(message1) - 1u));
+ BOOST_CHECK(!queue_a.try_send(message2, sizeof(message2) - 1u));
+
+ queue_a.clear();
+
+ BOOST_CHECK(queue_a.try_send(message2, sizeof(message2) - 1u));
+ char buffer[block_size] = {};
+ size_type message_size = 0u;
+ BOOST_CHECK(queue_b.try_receive(buffer, sizeof(buffer), message_size));
+ BOOST_CHECK_EQUAL(message_size, sizeof(message2) - 1u);
+ BOOST_CHECK(std::memcmp(buffer, message2, message_size) == 0);
+ }
+}
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+namespace {
+
+const unsigned int message_count = 100000;
+
+void multithreaded_message_passing_feeding_thread(const char* message, unsigned int& failure_count)
+{
+ const size_type len = static_cast< size_type >(std::strlen(message));
+ queue_t queue(boost::log::open_mode::open_or_create, ipc_queue_name, capacity, block_size);
+ for (unsigned int i = 0; i < message_count; ++i)
+ {
+ failure_count += queue.send(message, len) != queue_t::succeeded;
+ }
+
+ boost::atomic_thread_fence(boost::memory_order_release);
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(multithreaded_message_passing)
+{
+ unsigned int failure_count1 = 0, failure_count2 = 0, failure_count3 = 0;
+ boost::atomic_thread_fence(boost::memory_order_release);
+
+ boost::thread thread1(&multithreaded_message_passing_feeding_thread, "Thread 1", boost::ref(failure_count1));
+ boost::thread thread2(&multithreaded_message_passing_feeding_thread, "Thread 2", boost::ref(failure_count2));
+ boost::thread thread3(&multithreaded_message_passing_feeding_thread, "Thread 3", boost::ref(failure_count3));
+
+ BOOST_TEST_PASSPOINT();
+
+ queue_t queue(boost::log::open_mode::open_or_create, ipc_queue_name, capacity, block_size);
+ unsigned int receive_failures = 0, receive_corruptions = 0;
+ unsigned int message_count1 = 0, message_count2 = 0, message_count3 = 0;
+ std::string msg;
+
+ BOOST_TEST_PASSPOINT();
+
+ for (unsigned int i = 0; i < message_count * 3u; ++i)
+ {
+ msg.clear();
+ if (queue.receive(msg) == queue_t::succeeded)
+ {
+ if (msg == "Thread 1")
+ ++message_count1;
+ else if (msg == "Thread 2")
+ ++message_count2;
+ else if (msg == "Thread 3")
+ ++message_count3;
+ else
+ ++receive_corruptions;
+ }
+ else
+ ++receive_failures;
+ }
+
+ BOOST_TEST_PASSPOINT();
+ thread1.join();
+
+ BOOST_TEST_PASSPOINT();
+ thread2.join();
+
+ BOOST_TEST_PASSPOINT();
+ thread3.join();
+
+ boost::atomic_thread_fence(boost::memory_order_acquire);
+
+ BOOST_CHECK_EQUAL(failure_count1, 0u);
+ BOOST_CHECK_EQUAL(message_count1, message_count);
+ BOOST_CHECK_EQUAL(failure_count2, 0u);
+ BOOST_CHECK_EQUAL(message_count2, message_count);
+ BOOST_CHECK_EQUAL(failure_count3, 0u);
+ BOOST_CHECK_EQUAL(message_count3, message_count);
+ BOOST_CHECK_EQUAL(receive_failures, 0u);
+ BOOST_CHECK_EQUAL(receive_corruptions, 0u);
+}
+
+namespace {
+
+void stop_reset_feeding_thread(queue_t& queue, queue_t::operation_result* results, unsigned int count)
+{
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ results[i] = queue.send(message1, sizeof(message1) - 1u);
+ if (results[i] != queue_t::succeeded)
+ break;
+ }
+
+ boost::atomic_thread_fence(boost::memory_order_release);
+}
+
+void stop_reset_reading_thread(queue_t& queue, queue_t::operation_result* results, unsigned int count)
+{
+ std::string msg;
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ msg.clear();
+ results[i] = queue.receive(msg);
+ if (results[i] != queue_t::succeeded)
+ break;
+ }
+
+ boost::atomic_thread_fence(boost::memory_order_release);
+}
+
+} // namespace
+
+BOOST_AUTO_TEST_CASE(stop_reset_local)
+{
+ queue_t feeder_queue(boost::log::open_mode::open_or_create, ipc_queue_name, 1u, block_size);
+ queue_t::operation_result feeder_results[3];
+ queue_t reader_queue(boost::log::open_mode::open_only, ipc_queue_name);
+ queue_t::operation_result reader_results[3];
+
+ std::fill_n(feeder_results, sizeof(feeder_results) / sizeof(*feeder_results), queue_t::succeeded);
+ std::fill_n(reader_results, sizeof(reader_results) / sizeof(*reader_results), queue_t::succeeded);
+ boost::atomic_thread_fence(boost::memory_order_release);
+
+ BOOST_TEST_PASSPOINT();
+
+ // Case 1: Let the feeder block and then we unblock it with stop_local()
+ boost::thread feeder_thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 3);
+ boost::thread reader_thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 1);
+
+ BOOST_TEST_PASSPOINT();
+
+ reader_thread.join();
+ BOOST_TEST_PASSPOINT();
+ boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
+
+ BOOST_TEST_PASSPOINT();
+
+ feeder_queue.stop_local();
+ BOOST_TEST_PASSPOINT();
+ feeder_thread.join();
+
+ boost::atomic_thread_fence(boost::memory_order_acquire);
+
+ BOOST_CHECK_EQUAL(feeder_results[0], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(feeder_results[1], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(feeder_results[2], queue_t::aborted);
+ BOOST_CHECK_EQUAL(reader_results[0], queue_t::succeeded);
+
+ // Reset the aborted queue
+ feeder_queue.reset_local();
+ feeder_queue.clear();
+
+ std::fill_n(feeder_results, sizeof(feeder_results) / sizeof(*feeder_results), queue_t::succeeded);
+ std::fill_n(reader_results, sizeof(reader_results) / sizeof(*reader_results), queue_t::succeeded);
+ boost::atomic_thread_fence(boost::memory_order_release);
+
+ BOOST_TEST_PASSPOINT();
+
+ // Case 2: Let the reader block and then we unblock it with stop_local()
+ boost::thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 1).swap(feeder_thread);
+ boost::thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 2).swap(reader_thread);
+
+ BOOST_TEST_PASSPOINT();
+
+ feeder_thread.join();
+ BOOST_TEST_PASSPOINT();
+ boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
+
+ BOOST_TEST_PASSPOINT();
+
+ reader_queue.stop_local();
+ BOOST_TEST_PASSPOINT();
+ reader_thread.join();
+
+ boost::atomic_thread_fence(boost::memory_order_acquire);
+
+ BOOST_CHECK_EQUAL(feeder_results[0], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(feeder_results[1], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(reader_results[0], queue_t::succeeded);
+ BOOST_CHECK_EQUAL(reader_results[1], queue_t::aborted);
+}
+
+#endif // !defined(BOOST_LOG_NO_THREADS)
+
+#else // !defined(BOOST_LOG_WITHOUT_IPC)
+
+int main()
+{
+ return 0;
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_IPC)
diff --git a/src/boost/libs/log/test/run/util_manip_add_value.cpp b/src/boost/libs/log/test/run/util_manip_add_value.cpp
new file mode 100644
index 000000000..9b2227e59
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_add_value.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_manip_add_value.cpp
+ * \author Andrey Semashev
+ * \date 07.11.2013
+ *
+ * \brief This header contains tests for the \c add_value manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_add_value
+
+#include <iomanip>
+#include <iostream>
+#include <boost/move/core.hpp>
+#include <boost/io/ios_state.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/core.hpp>
+#include <boost/log/sources/record_ostream.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/value_extraction.hpp>
+#include <boost/log/expressions/keyword.hpp>
+#include <boost/log/utility/manipulators/add_value.hpp>
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+
+struct my_type
+{
+ BOOST_COPYABLE_AND_MOVABLE(my_type)
+
+public:
+ unsigned int value;
+
+ explicit my_type(unsigned int n = 0) : value(n) {}
+ my_type(my_type const& that) : value(that.value) {}
+ my_type(BOOST_RV_REF(my_type) that) : value(that.value) { that.value = 0xbaadbaad; }
+ ~my_type() { value = 0xdeaddead; }
+
+ my_type& operator= (BOOST_COPY_ASSIGN_REF(my_type) that) { value = that.value; return *this; }
+ my_type& operator= (BOOST_RV_REF(my_type) that) { value = that.value; that.value = 0xbaadbaad; return *this; }
+};
+
+inline bool operator== (my_type const& left, my_type const& right)
+{
+ return left.value == right.value;
+}
+
+inline bool operator!= (my_type const& left, my_type const& right)
+{
+ return left.value != right.value;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_type const& val)
+{
+ if (strm.good())
+ {
+ boost::io::ios_flags_saver flags(strm);
+ boost::io::basic_ios_fill_saver< CharT, TraitsT > fill(strm);
+ strm << std::hex << std::internal << std::setfill(static_cast< CharT >('0')) << std::setw(10) << val.value;
+ }
+ return strm;
+}
+
+struct my_pod_type
+{
+ unsigned int value;
+};
+
+inline bool operator== (my_pod_type const& left, my_pod_type const& right)
+{
+ return left.value == right.value;
+}
+
+inline bool operator!= (my_pod_type const& left, my_pod_type const& right)
+{
+ return left.value != right.value;
+}
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_pod_type const& val)
+{
+ if (strm.good())
+ {
+ boost::io::ios_flags_saver flags(strm);
+ boost::io::basic_ios_fill_saver< CharT, TraitsT > fill(strm);
+ strm << std::hex << std::internal << std::setfill(static_cast< CharT >('0')) << std::setw(10) << val.value;
+ }
+ return strm;
+}
+
+BOOST_AUTO_TEST_CASE(manual_add_attr)
+{
+ logging::record rec = make_record(logging::attribute_set());
+ BOOST_REQUIRE(!!rec);
+ logging::record_ostream strm(rec);
+
+ my_type val(0xaaaaaaaa);
+ const my_type const_val(0xbbbbbbbb);
+ strm << logging::add_value("MyAttr1", val) << logging::add_value("MyAttr2", const_val) << logging::add_value("MyAttr3", my_type(0xcccccccc));
+
+ // Test for MSVC bug: if the value is a scalar type, it saves a dangling reference to the add_value_manip,
+ // which results in garbage in the attribute value
+ strm << logging::add_value("MyAttr4", 100u);
+ strm << logging::add_value("MyAttr5", my_pod_type());
+
+ strm.detach_from_record();
+
+ BOOST_CHECK_EQUAL(rec["MyAttr1"].extract< my_type >(), val);
+ BOOST_CHECK_EQUAL(rec["MyAttr2"].extract< my_type >(), const_val);
+ BOOST_CHECK_EQUAL(rec["MyAttr3"].extract< my_type >(), my_type(0xcccccccc));
+ BOOST_CHECK_EQUAL(rec["MyAttr4"].extract< unsigned int >(), 100u);
+ BOOST_CHECK_EQUAL(rec["MyAttr5"].extract< my_pod_type >(), my_pod_type());
+}
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_my1, "MyAttr1", my_type)
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_my2, "MyAttr2", my_type)
+BOOST_LOG_ATTRIBUTE_KEYWORD(a_my3, "MyAttr3", my_type)
+
+BOOST_AUTO_TEST_CASE(keyword_add_attr)
+{
+ logging::record rec = make_record(logging::attribute_set());
+ BOOST_REQUIRE(!!rec);
+ logging::record_ostream strm(rec);
+
+ my_type val(0xaaaaaaaa);
+ const my_type const_val(0xbbbbbbbb);
+ strm << logging::add_value(a_my1, val) << logging::add_value(a_my2, const_val) << logging::add_value(a_my3, my_type(0xcccccccc));
+ strm.detach_from_record();
+
+ BOOST_CHECK_EQUAL(rec[a_my1], val);
+ BOOST_CHECK_EQUAL(rec[a_my2], const_val);
+ BOOST_CHECK_EQUAL(rec[a_my3], my_type(0xcccccccc));
+}
diff --git a/src/boost/libs/log/test/run/util_manip_auto_newline.cpp b/src/boost/libs/log/test/run/util_manip_auto_newline.cpp
new file mode 100644
index 000000000..91f1d07b5
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_auto_newline.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright Andrey Semashev 2019.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ */
+/*!
+ * \file util_manip_auto_newline.cpp
+ * \author Andrey Semashev
+ * \date 23.06.2019
+ *
+ * \brief This header contains tests for the auto_newline manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_auto_newline
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/manipulators/auto_newline.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+
+// Test appending a newline to a non-empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_non_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ strm_fmt << "Hello" << logging::auto_newline;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test appending a newline to an empty string
+BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_empty_string, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ strm_fmt << logging::auto_newline;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
+
+// Test not appending a newline to a non-empty string which already ends with a newline
+BOOST_AUTO_TEST_CASE_TEMPLATE(not_append_if_ends_with_a_newline, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+ typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
+ typedef typename formatting_ostream_type::string_type string_type;
+
+ string_type str_fmt;
+ formatting_ostream_type strm_fmt(str_fmt);
+
+ strm_fmt << "Hello\n" << logging::auto_newline;
+ strm_fmt.flush();
+
+ ostream_type strm_correct;
+ strm_correct << "Hello\n";
+
+ BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
+}
diff --git a/src/boost/libs/log/test/run/util_manip_dump.cpp b/src/boost/libs/log/test/run/util_manip_dump.cpp
new file mode 100644
index 000000000..731116cd0
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_dump.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_manip_dump.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the dump manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_dump
+
+#include <vector>
+#include <string>
+#include <iomanip>
+#include <sstream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/manipulators/dump.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+
+// Test a short data region
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_lowercase_short_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ data.push_back(100);
+ data.push_back(110);
+ data.push_back(120);
+ data.push_back(200);
+ data.push_back(210);
+ data.push_back(220);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size());
+
+ ostream_type strm_correct;
+ strm_correct << "01 02 03 64 6e 78 c8 d2 dc";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test a short data region with uppercase formatting
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_uppercase_short_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ data.push_back(100);
+ data.push_back(110);
+ data.push_back(120);
+ data.push_back(200);
+ data.push_back(210);
+ data.push_back(220);
+
+ ostream_type strm_dump;
+ strm_dump << std::uppercase << logging::dump(&data[0], data.size());
+
+ ostream_type strm_correct;
+ strm_correct << "01 02 03 64 6E 78 C8 D2 DC";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test void pointer handling
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_pvoid_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ data.push_back(100);
+ data.push_back(110);
+ data.push_back(120);
+ data.push_back(200);
+ data.push_back(210);
+ data.push_back(220);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump((void*)&data[0], data.size());
+
+ ostream_type strm_correct;
+ strm_correct << "01 02 03 64 6e 78 c8 d2 dc";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test a large data region
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_large_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ ostream_type strm_correct;
+ for (unsigned int i = 0; i < 1024; ++i)
+ {
+ unsigned char n = static_cast< unsigned char >(i);
+ data.push_back(n);
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size());
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test SIMD tail handling
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_binary_tail_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ ostream_type strm_correct;
+ // 1023 makes it very unlikely for the buffer to end at 16 or 32 byte boundary, which makes the dump algorithm to process the tail in a special way
+ for (unsigned int i = 0; i < 1023; ++i)
+ {
+ unsigned char n = static_cast< unsigned char >(i);
+ data.push_back(n);
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size());
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test bounded dump
+BOOST_AUTO_TEST_CASE_TEMPLATE(bounded_binary_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned char > data;
+ ostream_type strm_correct;
+ for (unsigned int i = 0; i < 1024; ++i)
+ {
+ unsigned char n = static_cast< unsigned char >(i);
+ data.push_back(n);
+
+ if (i < 500)
+ {
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+ }
+
+ strm_correct << std::dec << std::setfill(static_cast< char_type >(' ')) << " and " << 524u << " bytes more";
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump(&data[0], data.size(), 500);
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test array dump
+BOOST_AUTO_TEST_CASE_TEMPLATE(unbounded_element_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned int > data;
+ data.push_back(0x01020a0b);
+ data.push_back(0x03040c0d);
+ data.push_back(0x05060e0f);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump_elements(&data[0], data.size());
+
+ ostream_type strm_correct;
+ const unsigned char* p = reinterpret_cast< const unsigned char* >(&data[0]);
+ std::size_t size = data.size() * sizeof(unsigned int);
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ unsigned char n = p[i];
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
+// Test bounded array dump
+BOOST_AUTO_TEST_CASE_TEMPLATE(bounded_element_dump, CharT, char_types)
+{
+ typedef CharT char_type;
+ typedef std::basic_ostringstream< char_type > ostream_type;
+
+ std::vector< unsigned int > data;
+ data.push_back(0x01020a0b);
+ data.push_back(0x03040c0d);
+ data.push_back(0x05060e0f);
+
+ ostream_type strm_dump;
+ strm_dump << logging::dump_elements(&data[0], data.size(), 2);
+
+ ostream_type strm_correct;
+ const unsigned char* p = reinterpret_cast< const unsigned char* >(&data[0]);
+ std::size_t size = 2 * sizeof(unsigned int);
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ unsigned char n = p[i];
+ if (i > 0)
+ strm_correct << " ";
+ strm_correct << std::hex << std::setw(2) << std::setfill(static_cast< char_type >('0')) << static_cast< unsigned int >(n);
+ }
+
+ strm_correct << std::dec << std::setfill(static_cast< char_type >(' ')) << " and " << (data.size() - 2) * sizeof(unsigned int) << " bytes more";
+
+ BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str()));
+}
+
diff --git a/src/boost/libs/log/test/run/util_manip_to_log.cpp b/src/boost/libs/log/test/run/util_manip_to_log.cpp
new file mode 100644
index 000000000..3937d540a
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_manip_to_log.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_manip_to_log.cpp
+ * \author Andrey Semashev
+ * \date 05.07.2015
+ *
+ * \brief This header contains tests for the \c to_log stream manipulator.
+ */
+
+#define BOOST_TEST_MODULE util_manip_to_log
+
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/to_log.hpp>
+#include "char_definitions.hpp"
+
+namespace logging = boost::log;
+
+namespace tag {
+
+struct a_my_class;
+
+} // namespace tag
+
+namespace {
+
+struct my_class
+{
+ int m_Data;
+
+ explicit my_class(int data) : m_Data(data) {}
+};
+
+template< typename CharT, typename TraitsT >
+inline std::basic_ostream< CharT, TraitsT >&
+operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_class const& obj)
+{
+ strm << "my_class: [data: " << obj.m_Data << "]";
+ return strm;
+}
+
+template< typename StreamT >
+inline StreamT&
+operator<< (StreamT& strm, logging::to_log_manip< my_class > const& obj)
+{
+ strm << "to_log(my_class: [data: " << obj.get().m_Data << "])";
+ return strm;
+}
+
+template< typename StreamT >
+inline StreamT&
+operator<< (StreamT& strm, logging::to_log_manip< my_class, tag::a_my_class > const& obj)
+{
+ strm << "to_log<a_my_class>(my_class: [data: " << obj.get().m_Data << "])";
+ return strm;
+}
+
+template< typename CharT, typename StreamT >
+struct tests
+{
+ typedef CharT char_type;
+ typedef StreamT stream_type;
+ typedef std::basic_string< char_type > string;
+ typedef std::basic_ostringstream< char_type > std_stream;
+
+ //! The test verifies that the default behavior of the manipulator is equivalent to the standard operator<<
+ static void default_operator()
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << logging::to_log(10);
+
+ std_stream strm2;
+ strm2 << 10;
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+
+ //! The test verifies that operator overrides work
+ static void operator_overrides()
+ {
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << my_class(10);
+
+ std_stream strm2;
+ strm2 << "my_class: [data: " << 10 << "]";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << logging::to_log(my_class(10));
+
+ std_stream strm2;
+ strm2 << "to_log(my_class: [data: " << 10 << "])";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ {
+ string str;
+ stream_type strm1(str);
+ strm1 << logging::to_log< tag::a_my_class >(my_class(10));
+
+ std_stream strm2;
+ strm2 << "to_log<a_my_class>(my_class: [data: " << 10 << "])";
+ BOOST_CHECK(equal_strings(strm1.str(), strm2.str()));
+ }
+ }
+};
+
+} // namespace
+
+
+//! The test verifies that the default behavior of the manipulator is equivalent to the standard operator<<
+BOOST_AUTO_TEST_CASE_TEMPLATE(default_operator, CharT, char_types)
+{
+ tests< CharT, std::basic_ostringstream< CharT > >::default_operator();
+ tests< CharT, logging::basic_formatting_ostream< CharT > >::default_operator();
+}
+
+//! The test verifies that operator overrides work
+BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overrides, CharT, char_types)
+{
+ tests< CharT, std::basic_ostringstream< CharT > >::operator_overrides();
+ tests< CharT, logging::basic_formatting_ostream< CharT > >::operator_overrides();
+}
diff --git a/src/boost/libs/log/test/run/util_once_block.cpp b/src/boost/libs/log/test/run/util_once_block.cpp
new file mode 100644
index 000000000..4149c7428
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_once_block.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_once_block.cpp
+ * \author Andrey Semashev
+ * \date 24.06.2010
+ *
+ * \brief This header contains tests for once-blocks implementation.
+ *
+ * The test was adopted from test_once.cpp test of Boost.Thread.
+ */
+
+#define BOOST_TEST_MODULE util_once_block
+
+#include <boost/log/utility/once_block.hpp>
+#include <boost/test/unit_test.hpp>
+
+#if !defined(BOOST_LOG_NO_THREADS)
+
+#include <boost/core/ref.hpp>
+#include <boost/bind/bind.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/barrier.hpp>
+
+namespace logging = boost::log;
+
+enum config
+{
+ THREAD_COUNT = 20,
+ LOOP_COUNT = 100
+};
+
+boost::mutex m;
+typedef boost::lock_guard< boost::mutex > scoped_lock;
+
+logging::once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT;
+int var_to_init_once_flag = 0;
+
+void initialize_variable()
+{
+ // ensure that if multiple threads get in here, they are serialized, so we can see the effect
+ scoped_lock lock(m);
+ ++var_to_init_once_flag;
+}
+
+
+void once_block_flag_thread(boost::barrier& barrier)
+{
+ int my_once_value = 0;
+ barrier.wait();
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK_FLAG(flag)
+ {
+ initialize_variable();
+ }
+
+ my_once_value = var_to_init_once_flag;
+ if (my_once_value != 1)
+ {
+ break;
+ }
+ }
+ scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK_FLAG macro works
+BOOST_AUTO_TEST_CASE(once_block_flag)
+{
+ boost::thread_group group;
+ boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT));
+
+ try
+ {
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ {
+ group.create_thread(boost::bind(&once_block_flag_thread, boost::ref(barrier)));
+ }
+ group.join_all();
+ }
+ catch (...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once_flag, 1);
+}
+
+int var_to_init_once = 0;
+
+void once_block_thread(boost::barrier& barrier)
+{
+ int my_once_value = 0;
+ barrier.wait();
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ scoped_lock lock(m);
+ ++var_to_init_once;
+ }
+
+ my_once_value = var_to_init_once;
+ if (my_once_value != 1)
+ {
+ break;
+ }
+ }
+
+ scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK macro works
+BOOST_AUTO_TEST_CASE(once_block)
+{
+ boost::thread_group group;
+ boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT));
+
+ try
+ {
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ {
+ group.create_thread(boost::bind(&once_block_thread, boost::ref(barrier)));
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once, 1);
+}
+
+
+struct my_exception
+{
+};
+
+unsigned int pass_counter = 0;
+unsigned int exception_counter = 0;
+
+void once_block_with_exception_thread(boost::barrier& barrier)
+{
+ barrier.wait();
+ try
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ scoped_lock lock(m);
+ ++pass_counter;
+ if (pass_counter < 3)
+ {
+ throw my_exception();
+ }
+ }
+ }
+ catch (my_exception&)
+ {
+ scoped_lock lock(m);
+ ++exception_counter;
+ }
+}
+
+// The test verifies that the once_block flag is not set if an exception is thrown from the once-block
+BOOST_AUTO_TEST_CASE(once_block_retried_on_exception)
+{
+ boost::thread_group group;
+ boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT));
+
+ try
+ {
+ for (unsigned int i = 0; i < THREAD_COUNT; ++i)
+ {
+ group.create_thread(boost::bind(&once_block_with_exception_thread, boost::ref(barrier)));
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(pass_counter, 3u);
+ BOOST_CHECK_EQUAL(exception_counter, 2u);
+}
+
+#else // BOOST_LOG_NO_THREADS
+
+namespace logging = boost::log;
+
+enum config
+{
+ LOOP_COUNT = 100
+};
+
+logging::once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT;
+int var_to_init_once_flag = 0;
+
+void initialize_variable()
+{
+ ++var_to_init_once_flag;
+}
+
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK_FLAG macro works
+BOOST_AUTO_TEST_CASE(once_block_flag)
+{
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK_FLAG(flag)
+ {
+ initialize_variable();
+ }
+
+ if (var_to_init_once_flag != 1)
+ {
+ break;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once_flag, 1);
+}
+
+int var_to_init_once = 0;
+
+// The test checks if the BOOST_LOG_ONCE_BLOCK macro works
+BOOST_AUTO_TEST_CASE(once_block)
+{
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ ++var_to_init_once;
+ }
+
+ if (var_to_init_once != 1)
+ {
+ break;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_once, 1);
+}
+
+struct my_exception
+{
+};
+
+unsigned int pass_counter = 0;
+unsigned int exception_counter = 0;
+
+// The test verifies that the once_block flag is not set if an exception is thrown from the once-block
+BOOST_AUTO_TEST_CASE(once_block_retried_on_exception)
+{
+ for (unsigned int i = 0; i < LOOP_COUNT; ++i)
+ {
+ try
+ {
+ BOOST_LOG_ONCE_BLOCK()
+ {
+ ++pass_counter;
+ if (pass_counter < 3)
+ {
+ throw my_exception();
+ }
+ }
+ }
+ catch (my_exception&)
+ {
+ ++exception_counter;
+ }
+ }
+
+ BOOST_CHECK_EQUAL(pass_counter, 3u);
+ BOOST_CHECK_EQUAL(exception_counter, 2u);
+}
+
+#endif // BOOST_LOG_NO_THREADS
diff --git a/src/boost/libs/log/test/run/util_static_type_disp.cpp b/src/boost/libs/log/test/run/util_static_type_disp.cpp
new file mode 100644
index 000000000..3f30ad5d5
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_static_type_disp.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_static_type_disp.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the static type dispatcher.
+ */
+
+#define BOOST_TEST_MODULE util_static_type_disp
+
+#include <string>
+#include <typeinfo>
+#include <boost/mpl/vector.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/tools/floating_point_comparison.hpp>
+#include <boost/log/utility/type_dispatch/static_type_dispatcher.hpp>
+
+namespace logging = boost::log;
+
+namespace {
+
+ // A simple attribute value
+ template< typename T >
+ struct my_value
+ {
+ T m_Value;
+
+ explicit my_value(T const& value) : m_Value(value) {}
+
+ // The function passes the contained type into the dispatcher
+ bool dispatch(logging::type_dispatcher& dispatcher)
+ {
+ logging::type_dispatcher::callback< T > callback = dispatcher.get_callback< T >();
+ if (callback)
+ {
+ callback(m_Value);
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ // The function tests general functionality of the type dispatcher
+ template< typename DispatcherT >
+ void test_general_functionality(DispatcherT& disp)
+ {
+ // These two attributes are supported by the dispatcher
+ my_value< std::string > val1("Hello world!");
+ disp.set_expected(val1.m_Value);
+ BOOST_CHECK(val1.dispatch(disp));
+
+ my_value< double > val2(1.2);
+ disp.set_expected(val2.m_Value);
+ BOOST_CHECK(val2.dispatch(disp));
+
+ // This one is not
+ my_value< float > val3(static_cast< float >(-4.3));
+ disp.set_expected();
+ BOOST_CHECK(!val3.dispatch(disp));
+ }
+
+
+ // Type dispatcher for the supported types
+ struct my_dispatcher :
+ public logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ >
+ {
+ typedef logging::static_type_dispatcher<
+ boost::mpl::vector< int, double, std::string >
+ > base_type;
+
+ enum type_expected
+ {
+ none_expected,
+ int_expected,
+ double_expected,
+ string_expected
+ };
+
+ my_dispatcher() :
+ base_type(*this),
+ m_Expected(none_expected),
+ m_Int(0),
+ m_Double(0.0)
+ {
+ }
+
+ void set_expected()
+ {
+ m_Expected = none_expected;
+ }
+ void set_expected(int value)
+ {
+ m_Expected = int_expected;
+ m_Int = value;
+ }
+ void set_expected(double value)
+ {
+ m_Expected = double_expected;
+ m_Double = value;
+ }
+ void set_expected(std::string const& value)
+ {
+ m_Expected = string_expected;
+ m_String = value;
+ }
+
+ // Implement visitation logic for all supported types
+ void operator() (int const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, int_expected);
+ BOOST_CHECK_EQUAL(m_Int, value);
+ }
+ void operator() (double const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, double_expected);
+ BOOST_CHECK_CLOSE(m_Double, value, 0.001);
+ }
+ void operator() (std::string const& value) const
+ {
+ BOOST_CHECK_EQUAL(m_Expected, string_expected);
+ BOOST_CHECK_EQUAL(m_String, value);
+ }
+
+ private:
+ type_expected m_Expected;
+ int m_Int;
+ double m_Double;
+ std::string m_String;
+ };
+
+} // namespace
+
+// The test checks that general functionality works
+BOOST_AUTO_TEST_CASE(type_dispatch)
+{
+ my_dispatcher disp;
+ test_general_functionality(disp);
+}
diff --git a/src/boost/libs/log/test/run/util_stp_filter_parser.cpp b/src/boost/libs/log/test/run/util_stp_filter_parser.cpp
new file mode 100644
index 000000000..946c5f06c
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_stp_filter_parser.cpp
@@ -0,0 +1,808 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file setup_filter_parser.cpp
+ * \author Andrey Semashev
+ * \date 24.08.2013
+ *
+ * \brief This header contains tests for the filter parser.
+ */
+
+#define BOOST_TEST_MODULE setup_filter_parser
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/setup/filter_parser.hpp>
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/expressions/filter.hpp>
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+typedef logging::attribute_set attr_set;
+typedef logging::attribute_value_set attr_values;
+
+// Tests for attribute presence check
+BOOST_AUTO_TEST_CASE(attr_presence)
+{
+ attrs::constant< int > attr1(10);
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr%");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter(" % MyAttr % ");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+}
+
+// Tests for integer relation filter
+BOOST_AUTO_TEST_CASE(int_relation)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< long > attr2(20);
+ attrs::constant< int > attr3(-2);
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyAttr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% != 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < -7");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > -5");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% <= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% >= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+}
+
+// Tests for floating point relation filter
+BOOST_AUTO_TEST_CASE(fp_relation)
+{
+ attrs::constant< float > attr1(2.5f);
+ attrs::constant< float > attr2(8.8f);
+ attrs::constant< double > attr3(-9.1);
+ attrs::constant< float > attr4(0.0f);
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyAttr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ set1["MyAttr"] = attr4;
+ attr_values values5(set1, set2, set3);
+ values5.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10.3");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% != 10");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < 5.5");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% < -7");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 5.6");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > -5");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% <= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% >= 20");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+}
+
+// Tests for string relation filter
+BOOST_AUTO_TEST_CASE(string_relation)
+{
+ attrs::constant< std::string > attr1("hello");
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyStr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = hello");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter(" % MyStr % = \"hello\" ");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \" hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"hello \"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"Hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% != hello");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% != world");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% < world");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% > world");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+
+ // Check that strings that look like numbers can still be used in filters
+ attrs::constant< std::string > attr2("55");
+ set1["MyStr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% = \"55\"");
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% < \"555\"");
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% > \"44\"");
+ BOOST_CHECK(f(values3));
+ }
+}
+
+// Tests for multiple expression filter
+BOOST_AUTO_TEST_CASE(multi_expression)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< int > attr2(20);
+ attrs::constant< std::string > attr3("hello");
+ attrs::constant< std::string > attr4("world");
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyStr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ set1["MyStr"] = attr4;
+ attr_values values5(set1, set2, set3);
+ values5.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10 & %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10 & %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10 and %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10 | %MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 10 | %MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% = 10 or %MyStr% = \"world\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(!f(values4));
+ BOOST_CHECK(f(values5));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyAttr% > 0 & %MyAttr% < 20 | %MyStr% = \"hello\"");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(!f(values3));
+ BOOST_CHECK(f(values4));
+ BOOST_CHECK(!f(values5));
+ }
+}
+
+// Tests for negation
+BOOST_AUTO_TEST_CASE(negation)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< int > attr2(20);
+ attrs::constant< std::string > attr3("hello");
+ attr_set set1, set2, set3;
+
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ set1["MyAttr"] = attr1;
+ attr_values values2(set1, set2, set3);
+ values2.freeze();
+
+ set1["MyAttr"] = attr2;
+ attr_values values3(set1, set2, set3);
+ values3.freeze();
+
+ set1["MyStr"] = attr3;
+ attr_values values4(set1, set2, set3);
+ values4.freeze();
+
+ // Test with presence filter
+ {
+ logging::filter f = logging::parse_filter("!%MyAttr%");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter(" ! % MyAttr % ");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("not %MyAttr%");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ }
+ {
+ logging::filter f = logging::parse_filter("!!%MyAttr%");
+ BOOST_CHECK(!f(values1));
+ BOOST_CHECK(f(values2));
+ }
+
+ // Test with relations
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% = 10)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("not ( %MyAttr% = 10 ) ");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ }
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% < 20)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ }
+
+ // Test with multiple subexpressions
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% = 20 & %MyStr% = hello)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+ {
+ logging::filter f = logging::parse_filter("!(%MyAttr% = 10 | %MyStr% = hello)");
+ BOOST_CHECK(f(values1));
+ BOOST_CHECK(!f(values2));
+ BOOST_CHECK(f(values3));
+ BOOST_CHECK(!f(values4));
+ }
+}
+
+// Tests for begins_with relation filter
+BOOST_AUTO_TEST_CASE(begins_with_relation)
+{
+ attrs::constant< std::string > attr1("abcdABCD");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% begins_with \"abcd\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% begins_with \"ABCD\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% begins_with \"efgh\"");
+ BOOST_CHECK(!f(values1));
+ }
+}
+
+// Tests for ends_with relation filter
+BOOST_AUTO_TEST_CASE(ends_with_relation)
+{
+ attrs::constant< std::string > attr1("abcdABCD");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% ends_with \"abcd\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% ends_with \"ABCD\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% ends_with \"efgh\"");
+ BOOST_CHECK(!f(values1));
+ }
+}
+
+// Tests for contains relation filter
+BOOST_AUTO_TEST_CASE(contains_relation)
+{
+ attrs::constant< std::string > attr1("abcdABCD");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"abcd\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"ABCD\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"cdAB\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% contains \"efgh\"");
+ BOOST_CHECK(!f(values1));
+ }
+}
+
+// Tests for regex matching relation filter
+BOOST_AUTO_TEST_CASE(matches_relation)
+{
+ attrs::constant< std::string > attr1("hello");
+ attrs::constant< std::string > attr2("127.0.0.1");
+ attr_set set1, set2, set3;
+
+ set1["MyStr"] = attr1;
+ set1["MyIP"] = attr2;
+ attr_values values1(set1, set2, set3);
+ values1.freeze();
+
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"h.*\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"w.*\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"\\\\d*\"");
+ BOOST_CHECK(!f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyStr% matches \"[a-z]*\"");
+ BOOST_CHECK(f(values1));
+ }
+ {
+ logging::filter f = logging::parse_filter("%MyIP% matches \"\\\\d*\\\\.\\\\d*\\\\.\\\\d*\\\\.\\\\d*\"");
+ BOOST_CHECK(f(values1));
+ }
+}
+
+namespace {
+
+class test_filter_factory :
+ public logging::filter_factory< char >
+{
+private:
+ typedef logging::filter_factory< char > base_type;
+
+public:
+ enum relation_type
+ {
+ custom,
+ exists,
+ equality,
+ inequality,
+ less,
+ greater,
+ less_or_equal,
+ greater_or_equal
+ };
+
+ typedef base_type::string_type string_type;
+
+public:
+ explicit test_filter_factory(logging::attribute_name const& name) : m_name(name), m_rel(custom), m_called(false)
+ {
+ }
+
+ void expect_relation(relation_type rel, string_type const& arg)
+ {
+ m_rel = rel;
+ m_arg = arg;
+ m_custom_rel.clear();
+ }
+
+ void expect_relation(string_type const& rel, string_type const& arg)
+ {
+ m_rel = custom;
+ m_arg = arg;
+ m_custom_rel = rel;
+ }
+
+ void check_called()
+ {
+ BOOST_CHECK(m_called);
+ m_called = false;
+ }
+
+ logging::filter on_exists_test(logging::attribute_name const& name)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, exists);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_equality_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, equality);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_inequality_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, inequality);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_less_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, less);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_greater_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, greater);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_less_or_equal_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, less_or_equal);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_greater_or_equal_relation(logging::attribute_name const& name, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, greater_or_equal);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+ logging::filter on_custom_relation(logging::attribute_name const& name, string_type const& rel, string_type const& arg)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_rel, custom);
+ BOOST_CHECK_EQUAL(m_custom_rel, rel);
+ BOOST_CHECK_EQUAL(m_arg, arg);
+ m_called = true;
+ return logging::filter();
+ }
+
+private:
+ logging::attribute_name m_name;
+ relation_type m_rel;
+ string_type m_arg;
+ string_type m_custom_rel;
+ bool m_called;
+};
+
+} // namespace
+
+// Tests for filter factory
+BOOST_AUTO_TEST_CASE(filter_factory)
+{
+ logging::attribute_name attr_name("MyCustomAttr");
+ boost::shared_ptr< test_filter_factory > factory(new test_filter_factory(attr_name));
+ logging::register_filter_factory(attr_name, factory);
+
+ BOOST_TEST_CHECKPOINT("filter_factory::exists");
+ factory->expect_relation(test_filter_factory::exists, "");
+ logging::parse_filter("%MyCustomAttr%");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "15");
+ logging::parse_filter("%MyCustomAttr% = 15");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "hello");
+ logging::parse_filter("%MyCustomAttr% = hello");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "hello");
+ logging::parse_filter("%MyCustomAttr% = \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::equality");
+ factory->expect_relation(test_filter_factory::equality, "hello\nworld");
+ logging::parse_filter("%MyCustomAttr% = \"hello\\nworld\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::inequality");
+ factory->expect_relation(test_filter_factory::inequality, "hello");
+ logging::parse_filter("%MyCustomAttr% != \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::less");
+ factory->expect_relation(test_filter_factory::less, "hello");
+ logging::parse_filter("%MyCustomAttr% < \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::greater");
+ factory->expect_relation(test_filter_factory::greater, "hello");
+ logging::parse_filter("%MyCustomAttr% > \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::less_or_equal");
+ factory->expect_relation(test_filter_factory::less_or_equal, "hello");
+ logging::parse_filter("%MyCustomAttr% <= \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::greater_or_equal");
+ factory->expect_relation(test_filter_factory::greater_or_equal, "hello");
+ logging::parse_filter("%MyCustomAttr% >= \"hello\"");
+ factory->check_called();
+
+ BOOST_TEST_CHECKPOINT("filter_factory::custom");
+ factory->expect_relation("my_relation", "hello");
+ logging::parse_filter("%MyCustomAttr% my_relation \"hello\"");
+ factory->check_called();
+}
+
+// Tests for invalid filters
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% abcd"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("(%MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr%)"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("!"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("!()"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("\"xxx\" == %MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% == \"xxx"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% === \"xxx\""), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% ! \"xxx\""), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_filter("%MyStr% %MyStr2%"), logging::parse_error);
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/test/run/util_stp_formatter_parser.cpp b/src/boost/libs/log/test/run/util_stp_formatter_parser.cpp
new file mode 100644
index 000000000..15a603678
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_stp_formatter_parser.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file setup_formatter_parser.cpp
+ * \author Andrey Semashev
+ * \date 25.08.2013
+ *
+ * \brief This header contains tests for the formatter parser.
+ */
+
+#define BOOST_TEST_MODULE setup_formatter_parser
+
+#include <string>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/setup/formatter_parser.hpp>
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
+
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/log/exceptions.hpp>
+#include <boost/log/core/record.hpp>
+#include <boost/log/core/record_view.hpp>
+#include <boost/log/attributes/constant.hpp>
+#include <boost/log/attributes/attribute_set.hpp>
+#include <boost/log/attributes/attribute_value_set.hpp>
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/expressions/formatter.hpp>
+#include "make_record.hpp"
+
+namespace logging = boost::log;
+namespace attrs = logging::attributes;
+
+typedef logging::attribute_set attr_set;
+typedef logging::attribute_value_set attr_values;
+typedef logging::record_view record_view;
+
+typedef logging::basic_formatting_ostream< char > osstream;
+typedef logging::basic_formatter< char > formatter;
+
+// Tests for simple attribute placeholders in formatters
+BOOST_AUTO_TEST_CASE(attr_placeholders)
+{
+ attrs::constant< int > attr1(10);
+ attrs::constant< std::string > attr2("hello");
+ attr_set set1;
+
+ set1["MyAttr"] = attr1;
+ set1["MyStr"] = attr2;
+
+ record_view rec = make_record_view(set1);
+
+ {
+ formatter f = logging::parse_formatter("String literal");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "String literal";
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("MyAttr: %MyAttr%, MyStr: %MyStr%");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "MyAttr: " << attr1.get() << ", MyStr: " << attr2.get();
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("MyAttr: % MyAttr %, MyStr: % MyStr %");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "MyAttr: " << attr1.get() << ", MyStr: " << attr2.get();
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("%MyAttr%%MyStr%");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << attr1.get() << attr2.get();
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+ {
+ formatter f = logging::parse_formatter("MyAttr: %MyAttr%, MissingAttr: %MissingAttr%");
+ std::string str1, str2;
+ osstream strm1(str1), strm2(str2);
+ f(rec, strm1);
+ strm2 << "MyAttr: " << attr1.get() << ", MissingAttr: ";
+ BOOST_CHECK_EQUAL(strm1.str(), strm2.str());
+ }
+}
+
+namespace {
+
+class test_formatter_factory :
+ public logging::formatter_factory< char >
+{
+private:
+ typedef logging::formatter_factory< char > base_type;
+
+public:
+ typedef base_type::string_type string_type;
+ typedef base_type::args_map args_map;
+ typedef base_type::formatter_type formatter_type;
+
+public:
+ explicit test_formatter_factory(logging::attribute_name const& name) : m_name(name), m_called(false)
+ {
+ }
+
+ void expect_args(args_map const& args)
+ {
+ m_args = args;
+ }
+
+ void check_called()
+ {
+ BOOST_CHECK(m_called);
+ m_called = false;
+ }
+
+ formatter_type create_formatter(logging::attribute_name const& name, args_map const& args)
+ {
+ BOOST_CHECK_EQUAL(m_name, name);
+ BOOST_CHECK_EQUAL(m_args.size(), args.size());
+
+ for (args_map::const_iterator it = m_args.begin(), end = m_args.end(); it != end; ++it)
+ {
+ args_map::const_iterator parsed_it = args.find(it->first);
+ if (parsed_it != args.end())
+ {
+ BOOST_TEST_CHECKPOINT(("Arg: " + it->first));
+ BOOST_CHECK_EQUAL(it->second, parsed_it->second);
+ }
+ else
+ {
+ BOOST_ERROR(("Arg not found: " + it->first));
+ }
+ }
+
+ m_called = true;
+ return formatter_type();
+ }
+
+private:
+ logging::attribute_name m_name;
+ args_map m_args;
+ bool m_called;
+};
+
+} // namespace
+
+// Tests for formatter factory
+BOOST_AUTO_TEST_CASE(formatter_factory)
+{
+ logging::attribute_name attr_name("MyCustomAttr");
+ boost::shared_ptr< test_formatter_factory > factory(new test_formatter_factory(attr_name));
+ logging::register_formatter_factory(attr_name, factory);
+
+ {
+ BOOST_TEST_CHECKPOINT("formatter 1");
+ test_formatter_factory::args_map args;
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 2");
+ test_formatter_factory::args_map args;
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr()%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 3");
+ test_formatter_factory::args_map args;
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr ( ) %");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 4");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1=10)%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 5");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: % MyCustomAttr ( param1 = 10 ) % ");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 6");
+ test_formatter_factory::args_map args;
+ args["param1"] = " 10 ";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1=\" 10 \")%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 7");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ args["param2"] = "abcd";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1 = 10, param2 = abcd)%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 8");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ args["param2"] = "abcd";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1=10,param2=abcd)%");
+ factory->check_called();
+ }
+ {
+ BOOST_TEST_CHECKPOINT("formatter 9");
+ test_formatter_factory::args_map args;
+ args["param1"] = "10";
+ args["param2"] = "abcd";
+ args["param_last"] = "-2.2";
+ factory->expect_args(args);
+ logging::parse_formatter("Hello: %MyCustomAttr(param1 = 10, param2 = \"abcd\", param_last = -2.2)%");
+ factory->check_called();
+ }
+}
+
+// Tests for invalid formatters
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("MyStr%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(=value)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param,param2)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=value,)%"), logging::parse_error);
+ BOOST_CHECK_THROW(logging::parse_formatter("%MyStr(param=value,param2)%"), logging::parse_error);
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)
diff --git a/src/boost/libs/log/test/run/util_stp_settings_parser.cpp b/src/boost/libs/log/test/run/util_stp_settings_parser.cpp
new file mode 100644
index 000000000..1027fb5bd
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_stp_settings_parser.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file setup_settings_parser.cpp
+ * \author Andrey Semashev
+ * \date 25.08.2013
+ *
+ * \brief This header contains tests for the settings parser.
+ */
+
+#define BOOST_TEST_MODULE setup_settings_parser
+
+#include <string>
+#include <sstream>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/setup/settings_parser.hpp>
+
+#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS)
+
+#include <boost/log/exceptions.hpp>
+
+namespace logging = boost::log;
+
+typedef logging::basic_settings< char > settings;
+
+// Tests for single-level settings
+BOOST_AUTO_TEST_CASE(single_level)
+{
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ settings s = logging::parse_settings(strm);
+
+ BOOST_CHECK(s.has_section("Section1"));
+ BOOST_CHECK(s.has_section("Section2"));
+ BOOST_CHECK(!s.has_section("Section3"));
+
+ BOOST_CHECK(s.has_parameter("Section1", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1", "Param2"));
+
+ BOOST_CHECK(s.has_parameter("Section2", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section2", "Param2"));
+
+ BOOST_CHECK_EQUAL(s["Section1"]["Param1"].or_default(std::string()), "Value1");
+ BOOST_CHECK_EQUAL(s["Section1"]["Param2"].or_default(std::string()), "hello, \"world\"");
+
+ BOOST_CHECK_EQUAL(s["Section2"]["Param1"].or_default(std::string()), "10");
+ BOOST_CHECK_EQUAL(s["Section2"]["Param2"].or_default(std::string()), "-2.2");
+ }
+}
+
+// Tests for multi-level settings
+BOOST_AUTO_TEST_CASE(multi_level)
+{
+ {
+ std::istringstream strm
+ (
+ " [Section1]\n"
+ "\n"
+ "Param1 = Value1 \n"
+ "Param2=\"hello, \\\"world\\\"\" \n"
+ "\n"
+ "[Section1.Subsection2] \n"
+ "\n"
+ "Param1=10\n"
+ "Param2=-2.2\n"
+ );
+ settings s = logging::parse_settings(strm);
+
+ BOOST_CHECK(s.has_section("Section1"));
+ BOOST_CHECK(s.has_section("Section1.Subsection2"));
+ BOOST_CHECK(!s.has_section("Subsection2"));
+
+ BOOST_CHECK(s.has_parameter("Section1", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1", "Param2"));
+
+ BOOST_CHECK(s.has_parameter("Section1.Subsection2", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1.Subsection2", "Param2"));
+ BOOST_CHECK(!s.has_parameter("Subsection2", "Param1"));
+ BOOST_CHECK(!s.has_parameter("Subsection2", "Param2"));
+
+ BOOST_CHECK_EQUAL(s["Section1"]["Param1"].or_default(std::string()), "Value1");
+ BOOST_CHECK_EQUAL(s["Section1"]["Param2"].or_default(std::string()), "hello, \"world\"");
+
+ BOOST_CHECK_EQUAL(s["Section1.Subsection2"]["Param1"].or_default(std::string()), "10");
+ BOOST_CHECK_EQUAL(s["Section1.Subsection2"]["Param2"].or_default(std::string()), "-2.2");
+ }
+}
+
+// Tests for comments
+BOOST_AUTO_TEST_CASE(comments)
+{
+ {
+ std::istringstream strm
+ (
+ "# Some comment\n"
+ "[ Section1 ] # another comment\n"
+ "\n"
+ "Param1 = Value1 ### yet another comment \n"
+ "Param2=\"hello, \\\"world\\\"\" # comment after a quoted string\n"
+ "\n"
+ "[ Section2 ]\n"
+ "\n"
+ "Param1=10#comment after a number\n"
+ "Param2=-2.2#comment without a terminating newline"
+ "\n"
+ "#[Section3]\n"
+ "#\n"
+ "#Param1=10#comment after a number\n"
+ "#Param2=-2.2#comment without a terminating newline"
+ );
+ settings s = logging::parse_settings(strm);
+
+ BOOST_CHECK(s.has_section("Section1"));
+ BOOST_CHECK(s.has_section("Section2"));
+ BOOST_CHECK(!s.has_section("Section3"));
+
+ BOOST_CHECK(s.has_parameter("Section1", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section1", "Param2"));
+
+ BOOST_CHECK(s.has_parameter("Section2", "Param1"));
+ BOOST_CHECK(s.has_parameter("Section2", "Param2"));
+
+ BOOST_CHECK_EQUAL(s["Section1"]["Param1"].or_default(std::string()), "Value1");
+ BOOST_CHECK_EQUAL(s["Section1"]["Param2"].or_default(std::string()), "hello, \"world\"");
+
+ BOOST_CHECK_EQUAL(s["Section2"]["Param1"].or_default(std::string()), "10");
+ BOOST_CHECK_EQUAL(s["Section2"]["Param2"].or_default(std::string()), "-2.2");
+ }
+}
+
+// Tests for invalid settings
+BOOST_AUTO_TEST_CASE(invalid)
+{
+ {
+ std::istringstream strm
+ (
+ "Param1 = Value1\n" // parameters outside sections
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1\n" // missing closing brace
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "Section1]\n" // missing opening brace
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1=xyz]\n" // invalid characters in the section name
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1# hello?]\n" // invalid characters in the section name
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "(Section1)\n" // invalid braces
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 =\n" // no parameter value
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1\n" // no parameter value
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 = Value1\n"
+ "Param2 = \"hello, \\\"world\\\"\n" // unterminated quote
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+ {
+ std::istringstream strm
+ (
+ "[Section1]\n"
+ "\n"
+ "Param1 = Value1 Value2\n" // multi-word value
+ "Param2 = \"hello, \\\"world\\\"\"\n"
+ "\n"
+ "[Section2]\n"
+ "\n"
+ "Param1 = 10\n"
+ "Param2 = -2.2\n"
+ );
+ BOOST_CHECK_THROW(logging::parse_settings(strm), logging::parse_error);
+ }
+}
+
+#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS)
diff --git a/src/boost/libs/log/test/run/util_string_literal.cpp b/src/boost/libs/log/test/run/util_string_literal.cpp
new file mode 100644
index 000000000..356f87373
--- /dev/null
+++ b/src/boost/libs/log/test/run/util_string_literal.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright Andrey Semashev 2007 - 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)
+ */
+/*!
+ * \file util_string_literal.cpp
+ * \author Andrey Semashev
+ * \date 09.01.2009
+ *
+ * \brief This header contains tests for the string literals wrapper.
+ */
+
+#define BOOST_TEST_MODULE util_string_literal
+
+#include <cwchar>
+#include <cstring>
+#include <set>
+#include <memory>
+#include <string>
+#include <algorithm>
+#include <boost/test/unit_test.hpp>
+#include <boost/log/utility/string_literal.hpp>
+
+namespace logging = boost::log;
+
+// Construction tests
+BOOST_AUTO_TEST_CASE(string_literal_ctors)
+{
+ // Default construction
+ {
+ logging::string_literal lit;
+ BOOST_CHECK(lit.empty());
+ BOOST_CHECK_EQUAL(lit.size(), 0UL);
+ BOOST_CHECK(lit.c_str() != NULL);
+ }
+
+ // Construction from a literal
+ {
+ logging::string_literal lit = "abcd";
+ BOOST_CHECK(!lit.empty());
+ BOOST_CHECK_EQUAL(lit.size(), 4UL);
+ BOOST_CHECK(std::strcmp(lit.c_str(), "abcd") == 0);
+ }
+
+#ifdef BOOST_LOG_USE_WCHAR_T
+ // Copying
+ {
+ logging::wstring_literal lit1 = L"Hello";
+ logging::wstring_literal lit2 = lit1;
+ BOOST_CHECK(std::wcscmp(lit2.c_str(), L"Hello") == 0);
+ BOOST_CHECK(std::wcscmp(lit1.c_str(), lit2.c_str()) == 0);
+ }
+
+ // Generator functions
+ {
+ logging::string_literal lit1 = logging::str_literal("Wow!");
+ BOOST_CHECK(std::strcmp(lit1.c_str(), "Wow!") == 0);
+
+ logging::wstring_literal lit2 = logging::str_literal(L"Wow!");
+ BOOST_CHECK(std::wcscmp(lit2.c_str(), L"Wow!") == 0);
+ }
+#endif
+}
+
+// Assignment tests
+BOOST_AUTO_TEST_CASE(string_literal_assignment)
+{
+ // operator=
+ {
+ logging::string_literal lit;
+ BOOST_CHECK(lit.empty());
+
+ lit = "Hello";
+ BOOST_CHECK(std::strcmp(lit.c_str(), "Hello") == 0);
+
+ logging::string_literal empty_lit;
+ lit = empty_lit;
+ BOOST_CHECK(lit.empty());
+
+ logging::string_literal filled_lit = "Some string";
+ lit = filled_lit;
+ BOOST_CHECK(std::strcmp(lit.c_str(), filled_lit.c_str()) == 0);
+ }
+
+ // assign
+ {
+ logging::string_literal lit;
+ BOOST_CHECK(lit.empty());
+
+ lit.assign("Hello");
+ BOOST_CHECK(std::strcmp(lit.c_str(), "Hello") == 0);
+
+ logging::string_literal empty_lit;
+ lit.assign(empty_lit);
+ BOOST_CHECK(lit.empty());
+
+ logging::string_literal filled_lit = "Some string";
+ lit.assign(filled_lit);
+ BOOST_CHECK(std::strcmp(lit.c_str(), filled_lit.c_str()) == 0);
+ }
+}
+
+// Comparison tests
+BOOST_AUTO_TEST_CASE(string_literal_comparison)
+{
+ logging::string_literal lit;
+ BOOST_CHECK(lit == "");
+
+ lit = "abcdefg";
+ BOOST_CHECK(lit == "abcdefg");
+ BOOST_CHECK(lit != "xyz");
+ BOOST_CHECK(lit != "aBcDeFg");
+
+ logging::string_literal lit2 = "Yo!";
+ BOOST_CHECK(lit != lit2);
+ lit2 = "abcdefg";
+ BOOST_CHECK(lit == lit2);
+
+ BOOST_CHECK(lit.compare(lit2) == 0);
+ BOOST_CHECK(lit.compare("aaaaa") > 0);
+ BOOST_CHECK(lit.compare("zzzzzzzz") < 0);
+ BOOST_CHECK(lit.compare("zbcdefg") < 0);
+
+ BOOST_CHECK(lit.compare(2, 3, "cde") == 0);
+ BOOST_CHECK(lit.compare(2, 3, "cdefgh", 3) == 0);
+
+ // Check ordering
+ std::set< logging::string_literal > lit_set;
+ lit_set.insert(logging::str_literal("abc"));
+ lit_set.insert(logging::str_literal("def"));
+ lit_set.insert(logging::str_literal("aaa"));
+ lit_set.insert(logging::str_literal("abcd"));
+ lit_set.insert(logging::str_literal("zz"));
+
+ std::set< std::string > str_set;
+ str_set.insert(logging::str_literal("abc").str());
+ str_set.insert(logging::str_literal("def").str());
+ str_set.insert(logging::str_literal("aaa").str());
+ str_set.insert(logging::str_literal("abcd").str());
+ str_set.insert(logging::str_literal("zz").str());
+
+ BOOST_CHECK_EQUAL_COLLECTIONS(lit_set.begin(), lit_set.end(), str_set.begin(), str_set.end());
+}
+
+// Iteration tests
+BOOST_AUTO_TEST_CASE(string_literal_iteration)
+{
+ std::string str;
+ logging::string_literal lit = "abcdefg";
+
+ std::copy(lit.begin(), lit.end(), std::back_inserter(str));
+ BOOST_CHECK(str == "abcdefg");
+
+ str.clear();
+ std::copy(lit.rbegin(), lit.rend(), std::back_inserter(str));
+ BOOST_CHECK(str == "gfedcba");
+}
+
+// Subscript tests
+BOOST_AUTO_TEST_CASE(string_literal_indexing)
+{
+ logging::string_literal lit = "abcdefg";
+
+ BOOST_CHECK_EQUAL(lit[2], 'c');
+ BOOST_CHECK_EQUAL(lit.at(3), 'd');
+
+ BOOST_CHECK_THROW(lit.at(100), std::exception);
+}
+
+// Clearing tests
+BOOST_AUTO_TEST_CASE(string_literal_clear)
+{
+ logging::string_literal lit = "yo-ho-ho";
+ BOOST_CHECK(!lit.empty());
+
+ lit.clear();
+ BOOST_CHECK(lit.empty());
+ BOOST_CHECK_EQUAL(lit, "");
+}
+
+// Swapping tests
+BOOST_AUTO_TEST_CASE(string_literal_swap)
+{
+ logging::string_literal lit1 = "yo-ho-ho";
+ logging::string_literal lit2 = "hello";
+
+ lit1.swap(lit2);
+ BOOST_CHECK_EQUAL(lit1, "hello");
+ BOOST_CHECK_EQUAL(lit2, "yo-ho-ho");
+
+ swap(lit1, lit2);
+ BOOST_CHECK_EQUAL(lit2, "hello");
+ BOOST_CHECK_EQUAL(lit1, "yo-ho-ho");
+}
+
+// STL strings acquisition tests
+BOOST_AUTO_TEST_CASE(string_literal_str)
+{
+ logging::string_literal lit = "yo-ho-ho";
+ std::string str = lit.str();
+ BOOST_CHECK_EQUAL(str, "yo-ho-ho");
+ BOOST_CHECK_EQUAL(lit, str);
+}
+
+// Substring extraction tests
+BOOST_AUTO_TEST_CASE(string_literal_copy)
+{
+ logging::string_literal lit = "yo-ho-ho";
+ char t[32] = { 0 };
+
+ BOOST_CHECK_EQUAL(lit.copy(t, 2), 2UL);
+ BOOST_CHECK(std::strcmp(t, "yo") == 0);
+
+ BOOST_CHECK_EQUAL(lit.copy(t, 4, 2), 4UL);
+ BOOST_CHECK(std::strcmp(t, "-ho-") == 0);
+
+ BOOST_CHECK_EQUAL(lit.copy(t, 100), 8UL);
+ BOOST_CHECK(std::strcmp(t, "yo-ho-ho") == 0);
+}