$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: john.groups_at_[hidden]
Date: 2007-11-07 20:52:01
Author: jtorjo
Date: 2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
New Revision: 40917
URL: http://svn.boost.org/trac/boost/changeset/40917
Log:
[logging]
v0.10.11, 8 nov 2007
- added tss_resource_once_init and correspondent filter/logger class
- added scenario.hpp - not tested yet
Added:
   sandbox/logging/boost/logging/scenario.hpp   (contents, props changed)
Text files modified: 
   sandbox/logging/boost/logging/defaults.hpp                            |     2                                         
   sandbox/logging/boost/logging/detail/raw_doc/changelog.hpp            |     4 +                                       
   sandbox/logging/boost/logging/detail/ts/ts_resource.hpp               |    80 ++++++++++++++++++++++++++++++++++++++- 
   sandbox/logging/boost/logging/filter.hpp                              |    26 +++++++++++--                           
   sandbox/logging/boost/logging/format_fwd.hpp                          |     3 +                                       
   sandbox/logging/boost/logging/level.hpp                               |    21 +++++++++-                              
   sandbox/logging/lib/logging/internal/vc8/loggingvc8/loggingvc8.vcproj |    11 ++---                                   
   7 files changed, 128 insertions(+), 19 deletions(-)
Modified: sandbox/logging/boost/logging/defaults.hpp
==============================================================================
--- sandbox/logging/boost/logging/defaults.hpp	(original)
+++ sandbox/logging/boost/logging/defaults.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -85,7 +85,7 @@
     namespace level {
         struct holder_no_ts ;
         struct holder_ts ;
-        struct holder_tss_with_cache ;
+        template<int> struct holder_tss_with_cache ;
     }
 
     namespace locker {
Modified: sandbox/logging/boost/logging/detail/raw_doc/changelog.hpp
==============================================================================
--- sandbox/logging/boost/logging/detail/raw_doc/changelog.hpp	(original)
+++ sandbox/logging/boost/logging/detail/raw_doc/changelog.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -1,7 +1,9 @@
 /** 
 @page page_changelog Changelog
 
-v0.10.10, 6 nov 2007
+v0.10.11, 8 nov 2007
+- added tss_resource_once_init and correspondent filter/logger class
+- added scenario.hpp - not tested yet
 - added and tested thread-safety (ts_write/on_dedicated_thread) for logger_format_write<>
 - added 2 more scenarios: ts_loger_one_filter.cpp and ded_loger_one_filter.cpp
 
Modified: sandbox/logging/boost/logging/detail/ts/ts_resource.hpp
==============================================================================
--- sandbox/logging/boost/logging/detail/ts/ts_resource.hpp	(original)
+++ sandbox/logging/boost/logging/detail/ts/ts_resource.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -27,6 +27,9 @@
 #include <boost/assert.hpp>
 
 namespace boost { namespace logging { 
+
+
+
     
 /** 
     @brief Contains implementations of locker objects. Such a locker can lock data for read or write.
@@ -117,7 +120,7 @@
         @sa default_cache_millis how many secs to cache the data. By default, 5
     */
     template<class type, int default_cache_secs = 5, class mutex = boost::logging::threading::mutex > struct tss_resource_with_cache {
-        typedef tss_resource_with_cache<type, default_cache_secs> self_type;
+        typedef tss_resource_with_cache<type, default_cache_secs, mutex> self_type;
 
     private:
         struct value_and_time {
@@ -179,8 +182,6 @@
             const type* operator->() { return &use(); }
         };
 
-
-
     private:
         mutable tss_value<value_and_time> m_cache;
         type m_val;
@@ -188,6 +189,79 @@
         int m_cache_secs;
     };
 
+
+
+
+    /** 
+        Locks a resource, and uses TSS. 
+
+        The resource can be initialized once, at any time, no matter how many threads.
+        Once the resource is initialized (basically, someone used resource::write), that is <b>the final value</b>
+
+        All other threads will use and cached the initialized value.
+
+        @sa locker
+        @sa default_cache_millis how many secs to cache the data. By default, 5
+    */
+    template<class type, class mutex = boost::logging::threading::mutex > struct tss_resource_once_init {
+        typedef tss_resource_once_init<type, mutex> self_type;
+
+    private:
+        struct cached_value {
+            cached_value(const type & val = type() ) : val(val), is_cached(false) {}
+            type val;
+            bool is_cached;
+        };
+
+    public:
+        tss_resource_once_init(const type& val = type() ) : m_val(val), m_cache(val), m_initialized(false) {}
+
+        struct read;
+        struct write;
+        friend struct read;
+        friend struct write;
+
+        struct write {
+            type & val;
+            typename mutex::scoped_lock locker;
+            write(self_type & self) : val(self.m_val), locker(self.m_cs) {
+                self.m_initialized = true;
+            }
+            ~write() {
+            }
+
+            type & use() { return val ; }
+            type* operator->() { return &use(); }
+        };
+
+        struct read {
+            const type *val ;
+            read(const self_type & self) {
+                cached_value & cached = *(self.m_cache);
+                val = &cached.val;
+                if ( !cached.is_cached) {
+                    mutex::scoped_lock lk(self.m_cs);
+                    if ( self.m_initialized) {
+                        cached.val = self.m_val;
+                        cached.is_cached = true;
+                    }
+                }
+            }
+            ~read() {
+            }
+
+            const type & use() { return *val ; }
+            const type* operator->() { return &use(); }
+        };
+
+    private:
+        type m_val;
+        mutable tss_value<cached_value> m_cache;
+        mutable mutex m_cs;
+        bool m_initialized;
+    };
+
+
 #endif
 
 }}}
Modified: sandbox/logging/boost/logging/filter.hpp
==============================================================================
--- sandbox/logging/boost/logging/filter.hpp	(original)
+++ sandbox/logging/boost/logging/filter.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -160,7 +160,7 @@
 #ifndef BOOST_LOG_NO_TSS
 
 /** 
-    Uses TLS (Thread Local Storage) to find out if a filter is enabled or not. It caches the current "is_enabled" on each thread.
+    Uses TSS (Thread Specific Storage) to find out if a filter is enabled or not. It caches the current "is_enabled" on each thread.
     Then, at a given period, it retrieves the real "is_enabled".
 
     @remarks
@@ -168,10 +168,10 @@
     Another implementation can be done, which could be faster - where you retrieve the "is_enabled" each X calls on a given thread
     (like, every 20 calls on a given thread)
 */
-struct use_tss_with_cache {
-    typedef locker::tss_resource_with_cache<bool> data;
+template<int default_cache_secs = 5> struct use_tss_with_cache {
+    typedef locker::tss_resource_with_cache<bool,default_cache_secs> data;
 
-    use_tss_with_cache(int cache_secs) : m_enabled(true, cache_secs) {}
+    use_tss_with_cache(int cache_secs = default_cache_secs) : m_enabled(true, cache_secs) {}
     bool is_enabled() const { 
         data::read enabled(m_enabled);
         return enabled.use(); 
@@ -184,6 +184,24 @@
     data m_enabled;
 };
 
+
+struct use_tss_once_init {
+    typedef locker::tss_resource_once_init<bool> data;
+
+    use_tss_once_init() : m_enabled(true) {}
+    bool is_enabled() const { 
+        data::read enabled(m_enabled);
+        return enabled.use(); 
+    }
+    void set_enabled(bool enabled) { 
+        data::write cur(m_enabled);
+        cur.use() = enabled; 
+    }
+private:
+    data m_enabled;
+};
+
+
 #endif // #ifndef BOOST_LOG_NO_TSS
 
 
Modified: sandbox/logging/boost/logging/format_fwd.hpp
==============================================================================
--- sandbox/logging/boost/logging/format_fwd.hpp	(original)
+++ sandbox/logging/boost/logging/format_fwd.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -75,5 +75,8 @@
 
 }}
 
+
+//#include <boost/logging/scenario.hpp>
+
 #endif
 
Modified: sandbox/logging/boost/logging/level.hpp
==============================================================================
--- sandbox/logging/boost/logging/level.hpp	(original)
+++ sandbox/logging/boost/logging/level.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -127,10 +127,10 @@
         Uses TLS (Thread Local Storage) to find out if a level is enabled or not. It caches the current "is_enabled" on each thread.
         Then, at a given period, it retrieves the real "level".
     */
-    struct holder_tss_with_cache {
-        typedef locker::tss_resource_with_cache<type> data;
+    template<int default_cache_secs = 5> struct holder_tss_with_cache {
+        typedef locker::tss_resource_with_cache<type, default_cache_secs> data;
 
-        holder_tss_with_cache(int cache_millis, type default_level = enable_all) : m_level(default_level, cache_millis) {}
+        holder_tss_with_cache(int cache_secs = default_cache_secs, type default_level = enable_all) : m_level(default_level, cache_secs) {}
         bool is_enabled(type test_level) const { 
             data::read cur_level(m_level);
             return test_level >= cur_level.use(); 
@@ -143,6 +143,21 @@
         data m_level;
     };
 
+    struct holder_tss_once_init {
+        typedef locker::tss_resource_once_init<type> data;
+
+        holder_tss_once_init(type default_level = enable_all) : m_level(default_level) {}
+        bool is_enabled(type test_level) const { 
+            data::read cur_level(m_level);
+            return test_level >= cur_level.use(); 
+        }
+        void set_enabled(type level) {
+            data::write cur_level(m_level);
+            cur_level.use() = level;
+        }
+    private:
+        data m_level;
+    };
 #endif
 
 
Added: sandbox/logging/boost/logging/scenario.hpp
==============================================================================
--- (empty file)
+++ sandbox/logging/boost/logging/scenario.hpp	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -0,0 +1,292 @@
+// Template.hpp
+
+// Boost Logging library
+//
+// Author: John Torjo, www.torjo.com
+//
+// Copyright (C) 2007 John Torjo (see www.torjo.com for email)
+//
+// Distributed under the Boost Software License, Version 1.0.
+//    (See accompanying file LICENSE_1_0.txt or copy at
+//          http://www.boost.org/LICENSE_1_0.txt)
+//
+// See http://www.boost.org for updates, documentation, and revision history.
+// See http://www.torjo.com/log2/ for more details
+
+
+#ifndef JT28092007_TEMPLATE_HPP_DEFINED
+#define JT28092007_TEMPLATE_HPP_DEFINED
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+#include <boost/logging/detail/fwd.hpp>
+
+namespace boost { namespace logging {
+
+
+namespace filter {
+    template<int> struct use_tss_with_cache ;
+    struct no_ts ;
+    struct ts ;
+    struct use_tss_once_init ;
+};
+
+namespace level {
+    template<int> struct holder_tss_with_cache ;
+    struct holder_tss_once_init ;
+    struct holder_ts;
+    struct holder_no_ts ;
+}
+
+
+/** 
+    @brief Use it when you have a specific scenario, and want the best logger/filter classes for the scenario. Check out scenario::usage 
+*/
+namespace scenario {
+
+/** 
+    @brief Find out the right logger/filter, based on how your application will use the loggers and filters
+
+    First, don't forget to \n <tt>use namespace boost::logging::scenario::usage;</tt>
+*/
+namespace usage {
+
+    /** @brief Filter usage settings : filter_::change and filter_::level
+    */
+    namespace filter_ {
+        /** @brief When does the filter change? */
+        namespace change {
+            /** @brief Optimize for %often %change. Does per-thread caching. At a given period, it re-synchronizes. 
+                
+                This is the default, for a multi-threaded application.
+
+                @param cache_period_secs At what period should we re-syncronize
+            */
+            template<int cache_period_secs = 5> struct often {};
+
+            /** @brief Set only once, when there's only one thread running - thus, you don't need to worry about thread-syncronizing */
+            struct set_once_when_one_thread {};
+
+            /** @brief Set only once, when there could be multiple thread running. 
+            
+            We automatically implement a strategy to check if the filter/logger has been initialized, and when it's done, we cache
+            the result on every thread */
+            struct set_once_when_multiple_threads {};
+
+            /** @brief This is always accurate. However, it's the slowest too.
+
+            In case of multiple threads, it always locks the logger/filter before accessing it. 
+
+            Not recommended, you should usually go with another strategy (often, set_once_when_one_thread or set_once_when_multiple_threads)
+            */
+            struct always_accurate {};
+
+            /** @brief Single threading. It doesn't matter when/how %often the filter/logger changes. 
+
+                This is the default, for a single-threaded application.
+            */
+            struct single_thread {};
+
+#ifdef BOOST_HAS_THREADS
+            typedef often<> default_;
+#else
+            typedef single_thread default_;
+#endif
+        };
+
+        /** @brief What's our "level" policy? */
+        namespace level {
+            /** @brief not using levels (default) */
+            struct no_levels {};
+            /** @brief using levels */
+            struct use_levels {};
+
+            typedef no_levels default_;
+        };
+    }
+
+    /** @brief Logger %usage settings : logger_::change and logger_::favor
+    */
+    namespace logger_ {
+        /** @brief When does the logger change, that is, how often do you manipulate it? 
+        
+        Note that using the log does not mean changing it. 
+        Manipulation means invoking non-const functions on the logger, like 
+        adding/removing formatters/destinations for instance.
+        */
+        namespace change {
+            /** @brief Optimize for often change. Does per-thread caching. At a given period, it re-synchronizes. 
+                
+                This is the default, for a multi-threaded application.
+
+                @param cache_period_secs At what period should we re-syncronize
+            */
+            template<int cache_period_secs = 5> struct often {};
+
+            /** @brief Set only once, when there's only one thread running - thus, you don't need to worry about thread-syncronizing */
+            struct set_once_when_one_thread {};
+
+            /** @brief Set only once, when there could be multiple thread running. 
+            
+            We automatically implement a strategy to check if the filter/logger has been initialized, and when it's done, we cache
+            the result on every thread */
+            struct set_once_when_multiple_threads {};
+
+            /** @brief This is always accurate. However, it's the slowest too.
+
+            In case of multiple threads, it always locks the logger/filter before accessing it. 
+
+            Not recommended, you should usually go with another strategy (often, set_once_when_one_thread or set_once_when_multiple_threads)
+            */
+            struct always_accurate {};
+
+            /** @brief Single threading. It doesn't matter when/how often the filter/logger changes. 
+            
+                This is the default, for a single-threaded application.
+            */
+            struct single_thread {};
+
+#ifdef BOOST_HAS_THREADS
+            typedef often<> default_;
+#else
+            typedef single_thread default_;
+#endif
+        };
+
+        /** @brief When logging, what should we %favor? */
+        namespace favor {
+            /** @brief This will favor speed (logging will happen on a dedicated thread). The only problem you could have is if the application crashes.
+
+                In this case, on Windows, the rest of the application will continue, and any non-flushed log message will be flushed.
+
+                On POSIX, this may not be the case.
+            */
+            struct speed {};
+
+            /** @brief all messages will be logged 
+            
+            This is the default
+            */
+            struct correctness {};
+
+            typedef correctness default_;
+        };
+    }
+
+
+
+    namespace detail_find_filter {
+        namespace level = ::boost::logging::scenario::usage::filter_::level;
+        namespace change = ::boost::logging::scenario::usage::filter_::change;
+
+        //////// use levels
+
+        template<class change_> struct find_filter_use_levels {};
+        
+        template<int period_ms> struct find_filter_use_levels< change::often<period_ms> > {
+            typedef ::boost::logging::level::holder_tss_with_cache<period_ms> type;
+        };
+
+        template<> struct find_filter_use_levels< change::set_once_when_one_thread > {
+            typedef ::boost::logging::level::holder_no_ts type;
+        };
+
+        template<> struct find_filter_use_levels< change::set_once_when_multiple_threads > {
+            typedef ::boost::logging::level::holder_tss_once_init type;
+        };
+
+        template<> struct find_filter_use_levels< change::always_accurate > {
+            typedef ::boost::logging::level::holder_ts type;
+        };
+
+        template<> struct find_filter_use_levels< change::single_thread > {
+            typedef ::boost::logging::level::holder_no_ts type;
+        };
+
+
+
+        //////// no levels
+
+        template<class change_> struct find_filter_no_levels {};
+        
+        template<int period_ms> struct find_filter_no_levels< change::often<period_ms> > {
+            typedef ::boost::logging::filter::use_tss_with_cache<period_ms> type;
+        };
+
+        template<> struct find_filter_no_levels< change::set_once_when_one_thread > {
+            typedef ::boost::logging::filter::no_ts type;
+        };
+
+        template<> struct find_filter_no_levels< change::set_once_when_multiple_threads > {
+            typedef ::boost::logging::filter::use_tss_once_init type;
+        };
+
+        template<> struct find_filter_no_levels< change::always_accurate > {
+            typedef ::boost::logging::filter::ts type;
+        };
+
+        template<> struct find_filter_no_levels< change::single_thread > {
+            typedef ::boost::logging::filter::no_ts type;
+        };
+
+
+
+        template<class change_, class level_> struct find_filter {
+            // no levels
+            typedef typename find_filter_no_levels<change_>::type type;
+        };
+
+        template<class change_> struct find_filter<change_, level::use_levels> {
+            typedef typename find_filter_use_levels<change_>::type type;
+        };
+
+    }
+
+
+    namespace detail_find_logger {
+        namespace favor = ::boost::logging::scenario::usage::logger_::favor;
+        namespace change = ::boost::logging::scenario::usage::logger_::change;
+    }
+
+    /** 
+        @brief Finds a filter class and a logger class, based on your specific scenario
+
+        @param filter_change (optional) How does the %filter change? Any of the classes in the filter_::change namespace
+        @param filter_level_ (optional) Does our %filter %use levels? Any of the classes in the filter_::level namespace
+        @param logger_change (optional) How does our %logger change? Any of the classes in the logger_::change namespace
+        @param logger_favor (optional) What does the %logger favor? Any of the classes in the logger_::favor namespace
+    */
+    template<
+        class filter_change = default_,
+        class filter_level = default_, 
+        class logger_change = default_,
+        class logger_favor = default_>
+    struct use {
+
+        typedef typename use_default<filter_change, filter_::change::default_ >::type filter_change_type;
+        typedef typename use_default<filter_level, filter_::level::default_ >::type filter_level_type;
+
+        typedef typename detail_find_filter::find_filter<filter_change_type, filter_level_type>::type filter;
+
+
+//        typedef ... logger;
+  //      typedef ... filter;
+    };
+}
+
+/** 
+    @brief Find out the right logger/filter, based on thread-safety of logger(s)/filter(s)
+
+    First, don't forget to <tt>use namespace boost::logging::scenario::ts;</tt>
+*/
+namespace ts {
+}
+
+}
+
+}}
+
+#endif
+
Modified: sandbox/logging/lib/logging/internal/vc8/loggingvc8/loggingvc8.vcproj
==============================================================================
--- sandbox/logging/lib/logging/internal/vc8/loggingvc8/loggingvc8.vcproj	(original)
+++ sandbox/logging/lib/logging/internal/vc8/loggingvc8/loggingvc8.vcproj	2007-11-07 20:52:00 EST (Wed, 07 Nov 2007)
@@ -630,6 +630,10 @@
 				>
                         </File>
                         <File
+				RelativePath="..\..\..\..\..\boost\logging\scenario.hpp"
+				>
+			</File>
+			<File
                                 RelativePath="..\..\..\..\..\boost\logging\detail\sink.hpp"
 				>
                         </File>
@@ -996,13 +1000,6 @@
                         <File
                                 RelativePath="..\..\..\samples\scenarios\ts_loger_one_filter.cpp"
 				>
-				<FileConfiguration
-					Name="Test|Win32"
-					>
-					<Tool
-						Name="VCCLCompilerTool"
-					/>
-				</FileConfiguration>
                         </File>
                 </Filter>
         </Files>