text:
#ifndef litwindow_logger_h__151208
#define litwindow_logger_h__151208

/// define this to use boost::mutex
#define LITWINDOW_LOGGER_MUTEX
/// define this to use hashmap for basic_tag
#define LITWINDOW_LOGGER_HASHMAP

#ifdef LWBASE_EXPORTS
#define LITWINDOW_LOGGER_EXPORTS
#elif defined(LITWINDOW_ALL_DYN_LINK) || defined(LWBASE_DYN_LINK)
#define LITWINDOW_LOGGER_DYN_LINK
#endif

#ifdef LITWINDOW_LOGGER_EXPORTS
#define LITWINDOW_LOGGER_API _declspec(dllexport)
#elif defined(LITWINDOW_LOGGER_DYN_LINK)
#define LITWINDOW_LOGGER_API _declspec(dllimport)
#else
#define LITWINDOW_LOGGER_API
#endif

#include <iostream>

#ifdef LITWINDOW_LOGGER_HASHMAP
#include <hash_map>
#endif
#ifdef LITWINDOW_LOGGER_MUTEX
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/tss.hpp>

#endif
#include <boost/lexical_cast.hpp>

#ifdef max
#undef max
#endif
#include <limits>

namespace litwindow {
	/// encapsules the litwindow logging library
	namespace logger {

		//---------------------------------------------------------------------------------------------
		//
		namespace details {
			static const size_t word_alignment = sizeof (unsigned long);
			template <typename _Val>
			inline _Val *aligned_ptr(void *p)
			{
				char *ptr=reinterpret_cast<char*>(p);
				size_t misalign= (ptr-reinterpret_cast<char*>(0)) % word_alignment;
				return reinterpret_cast<_Val*>( ptr + (misalign ? word_alignment-misalign : 0));
			}
			template <typename _Val>
			inline const _Val *aligned_ptr(const void *p)
			{
				const char *ptr=reinterpret_cast<const char*>(p);
				size_t misalign= (ptr-reinterpret_cast<const char*>(0)) % word_alignment;
				return reinterpret_cast<const _Val*>( ptr + (misalign ? word_alignment-misalign : 0));
			}
			template <typename _Elem>
			struct defaults
			{
				typedef size_t index_type;
				typedef std::basic_string<_Elem> string_type;
#if defined(LITWINDOW_LOGGER_HASHMAP)
				typedef stdext::hash_map<string_type, index_type> basic_name_map;
#else
				typedef map<string_type, index_type> basic_name_map;
#endif
#if defined(_MT) && defined(LITWINDOW_LOGGER_MUTEX)
				typedef boost::mutex mutex_type;
				template <typename _L>
				struct mutex_lock_type:public boost::lock_guard<_L>
				{
					mutex_lock_type(_L &l):boost::lock_guard<_L>(l) {}
				};
#else
				struct mutex_type
				{
					void lock() {}
					void unlock() {}
				};
				template <typename _Lock>
				struct mutex_lock_type
				{
					mutex_lock_type(_Lock &){}
				};
#endif
			};
			template <typename _Elem>
			inline _Elem sep();
			template<>
			inline char sep<char>() { return '\t'; }
			template <>
			inline wchar_t sep<wchar_t>() { return L'\t'; }

		}

		//---------------------------------------------------------------------------------------------
		//
		///\brief Small, lightweight class containing strings as tags for basic_component, basic_level, basic_topic, basic_instance.
		///
		/// The strings are stored in a global string table and associated with a unique numerical value.
		/// Every instance of basic_tag searches the global string table for its string parameter.
		/// If the string is contained in the string table, it will be reused. Otherwise it will be inserted.
		/// Once inserted it will never be removed.
		///
		/// The indexes are guaranteed to be stable during one application run.
		/// \threadsafe
		template <typename _Elem,
			typename _Index=typename details::defaults<_Elem>::index_type,
			typename _Lock=typename details::defaults<_Elem>::mutex_type,
			typename _Container=typename details::defaults<_Elem>::basic_name_map >
		class basic_tag
		{
			typedef basic_tag<_Elem, _Index, _Lock, _Container> _Myt;
			typedef _Container container_type;
			typedef typename container_type::key_type name_type;
			typedef std::vector<typename container_type::const_iterator> index_container_type;
		public:
			typedef _Index index_type;

			typedef _Index const_iterator;
			/// Default constructs an empty tag
			basic_tag():m_index(std::numeric_limits<index_type>::max()){}
			/// Construct from a pointer to char
			basic_tag(const _Elem *n)
			{
				set(name_type(n));
			}
			/// Construct from a string, usually a basic_string<_Elem>
			basic_tag(const name_type &n)
			{
				set(n);
			}
			/// Construct from an index.
			///
			///\throw an error if the index does not exist.
			basic_tag(_Index idx)
			{
				set(idx);
			}

			///\return this names index
			_Index index() const { return m_index; }
			///\return this names string
			const name_type &str() const { return *find_by_index(index()); }
			static _Elem tag_sep() { return _Elem(0); }
			///\name Operators
			//{
			bool operator== (const _Myt &right) const   {return index()==right.index();}
			bool operator!= (const _Myt &right) const   {return !operator==(right);}
			bool operator<  (const _Myt &right) const   {return str()<right.str();}
			bool operator<= (const _Myt &right) const   {return str()<=right.str();}
			bool operator>  (const _Myt &right) const   {return str()>right.str();}
			bool operator>= (const _Myt &right) const   {return str()>=right.str();}
			_Myt operator+  (const _Myt &right) const   {return _Myt(str()+tag_sep()+right.str());}
			//}
			///\return an iterator pointing to the beginning of the string table
			static const_iterator begin()
			{
				return const_iterator(0);
			}
			///\return an index beyond the last valid index
			static const_iterator end()
			{
				return const_iterator(size());
			}
		protected:
			void set(const name_type &n)
			{
				typename container_type::const_iterator i=find_name(n);
				m_index=i->second;
			}
			static _Lock LITWINDOW_LOGGER_API &g_lock()
			{
				static _Lock theLock;
				return theLock;
			}
			static typename container_type::iterator find_name(const name_type &n)
			{
				details::defaults<_Elem>::mutex_lock_type<_Lock> lock(g_lock());
				container_type &c(name_container());
				std::pair<typename container_type::iterator, bool> i=c.insert(std::make_pair(n, c.size()));
				if (i.second) {
					index_container().insert(index_container().end(), 1, i.first);
				}
				return i.first;
			}

			void set(_Index idx)
			{
				const name_type *n=find_by_index(idx);
				if (n)
					m_index=idx;
				else
					throw std::out_of_range("logger::basic_name - no name registered for index");
			}
			static const name_type *find_by_index(_Index idx)
			{
				const name_type *rc=0;
				g_lock().lock();
				if (idx<index_container().size()) {
					rc=&index_container()[idx]->first;
				}
				g_lock().unlock();
				return rc;
			}
			static _Index size()
			{
				_Index rc;
				g_lock().lock();
				rc=index_container().size();
				g_lock().unlock();
				return rc;
			}
			static container_type LITWINDOW_LOGGER_API &name_container()
			{
				static container_type theNames;
				return theNames;
			}
			static index_container_type LITWINDOW_LOGGER_API &index_container()
			{
				static index_container_type theIndex;
				return theIndex;
			}
			index_type          m_index;
		};

		template <>
		char basic_tag<char>::tag_sep() { return '/'; }
		template <>
		wchar_t basic_tag<wchar_t>::tag_sep() { return L'/'; }

		template <typename _Elem>
		std::basic_ostream<_Elem> &operator<<(std::basic_ostream<_Elem> &o, const basic_tag<_Elem> &n)
		{
			return o << n.str();
		}
		typedef basic_tag<char> tag;
		typedef basic_tag<wchar_t> wtag;

		//---------------------------------------------------------------------------------------------
		/// basic_instance records information about the instance of a log object
		/// It stores the thread id and a unique counter. When transferred between processes or machines
		/// the transfer mechanism adds the process id and, if applicable, the machine id.
		template <typename _Elem>
		class basic_instance
		{
		public:
			struct thread_process_id
			{
				std::basic_string<_Elem> m_name;
				unsigned int	m_thread_id;
				unsigned int	m_process_id;
			};
			static const thread_process_id *get_thread_process_id() { return 0; }
			basic_instance()
				:m_instance(next_instance_value())
				,m_source_id(get_thread_process_id())
			{}
			explicit basic_instance(unsigned int i)
				:m_instance(i){}
			unsigned int	index() const { return m_instance; }
			std::basic_string<_Elem> str() const { return boost::lexical_cast<std::basic_string<_Elem> >(index()); }
		private:
			static int next_instance_value()
			{
				static int g_instance=0;
				return g_instance++;
			}
			unsigned int m_instance;
			const thread_process_id *m_source_id;
		};

		template <typename Category, typename _Elem>
		class basic_tag_with_category:public basic_tag<_Elem>
		{
			typedef basic_tag<_Elem> inherited;
		public:
			basic_tag_with_category():inherited(){}
			basic_tag_with_category(const _Elem *s):inherited(s){}
			basic_tag_with_category(const std::basic_string<_Elem> &s):inherited(s){}
			basic_tag_with_category(typename inherited::index_type i):inherited(i){}
		};

		namespace {
            struct cat_component {};
            struct cat_topic {};
            struct cat_level {};
            struct cat_instance {};
		};
		template <typename _Elem>
		struct basic_component:public basic_tag_with_category<cat_component, _Elem>
		{
			basic_component():basic_tag_with_category<cat_component, _Elem>(){}
			explicit basic_component(const _Elem *s):basic_tag_with_category<cat_component, _Elem>(s){}
			explicit basic_component(const std::basic_string<_Elem> &s):basic_tag_with_category<cat_component, _Elem>(s){}
			explicit basic_component(typename basic_tag_with_category<cat_component, _Elem>::index_type i):basic_tag_with_category<cat_component, _Elem>(i){}
		};
		template <typename _Elem>
		struct basic_topic:public basic_tag_with_category<cat_topic, _Elem>
		{
			basic_topic():basic_tag_with_category<cat_topic, _Elem>(){}
			explicit basic_topic(const _Elem *s):basic_tag_with_category<cat_topic, _Elem>(s){}
			explicit basic_topic(const std::basic_string<_Elem> &s):basic_tag_with_category<cat_topic, _Elem>(s){}
			explicit basic_topic(typename basic_tag_with_category<cat_topic, _Elem>::index_type i):basic_tag_with_category<cat_topic, _Elem>(i){}
		};
		typedef basic_component<char> component;
		typedef basic_component<wchar_t> wcomponent;
		typedef basic_topic<char> topic;
		typedef basic_topic<wchar_t> wtopic;
		template <typename _Elem>
		class basic_level:public basic_tag_with_category<cat_level, _Elem>
		{
			typedef basic_tag_with_category<cat_level, _Elem> inherited;
		public:
			enum preset {
				unknown,
				critical,
				error,
				warning,
				information,
				info = information,
				debug0,
				debug = debug0,
				debug1,
				debug2,
				debug3,
				debug4,

				end_marker_for_preset_levels
			};
			typedef inherited tag_type;
			inline static const tag_type &get(preset p);
			basic_level(preset p):inherited(get(p)){}
			explicit basic_level(const tag_type &t):inherited(t){}
			explicit basic_level(const _Elem *s):inherited(s){}
			explicit basic_level(const std::basic_string<_Elem> &s):inherited(s){}
		};
		template <>
		inline static const typename basic_level<char>::tag_type &basic_level<char>::get(basic_level<char>::preset p)
		{
			static const tag_type g_tags[]=
			{
				tag_type("unknown"), tag_type("critical"), tag_type("error"), tag_type("warning"), tag_type("info"),
				tag_type("debug"), tag_type("debug1"), tag_type("debug2"), tag_type("debug3"), tag_type("debug4")
			};
			return g_tags[p<sizeof(g_tags)/sizeof(g_tags[0]) ? p : 0];
		}
		template <>
		inline static const typename basic_level<wchar_t>::tag_type &basic_level<wchar_t>::get(basic_level<wchar_t>::preset p)
		{
			static const tag_type g_tags[]=
			{
				tag_type(L"unknown"), tag_type(L"critical"), tag_type(L"error"), tag_type(L"warning"), tag_type(L"info"),
				tag_type(L"debug"), tag_type(L"debug1"), tag_type(L"debug2"), tag_type(L"debug3"), tag_type(L"debug4")
			};
			return g_tags[p<sizeof(g_tags)/sizeof(g_tags[0]) ? p : 0];
		}

		typedef basic_level<char> level;
		typedef basic_level<wchar_t> wlevel;

		template <typename _Elem>
		inline const basic_component<_Elem> &default_component();
		template <>
		inline const basic_component<char> &default_component() { static basic_component<char> g_default(""); return g_default; }
		template <>
		inline const basic_component<wchar_t> &default_component() { static basic_component<wchar_t> g_default(L""); return g_default; }
		template <typename _Elem>
		inline const basic_topic<_Elem> &default_topic();
		template <>
		inline const basic_topic<char> &default_topic() { static basic_topic<char> g_default(""); return g_default; }
		template <>
		inline const basic_topic<wchar_t> &default_topic() { static basic_topic<wchar_t> g_default(L""); return g_default; }

		template <typename _Elem>
		inline const basic_level<_Elem> &default_level() { static basic_level<_Elem> g_default(basic_level<_Elem>::info); return g_default; }

		//---------------------------------------------------------------------------------------------
		//
		template <typename _Elem> class basic_logsink;
		template <typename _Elem> inline basic_logsink<_Elem> *default_sink();

		typedef basic_logsink<char> logsink;
		typedef basic_logsink<wchar_t> wlogsink;

		/// basic_logbuf is a streambuf accepting events and storing them in a logsink
		template <typename _Elem, typename _Traits, typename _Alloc >
		class basic_logbuf:public std::basic_streambuf<_Elem, _Traits>, private boost::noncopyable
		{
			friend class basic_logsink<_Elem>;
		public:
			enum {
				_Allocated = 1  ///< set if character array storage has been allocated
			};
			typedef int _Strstate;
			typedef typename _Traits::int_type int_type;
			typedef typename _Traits::pos_type pos_type;
			typedef typename _Traits::off_type off_type;
			typedef basic_streambuf<_Elem, _Traits> _Mysb;
			typedef _Alloc allocator_type;
			typedef basic_level<_Elem> level_type;
			typedef basic_component<_Elem> component_type;
			typedef basic_topic<_Elem> topic_type;
			typedef basic_logsink<_Elem> sink_type;
			typedef basic_instance<_Elem> instance_type;
			typedef time_t timestamp_type;
		private:
			struct entry
			{
				timestamp_type  m_timestamp;
				unsigned long	m_index;
				unsigned int    m_instance;
				unsigned short  m_component;
				unsigned short  m_topic;
				unsigned short  m_level;
				unsigned short  m_length;
				size_t          header_size() const { return reinterpret_cast<const char*>(this+1)-reinterpret_cast<const char*>(this); }
				const _Elem     *begin_data() const { return reinterpret_cast<const _Elem*>(this+1); }
				const _Elem     *end_data() const { return begin_data()+length(); }
				const _Elem	   *raw_data() const { return begin_data(); }
				size_t			length() const { return m_length; }
				std::basic_string<_Elem> str() const { return std::basic_string<_Elem>(raw_data(), length()); }
				component_type	component() const { return component_type(m_component); }
				topic_type		topic() const { return topic_type(m_topic); }
				level_type		level() const { return level_type(m_level); }
				instance_type	instance() const { return instance_type(m_instance); }
				void			index(size_t new_index) { m_index=unsigned long(new_index); }
				size_t			index() const { return m_index; }
				timestamp_type	timestamp() const { return m_timestamp; }
				size_t          full_size_in_bytes() const
				{
					return reinterpret_cast<const char*>(end_data())-reinterpret_cast<const char*>(this);
				}
				entry *next_entry() const
				{
					return const_cast<entry*>(details::aligned_ptr<entry>(end_data()));
				}
				bool validate() const
				{
#ifdef _DEBUG
					if (length()>4096 || m_timestamp>time(0)+5 || m_index>100000 || m_index>10000 || m_component>10000 || m_topic>10000 || m_level>1000) {
						return false;
					}
#endif
					return true;
				}
			};
			class entries
			{
			public:
				typedef typename basic_logbuf<_Elem, _Traits, _Alloc>::entry entry;
				entries(const char_type *b, const char_type *e)
					:m_begin(b), m_end(e)
				{
					begin()->validate();
				}
				class const_iterator
				{
					const entry *m_ptr;
				public:
					const_iterator(const char_type *p=0)
						:m_ptr(reinterpret_cast<const entry*>(p)){}
					const_iterator(const const_iterator &i)
						:m_ptr(i.m_ptr){}
					const const_iterator &operator++()
					{
						const entry *next=get_entry()->next_entry();
						m_ptr=next;
						return *this;
					}
					bool operator==(const const_iterator &r) const { return m_ptr==r.m_ptr; }
					bool operator!=(const const_iterator &r) const { return !operator==(r); }
					const const_iterator &operator=(const const_iterator &i) { m_ptr=i.m_ptr; return *this; }
					const entry *operator->() const { return get_entry(); }
					const entry &operator*() const { return *get_entry(); }
					const entry *get_entry() const { return m_ptr; }
				};
				const_iterator begin() const { return const_iterator(m_begin); }
				const_iterator end() const { return const_iterator(m_end); }
			private:
				const char_type	*m_begin;
				const char_type *m_end;
			};
			enum {
				GROW_INCREMENT = 4096   ///< number of elements the log buffer is grown per overflow request
			};
			void    init()
			{
				memset(&m_entry, 0, sizeof(m_entry));
				m_state=0;
				m_sink=default_sink<_Elem>();
				m_sync_frequency=1;	// sync after every log entry
				m_sync_period=0;
				m_log_count_since_last_sync=0;
				m_next_index=0;
				m_time_of_last_sync=timestamp();
				clear();
			}
			entry	m_entry;
			template <typename Value>
			void do_put(const Value &v)
			{
				sputn((const char_type*)&v, (sizeof(v)+sizeof(char_type)-1)/sizeof(char_type));
			}
			size_t count() const { return pptr()-m_begin_data; }
			timestamp_type timestamp() const { return time(0); }

			char_type	*m_begin_data;
			entry		*m_current_entry;
			entry		*current_entry() { if (m_current_entry==0) begin_entry(); return m_current_entry; }
			void		current_entry(entry * val) { m_current_entry = val; }
			sink_type	*m_sink;
			allocator_type m_allocator;
			_Strstate m_state;
			int_type end_of_log_entry;
			size_t		m_sync_frequency;
			timestamp_type m_sync_period;
			size_t		m_log_count_since_last_sync;
			timestamp_type m_time_of_last_sync;
			size_t		m_next_index;
			bool		need_sync() const
			{
				return m_sync_frequency>0 && m_log_count_since_last_sync>=m_sync_frequency
					|| m_sync_period>0 && m_current_entry && m_current_entry->m_timestamp-m_time_of_last_sync>=m_sync_period;
			}
		public:
			basic_logbuf():end_of_log_entry(0) { init(); }
			~basic_logbuf() { clear(); sink(0); }
			void sink(sink_type *new_sink)			{ m_sink=new_sink; }
			sink_type *sink() const					{ return m_sink; }
			/// specify flush frequency: write to sink after \p log entries
			void sync_frequency(size_t f)			{ m_sync_frequency=f; }
			/// specify flush period: write to sink after a timespan of \p p
			void sync_period(timestamp_type p)		{ m_sync_period=p; }

			void    level(const level_type &lvl)		{ current_entry()->m_level=unsigned short(lvl.index()); }
			size_t  level() const					{ return m_current_entry->m_level; }
			void    topic(const topic_type &t)		{ current_entry()->m_topic=(unsigned short)t.index(); }
			size_t  topic() const					{ return m_current_entry->m_topic; }
			void	component(const component_type &c)	{ current_entry()->m_component=(unsigned short)c.index(); }
			size_t	component() const				{ return m_current_entry->m_component; }
			void	instance(const instance_type &i){ current_entry()->m_instance=i.index(); }
			unsigned int instance() const			{ return m_current_entry->m_instance; }

			virtual int sync()
			{
				m_log_count_since_last_sync=0;
				m_time_of_last_sync=m_current_entry ? m_current_entry->m_timestamp : timestamp();
				int rc=_Mysb::sync();
				//TODO: Optimize this
				if (sink()) {
					sink()->put(entries(_Mysb::pbase(), _Mysb::pptr()));
					_Mysb::setp(_Mysb::pbase(), _Mysb::pbase(), _Mysb::epptr());
					m_begin_data=0;
					m_current_entry=0;
				}
				return rc;
			}

			virtual int_type overflow(int_type _Meta = traits_type::eof() )
			{
				if (traits_type::eq_int_type(traits_type::eof(), _Meta))
					return traits_type::not_eof(_Meta);
				// if room in buffer, then store element
				if (_Mysb::pptr()!=0 && _Mysb::pptr() < _Mysb::epptr()) {
					*_Mysb::pptr() = traits_type::to_char_type(_Meta);
					_Mysb::pbump(1);
					return _Meta;
				}
				// grow buffer
				size_t _Oldsize = _Mysb::pptr() == 0 ? 0 : _Mysb::epptr() - _Mysb::pbase();
				size_t _Newsize = _Oldsize + GROW_INCREMENT;
				_Elem *_Newptr = m_allocator.allocate(_Newsize);
				if (_Oldsize == 0) {
					// first growth, set up buffer and pointers
					_Mysb::setp(_Newptr, _Newptr+_Newsize);
				} else {
					_Elem *_Oldptr = _Mysb::pbase();
#if defined(_MSC_VER) && _MSC_VER<1700
					std::_Traits_helper::copy_s<_Traits>(_Newptr, _Newsize, _Oldptr, _Oldsize);
#else
					std::copy(_Oldptr, _Oldptr+_Oldsize, _Newptr);
#endif
					_Mysb::setp(_Newptr, _Newptr + (_Mysb::pptr()-_Oldptr), _Newptr+_Newsize);
					if (m_state & _Allocated)
						m_allocator.deallocate(_Oldptr, _Oldsize);
				}
				m_state |= _Allocated;
				*_Mysb::pptr() = traits_type::to_char_type(_Meta);
				_Mysb::pbump(1);
				return _Meta;
			}
			void set_end_of_log_entry(int_type new_end_of_Log_entry)
			{
				end_of_log_entry=new_end_of_Log_entry;
			}
			void clear()
			{
				if (m_state & _Allocated) {
					m_allocator.deallocate(_Mysb::pbase(), _Mysb::epptr()-_Mysb::pbase());
					m_state&=~_Allocated;
				}
				_Mysb::setp(0,0);
				m_current_entry=0;
				m_begin_data=0;
			}
			void begin_entry()
			{
				m_entry.m_timestamp=timestamp();
				m_entry.index(m_next_index++);
				if (m_current_entry==0) {
					do_put(m_entry);
					m_begin_data=pptr();
					m_current_entry=((entry*)m_begin_data)-1;
				}
			}
			void end_entry()
			{
				if (m_current_entry) {
					off_t total=(off_t)count();
					if (total>0) {
						++m_log_count_since_last_sync;
						m_current_entry->m_length=(unsigned short)total;
						m_current_entry=0;
						// pad to fill word alignment
						_Elem *next_free=details::aligned_ptr<_Elem>(pptr());
						size_t padding=next_free-pptr();
						while (padding--)
							sputc(0);
						if (need_sync())
							sync();
					}
				}
			}
		};

		template <typename _Elem, typename _Traits=std::char_traits<_Elem>, typename _Alloc=std::allocator<_Elem> >
		class basic_logstream:public std::basic_ostream<_Elem, _Traits>
		{
			typedef std::basic_ostream<_Elem, _Traits> inherited;
		public:
			typedef basic_logbuf<_Elem, _Traits, _Alloc> _Streambuf;
			typedef basic_logstream<_Elem, _Traits> _Myt;
			typedef basic_level<_Elem> level_type;
			typedef basic_component<_Elem> component_type;
			typedef basic_topic<_Elem> topic_type;
			typedef basic_logsink<_Elem> sink_type;
			typedef basic_instance<_Elem> instance_type;
			typedef _Myt& (*logmanipulator)(_Myt&);
			basic_logstream()
				:inherited(&m_rdbuf)
			{
			}
			_Streambuf *rdbuf() { return &m_rdbuf; }
			const _Streambuf *rdbuf() const { return &m_rdbuf; }
			void sink(sink_type *newsink) { rdbuf()->sink(newsink); }
			sink_type *sink() const { return rdbuf()->sink(); }

			_Myt &operator &&(logmanipulator l)
			{
				return (*l)(*this);
			}

			_Myt &begin_entry()
			{
				m_rdbuf.begin_entry(); return *this;
			}
			_Myt &end_entry()
			{
				m_rdbuf.end_entry(); return *this;
			}
			_Myt &put_level(const level_type &lvl)
			{
				m_rdbuf.level(lvl); return *this;
			}
			_Myt &put_topic(const topic_type &topic)
			{
				m_rdbuf.topic(topic); return *this;
			}
			_Myt &put_component(const component_type &component)
			{
				m_rdbuf.component(component); return *this;
			}
			_Myt &put_instance(const instance_type &instance)
			{
				m_rdbuf.instance(instance); return *this;
			}
		protected:
			_Streambuf m_rdbuf;

		};
		typedef basic_logstream<char> logstream;
		typedef basic_logstream<wchar_t> wlogstream;

		template <typename _Stream>
		struct stream_traits
		{
			typedef _Stream stream_type;
			typedef typename stream_type::char_type char_type;
			typedef basic_level<char_type> level_type;
			typedef basic_component<char_type> component_type;
			typedef basic_topic<char_type> topic_type;
			typedef basic_logsink<char_type> sink_type;
			typedef basic_instance<char_type> instance_type;
			void set_sink(_Stream &stream, basic_logsink<char_type> *s) { }
			basic_logsink<char_type> *get_sink(const _Stream &) const { return 0; }
			void lbegin(_Stream &stream) { }
			void lend(_Stream &stream) { }

			void put_level(_Stream &stream, const level_type &l) { stream << l.str() << details::sep<char_type>(); }
			void put_component(_Stream &stream, const component_type &c) { stream << c.str() << details::sep<char_type>(); }
			void put_topic(_Stream &stream, const topic_type &t) { stream << t.str() << details::sep<char_type>(); }
			void put_instance(_Stream &stream, const instance_type &i) { stream << i.str() << details::sep<char_type>(); }
		};
		template <typename _Elem>
		struct stream_traits<basic_logstream<_Elem> >
		{
			typedef basic_logstream<_Elem> stream_type;
			typedef typename stream_type::char_type char_type;
			typedef basic_level<char_type> level_type;
			typedef basic_component<char_type> component_type;
			typedef basic_topic<char_type> topic_type;
			typedef basic_logsink<char_type> sink_type;
			typedef basic_instance<char_type> instance_type;
			void set_sink(stream_type &stream, typename stream_type::sink_type *s) { stream.sink(s); }
			typename stream_type::sink_type *get_sink(const stream_type &stream) const { return stream.sink(); }
			void lbegin(stream_type &stream) { stream.begin_entry(); }
			void lend(stream_type &stream) { stream.end_entry(); }
			void put_level(stream_type &stream, const level_type &l) { stream.put_level(l); }
			void put_component(stream_type &stream, const component_type &c) { stream.put_component(c); }
			void put_topic(stream_type &stream, const topic_type &t) { stream.put_topic(t); }
			void put_instance(stream_type &stream, const instance_type &i) { stream.put_instance(i); }
		};
		// ---------------------------------------------------------------------------------------------

        enum enable_state { enabled, disabled };
#pragma warning(push)
#pragma warning(disable: 4250)
		/// Base class for logging events
		template <
			typename _Elem,
			typename _Outstream=basic_logstream<_Elem> ,
			typename _Streamtraits=logger::stream_traits<_Outstream>
		>
		class basic_events:public _Outstream
		{
		public:
			typedef _Outstream Inherited;
			typedef basic_events<_Elem, _Outstream, _Streamtraits> _Myt;
			typedef _Elem char_type;
			typedef _Outstream outstream_type;
			typedef _Streamtraits outstream_traits;
			typedef std::basic_ostream<char_type>& (*iomanipulator)(std::basic_ostream<char_type>&);
			typedef _Myt& (*logmanipulator)(_Myt&);
			typedef basic_tag<char_type> tag_type;
			typedef basic_level<char_type> level_type;
			typedef basic_component<char_type> component_type;
			typedef basic_topic<char_type> topic_type;
			typedef basic_logsink<char_type> sink_type;
			typedef basic_instance<char_type> instance_type;
		private:
			bool m_enabled;
			outstream_traits m_stream_traits;
		public:
			class inserter
			{
				const inserter &operator=(const inserter &i);
			public:
				typedef _Myt events_type;
				bool _enabled;
				events_type &_owner;

				inserter(events_type &owner, bool is_enabled)
					:_owner(owner)
					,_enabled(is_enabled)
				{
					_owner.do_begin();
				}
				~inserter()
				{
					_owner.do_end();
				}
				inserter(const inserter &i)
					:_enabled(i._enabled)
					,_owner(i._owner)
				{
					_owner.do_begin();
				}
				template <typename Value>
				inserter &operator &&(const Value &v)
				{
					if (_enabled) {
						_owner.put(v);
					}
					return *this;
				}
				events_type &operator&&(logmanipulator pFn)
				{
					return (*pFn)(_owner);
				}
				inserter &operator&&(iomanipulator pFn)
				{
					//if (pFn==std::endl) {

					//}
					////(*pFn)(_owner._outstream);
					return *this;
				}
				template <typename Value>
				inserter &operator <<(const Value &v)
				{
					return operator&&<Value>(v);
				}
				inserter &operator<<(std::basic_ostream<_Elem> &(*pFn)(std::basic_ostream<_Elem> &))
				{
					return operator&&(pFn);
				}
			};

			basic_events(
				const component_type &c=default_component<char_type>(),
				const topic_type &t=default_topic<char_type>(),
                enable_state is_enabled=logger::enabled,
				sink_type &target=*default_sink<char_type>())
				:
			m_default_component(c), m_component(m_default_component)
				,m_default_topic(t), m_topic(m_default_topic)
				,m_default_level(default_level<char_type>()), m_level(m_default_level)
				,m_enabled(is_enabled!=disabled)
				,m_ignore_begin_end_count(0)
				,m_open_count(0)
			{
				sink(&target);
			}
			basic_events(
				const char_type *c,
				const char_type *t=default_topic<_Elem>().str().c_str(),
                enable_state is_enabled=logger::enabled,
				sink_type &target=*default_sink<char_type>()
				)
				:m_default_component(c), m_component(m_default_component)
				,m_default_topic(t), m_topic(m_default_topic)
				,m_default_level(default_level<char_type>()), m_level(m_default_level)
				,m_enabled(is_enabled!=disabled)
				,m_ignore_begin_end_count(0)
				,m_open_count(0)
			{
				reset_tags_to_default();
				sink(&target);
			}
			basic_events(const basic_events &e)
				:m_default_component(e.m_default_component), m_component(e.m_component)
				,m_default_topic(e.m_default_topic), m_topic(e.m_topic)
				,m_default_level(e.m_default_level), m_level(e.m_level)
				,m_enabled(e.m_enabled), m_ignore_begin_end_count(0), m_open_count(0)
				,m_instance(e.m_instance)
				,m_stream_traits(e.m_stream_traits)
			{
				sink(e.sink());
			}
			const basic_events& operator=(const basic_events &e)
			{
				m_default_component=e.m_default_component;
				m_component=e.m_component;
				m_default_topic=e.m_default_topic;
				m_topic=e.m_topic;
				m_default_level=e.m_default_level;
				m_level=e.m_level;
				m_enabled=e.m_enabled; m_ignore_begin_end_count=0; m_open_count=0;
				m_instance=e.m_instance;
				m_stream_traits=e.m_stream_traits;
				sink(e.sink());
				return *this;
			}
			void enabled(bool enabled) { m_enabled=enabled; }
            bool enabled() const { return m_enabled; }
            void enable() { enabled(true); }
            void disable() { enabled(false); }
			basic_events(sink_type &target)
				:m_default_component(default_component<char_type>()), m_component(m_default_component)
				,m_default_topic(default_topic<char_type>()), m_topic(m_default_topic)
				,m_default_level(default_level<char_type>()), m_level(m_default_level)
				,m_enabled(true)
				,m_ignore_begin_end_count(0)
				,m_open_count(0)
			{
				reset_tags_to_default();
				sink(&target);
			}

			_Outstream &stream() { return *this; }
			const _Outstream &stream() const { return *this; }

			operator bool() const { return m_enabled; }

			template <typename Value>
			inserter operator && (const Value &v)
			{
				return inserter(*this, enabled()) && v;
			}
			template <typename Value>
			void put(const Value &v)
			{
                litwindow_logger_find_all_namespaces_operator_insert_to_stream(stream(), v);
                // This here used to be
				// stream() << v;
                // but in that case a user defined operator << will not be found if it is not
                // visible in the litwindow::logger namespace
                // So call the ::litwindow_logger... function (see below), which then
                // will cause a lookup in all accessible namespaces

                // Note: This might be a Visual Studio 2008 compiler bug, but I don't know enough
                // about the exact C++ symbol lookup rules to determine that. I would have expected
                // that symbols from the global namespace were accessible here in this function
                // even if they where defined somewhere else or somewhat later on.
                // But without this 'workaround', a user defined operator<<(ostream&, const Value&) will not be
                // found.
			}
			template <typename Value>
			inserter operator<<(const Value &v)
			{
				return operator&&<Value>(v);
			}

			_Myt &operator && (logmanipulator l)
			{
				return (*l)(*this);
				//return inserter(r, r.enabled());
			}
			_Myt &operator &&(const component_type &c)
			{
				return this->component(c);
			}
			_Myt &operator &&(const level_type &l)
			{
				return this->level(l);
			}
			_Myt &operator &&(const topic_type &t)
			{
				return this->topic(t);
			}
			void sink(sink_type *s)
			{
				m_stream_traits.set_sink(stream(), s);
			}
			sink_type *sink() const
			{
				return m_stream_traits.get_sink(stream());
			}

			_Myt &level(const level_type &l)
			{
				m_level=l; return *this;
			}
			_Myt &level(typename level_type::preset l)
			{
				return level(level_type(l));
			}
			_Myt &component(const component_type &c)
			{
				m_component=c; return *this;
			}
			_Myt &topic(const topic_type &t)
			{
				m_topic=t; return *this;
			}
			_Myt &set_default_topic(const topic_type &t)
			{
				m_topic=m_default_topic=t; return *this;
			}
			_Myt &set_default_component(const component_type &c)
			{
				m_component=m_default_component=c; return *this;
			}
			void copy_tags_from(const _Myt &r)
			{
				m_default_level = r.m_default_level;
				m_default_component = r.m_default_component;
				m_default_topic = r.m_default_topic;
				m_enabled = r.m_enabled;
			}

			void continue_entry()
			{
				// ignore one 'end' and one 'begin'
				if (m_open_count)
                    m_ignore_begin_end_count=2;
			}
		private:
			size_t	m_ignore_begin_end_count;
			size_t	m_open_count;
			/// begin a new entry
			void do_begin()
			{
				if (m_open_count++==0) {
					if (m_ignore_begin_end_count==0) {
						m_stream_traits.lbegin(stream());
						m_stream_traits.put_level(stream(), m_level);
						m_stream_traits.put_component(stream(), m_component);
						m_stream_traits.put_topic(stream(), m_topic);
						m_stream_traits.put_instance(stream(), m_instance);
					} else
						--m_ignore_begin_end_count;
				}
			}
			/// end an entry
			void do_end()
			{
				if (m_open_count==1) {
					if (m_ignore_begin_end_count==0) {
						m_stream_traits.lend(stream());
						reset_tags_to_default();
					} else
						--m_ignore_begin_end_count;
					m_open_count=0;
				} else if (m_open_count>0)
					--m_open_count;
			}

			void reset_tags_to_default()
			{
				m_level=m_default_level;
				m_component=m_default_component;
				m_topic=m_default_topic;
			}
			friend class inserter;
			instance_type	m_instance;
			level_type		m_default_level, m_level;
			component_type	m_default_component, m_component;
			topic_type		m_default_topic, m_topic;
		};
#pragma warning(pop)

		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &debug(basic_events<_Elem, Streambuf> &in) { in.level(basic_level<_Elem>::debug); return in; }
		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &information(basic_events<_Elem, Streambuf> &in) { in.level(basic_level<_Elem>::information); return in; }
		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &info(basic_events<_Elem, Streambuf> &in) { return in.level(basic_level<_Elem>::info); return in; }
		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &warning(basic_events<_Elem, Streambuf> &in) { in.level(basic_level<_Elem>::warning); return in; }
		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &error(basic_events<_Elem, Streambuf> &in) { in.level(basic_level<_Elem>::error); return in; }
		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &critical(basic_events<_Elem, Streambuf> &in) { in.level(basic_level<_Elem>::critical); return in; }

		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &disable(basic_events<_Elem, Streambuf> &in) { in.disable(); return in; }
		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &enable(basic_events<_Elem, Streambuf> &in) { in.enable(); return in; }
		//template <typename _Elem, typename Streambuf>
		//inline basic_events<_Elem, Streambuf> &endl(basic_events<_Elem, Streambuf> &in) { in.put('\n'); return in; }

		template <typename _Elem, typename Streambuf>
		inline basic_events<_Elem, Streambuf> &contl(basic_events<_Elem, Streambuf> &in) { in.continue_entry(); return in; }

		typedef basic_events<char> events;
		typedef basic_events<wchar_t> wevents;
		namespace threadsafe {
			template <typename _Events>
			struct basic_threadsafe_events
			{
				typedef _Events events_type;
				typedef typename events_type::char_type char_type;
				typedef typename events_type::sink_type sink_type;
				typedef typename events_type::topic_type topic_type;
				typedef typename events_type::component_type component_type;
				boost::thread_specific_ptr<_Events> m_evt_ptr;
				_Events m_default;
				_Events &get_default() { return m_default; }
				const _Events &get_default() const { return m_default; }
				_Events &get()
				{
					if (m_evt_ptr.get()==0)
#ifdef DEBUG_NEW
						m_evt_ptr.reset(DEBUG_NEW _Events(m_default));
#else
						m_evt_ptr.reset(new _Events(m_default));
#endif
					m_evt_ptr->copy_tags_from(get_default());
					return *m_evt_ptr;
				}
				basic_threadsafe_events()
				{
				}
				basic_threadsafe_events(const basic_threadsafe_events &evt)
					:m_default(evt.m_default)
				{
				}
				basic_threadsafe_events(
					const char_type *c,
					const char_type *t=default_topic<char_type>().str().c_str(),
					enable_state is_enabled=logger::enabled,
					sink_type &target=*default_sink<char_type>()
					)
					:m_default(c, t, is_enabled, target)
				{
				}
				const basic_threadsafe_events &operator=(const basic_threadsafe_events &e)
				{
					m_default=e.m_default;
					m_evt_ptr.reset();
					return *this;
				}
				events_type &operator &&(typename events_type::logmanipulator l)
				{
					return get() && l;
				}
				events_type &operator &&(const typename events_type::component_type &c)
				{
					return get().component(c);
				}
				events_type &operator &&(const typename events_type::level_type &l)
				{
					return get().level(l);
				}
				events_type &operator &&(const typename events_type::topic_type &t)
				{
					return get().topic(t);
				}
				template <typename Value>
				typename events_type::inserter operator &&(const Value &v)
				{
					return get() && v;
				}
				void sink(typename events_type::sink_type *s)
				{
					get().sink(s);
				}
				typename events_type::sink_type *sink()
				{
					return get().sink();
				}
				void set_default_topic(const topic_type &t)
				{
					get_default().set_default_topic(t);
					get().set_default_topic(t);
				}
				template <typename ValueType>
				void set_default_component(ValueType c)
				{
					get_default().set_default_component(component_type(c));
					get().set_default_component(component_type(c));
				}
				void enabled(bool do_enable)
				{
					get_default().enabled(do_enable);
					get().enabled(do_enable);
				}
				bool enabled() const
				{
					return get_default().enabled();
				}
				void enable() { enabled(true); }
				void disable() { enabled(false); }
			};
			typedef basic_threadsafe_events<events> events;
			typedef basic_threadsafe_events<wevents> wevents;
		}

		/*!\page litwindow_logger Logging: recording events and states.
		* Copyright 2009 Hajo Kirchhoff, Lit Window Productions - Kirchhoff-IT Consulting, www.litwindow.com
		* \section logging_intro Introduction and Overview

		* Litwindow.logging is a library for generating and recording information about
		* a programs runtime environment and execution. The methods and procedures presented
		* here are commonly refered to as 'logging'. The library aims to give programmers a
		* simple, flexible and scalable framework to 'log' information for diagnostics,
		* debugging and UI purposes and collect the information during program execution.

		* - \subpage logger_quick_intro gives you some code samples and a very short introduction

		* \subsection rationale Rationale
		* Logging is often thought of as a slightly improved 'printf' with which one peppers the
		* source code with in hope of finding that problematic bug. More experienced software
		* developers however see logging in a greater perspective, especially if they have ever
		* had to diagnose defects that only occurred under very specific circumstances and only
		* on the customers system. As systems become more complex, good diagnostics information
		* is ever more important. This library treats the task of logging as an integral part of software development.

		* \subsection design_philosophy Design philosophy
		* The library distinguishes between logging events and logging states.

		* \par Events
		* Events essentially say: "The program execution reached this point at that time with the following information".
		* The classical log file is simply a list of events, usually in the order in which they occurred.

		* 		Events are characterized by several attributes.
		* 		<table>
		* 		<tr><td>Time<td>When did the event occur?
		* 		<tr><td>Level<td>What level (severity) does the event have?
		* 		<tr><td>Component<td>What (software) component reported the event?
		* 		<tr><td>Topic<td>What kind of information does it contain?
		* 		<tr><td>Instance<td>Where in the runtime environment did it happen?
		* 		<tr><td>Id<td>A unique identifier of the event
		* 		<tr><td>Text<td>The actual text of the event
		* 		</td></tr></table>

		* 	\par States
		*	States are very similar to events, with one distiction. While events have no memory - they are
		* 	simply recorded and forgotten - states have a 'current' value. The collection of states can give
		* 	a programmer or a user information about the state the program is in.
		*
		* \par Sinks and filters
		* All logging information is written to a logging stream, which is connected to a sink. A sink combines
		* the output from several separate streams into one. Sinks can be chained and multiple sinks can be
		* connected to a single master sink. Filters reduce the amount of information that is passed into a sink.
		*
		* \par Muting and deactivating log information
		* Events and states can be selectively disabled at runtime so that more chatty
		* logging sources can be muted until their information is actually helpful.
		* Or they can be completely deactivated at compile time so that no code is generated for them, but
		* their respective logging statements remain in the source code, should they be needed again.

		* \subsection logging_design Design goals
		* -# simplicity
		* 	- Inexperienced programmers shall be able to learn it within minutes.
		* 	- Logging program events and states shall be possible without constantly looking up the documentation.
		* -# flexibility
		* 	- Allow programmers to adapt to their specific programming scenario.
		* 	- Shall selectively en- or disable programmer specified parts of logging information.
		* 		- This shall be possible at compile time and at runtime.
		* -# scalability\n
		* 		Shall be suitable for ...
		* 	- single thread command line tools
		* 	- single process, multi-threaded GUI applications
		* 	- multi-process, multi-homed distributed systems (client-server)
		* -# performance
		* 	- Must work in multithreaded environments.
		* 	- Have very low logging overhead.
		* 	- Have the ability to defer more costly operations to a low priority thread.
		* -# cleanliness\n
		* 		Traditional logging mechanisms make heavy use of macros and sometimes require unorthodox
		* 		calling conventions. This tends to obfuscate the source code or interrupt readability.
		* 		Also macros come with their own set of problems (namespace collisions, side effects).
		* 		The library presented here avoids the use of macros alltogether.
		* \subsection library_architecture Architecture
		* The library is split into two parts:
		* \par generating event and state information
		* This part is used by all programmers in their source code to report information.
		* 	- \ref basic_events and basic_states are streams to report information.
		* 	- basic_level, basic_component, basic_topic, basic_instance and basic_id encapsulate
		* 		the attributes that describe an event or state.
		* 	- basic_tag is a low-level class implementing a global string table used by basic_component
		* 		and other classes.

		* \par collecting and storing event and state information
		* This part will be used only by some programmers to collect and possibly store the information
		* generated by the other part of the library.
		* 	- basic_logbuf and basic_logstream are used by basic_events and basic_states to compile
		* 		event and state information and send them to a basic_logsink.
		* 	- basic_logsink collects information from logging sources. It is thread safe
		* 		and combines several logging sources into one stream.
		* 	- basic_memory_logsink, basic_file_logsink and others store the logging information and
		* 		have an interface to query the logging information.
		*/

		/*! \page logger_quick_intro Logger: A quick introduction
		* This section gives you a quick introduction.
		* \section quick_intro_logging Logging in the source code.
		* Use events and wevents, derived from basic_events much as you would use an std::stream.
		* This example writes logging information to the global log sink, which needs to be
		* initialized elsewhere.

		* \par Simple case, no component or topic
		* \code
		* #include <litwindow/logger.hpp>
		* using namespace litwindow::logger;
		*
		* // define an events object
		* events ol;
		* // write to the events object
		* ol << "This gets written to the log";	// default level
		* ol << logger::error << "This is an error";	// error level
		* \endcode
		* The output in a simple log file would look like this.
		* \verbatim
12:52	info	This gets written to the log
12:53	error	This is an error \endverbatim

		* \par Using components and topics, Part I
		* \code
		* class my_sub_system
		* {
		*    logger::events ol_connect, ol;	// declare two events streams
		*
		*	 // initialise them and set up component and topic
		*    my_sub_system():ol_connect("communication.subsystem1", "connections")
		*    {
		*        // or change the component after initialisation
		*        ol.component("communication.subsystem1");
		*    }
		*    void connect_established(size_t portNo)
		*    {
		*        // log information
		*        ol_connect << "connection established at port: " << portNo;
		*    }
		* };
		* \endcode
		* \par Using components and topics, Part II
		* \code
		* // define two components
		* component com_sub1("communication.subsystem1");
		* component flat("flat");
		* // define a topics
		* topic t_connections("connections");
		* events ol;
		*
		* ol && com_sub1 && t_connections && "connection established at port: " && port_no;
		*
		* ol && logger::debug && flat && "This uses the default topic";
		* \endcode
		* This is what the output including component and topic would look like.
		* \verbatim
13:10	info	communication.subsystem1	connections	connection established at port: 9731
13:13	debug0	flat						This uses the default topic.\endverbatim
		*
		* \par Deactivate a log stream but leave its statement in the source code.
		* \code
		* // Change events to deactivated_events
		* deactivated_events ol;
		* ol && com_sub1 && t_tcp && "connection established at port: " && port_no;
		* \endcode
		* \note The compiler will not generate any code for this statement in release builds. deactivated_events
		* are implicitly convertible to bool and will always return false. Thus the statement will be
		* false && com_sub1 && t_tcp ... which always evaluates to false and will be short-circuited. The compiler
		* will optimize this and remove the entire statement.
		* \note This is the reason why logging streams (events or states) define the && operator to stream
		* information. The << operator is used for compatibility with iostreams but does not have the capability
		* to deactivate the log stream at compile time.
		* \section quick_intro_sink Specifying and using sinks.
		* \par Using a stringstream as the destination.
		* - define a stringstream
		* - define a logsink with the stringstream as its target
		* - modify the formatter
		* - define an events object with the logsink as its target
		* - write event information to the events object
		* - query the stringstream for the output
		*
		* \code
		* std::wstringstream s;
		* wostream_logsink sink(s);
		* sink.format().timestamp=false;	// no timestamp
		* sink.format().level=false;		// no level
		* wevents e(&sink);
		* e.sink(&sink);
		* e && debug && L"This is a test with number " && 800;
		* e && warning && L"Some more tests.";
		* wstring rc(s.str());
		* BOOST_CHECK(rc==wstring(L"\t\tThis is a test with number 800\n\t\tSome more tests.\n"));
		* \endcode
		*/
	}
}

template <typename _Elem, typename V>
inline std::basic_ostream<_Elem> &litwindow_logger_find_all_namespaces_operator_insert_to_stream(std::basic_ostream<_Elem> &o, const V &v)
{
    return (o << v);
}

#include "logger/sink.hpp"

#ifdef _MSC_VER
#pragma once
#endif

#endif // litwindow_logger_h__151208

ext: hpp

max_stars_repo_name: hajokirchhoff/litwindow

max_issues_repo_name: hajokirchhoff/litwindow

max_forks_repo_name: hajokirchhoff/litwindow


text:
/*!
@file
Forward declares `boost::hana::intersperse`.

@copyright Louis Dionne 2013-2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_FWD_INTERSPERSE_HPP
#define BOOST_HANA_FWD_INTERSPERSE_HPP

#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>

BOOST_HANA_NAMESPACE_BEGIN
    //! Insert a value between each pair of elements in a finite sequence.
    //! @ingroup group-Sequence
    //!
    //! Given a finite `Sequence` `xs` with a linearization of
    //! `[x1, x2, ..., xn]`, `intersperse(xs, z)` is a new sequence with a
    //! linearization of `[x1, z, x2, z, x3, ..., xn-1, z, xn]`. In other
    //! words, it inserts the `z` element between every pair of elements of
    //! the original sequence. If the sequence is empty or has a single
    //! element, `intersperse` returns the sequence as-is. In all cases,
    //! the sequence must be finite.
    //!
    //!
    //! @param xs
    //! The sequence in which a value is interspersed.
    //!
    //! @param z
    //! The value to be inserted between every pair of elements of the sequence.
    //!
    //!
    //! Example
    //! -------
    //! @include example/intersperse.cpp
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    constexpr auto intersperse = [](auto&& xs, auto&& z) {
        return tag-dispatched;
    };
#else
    template <typename S, typename = void>
    struct intersperse_impl : intersperse_impl<S, when<true>> { };

    struct intersperse_t {
        template <typename Xs, typename Z>
        constexpr auto operator()(Xs&& xs, Z&& z) const;
    };

    constexpr intersperse_t intersperse{};
#endif
BOOST_HANA_NAMESPACE_END

#endif // !BOOST_HANA_FWD_INTERSPERSE_HPP


text:
//---------------------------------------------------------------------------//
// Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
// Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//---------------------------------------------------------------------------//

#ifndef CRYPTO3_ALGEBRA_FIELD_UTILS_HPP
#define CRYPTO3_ALGEBRA_FIELD_UTILS_HPP

#include <type_traits>
#include <complex>

#include <boost/math/constants/constants.hpp>
#include <nil/crypto3/algebra/fields/params.hpp>

namespace nil {
    namespace crypto3 {
        namespace math {
            namespace detail {

                using namespace nil::crypto3::algebra;

                std::size_t bitreverse(std::size_t n, const std::size_t l) {
                    std::size_t r = 0;
                    for (std::size_t k = 0; k < l; ++k) {
                        r = (r << 1) | (n & 1);
                        n >>= 1;
                    }
                    return r;
                }

                constexpr std::size_t get_power_of_two(std::size_t n) {
                    n--;
                    n |= n >> 1;
                    n |= n >> 2;
                    n |= n >> 4;
                    n |= n >> 8;
                    n |= n >> 16;
                    n++;

                    return n;
                }

                template<typename FieldType>
                typename FieldType::value_type coset_shift() {
                    return
                        typename FieldType::value_type(fields::arithmetic_params<FieldType>::multiplicative_generator)
                            .squared();
                }

            }    // namespace detail
        }        // namespace fft
    }            // namespace crypto3
}    // namespace nil

#endif    // CRYPTO3_FIELD_UTILS_HPP


text:
//---------------------------------------------------------------------------//
//!
//! \file   MonteCarlo_StandardFilledParticleGeometryModel.hpp
//! \author Alex Robinson
//! \brief  The standard filled particle geometry model class declaration
//!
//---------------------------------------------------------------------------//

#ifndef MONTE_CARLO_STANDARD_FILLED_PARTICLE_GEOMETRY_MODEL_HPP
#define MONTE_CARLO_STANDARD_FILLED_PARTICLE_GEOMETRY_MODEL_HPP

// Std Lib Includes
#include <memory>

// Boost Includes
#include <boost/filesystem.hpp>

// FRENSIE Includes
#include "MonteCarlo_AtomicRelaxationModelFactory.hpp"
#include "MonteCarlo_ScatteringCenterDefinitionDatabase.hpp"
#include "MonteCarlo_MaterialDefinitionDatabase.hpp"
#include "MonteCarlo_SimulationProperties.hpp"
#include "Geometry_Model.hpp"
#include "Utility_Map.hpp"
#include "Utility_Set.hpp"
#include "Utility_Vector.hpp"

namespace MonteCarlo{

//! The standard filled particle geometry model class
template<typename Material>
class StandardFilledParticleGeometryModel
{
  // Typedef for this type
  typedef StandardFilledParticleGeometryModel<Material> ThisType;

public:

  //! Typedef for the material type
  typedef Material MaterialType;

  //! Typedef for the scattering center name map
  typedef typename Material::ScatteringCenterNameMap ScatteringCenterNameMap;

  //! Typedef for the reaction enum type
  typedef typename Material::ReactionEnumType ReactionEnumType;

  //! Typedef for the particle type
  typedef typename Material::ParticleStateType ParticleStateType;

  //! Check if the entire model is void
  bool isVoid() const;

  //! Check if a cell is void
  bool isCellVoid( const Geometry::Model::EntityId cell ) const;

  //! Check if a cell is a termination cell
  bool isTerminationCell( const Geometry::Model::EntityId cell ) const;

  //! Get the material contained in a cell
  const std::shared_ptr<const MaterialType>&
  getMaterial( const Geometry::Model::EntityId cell ) const;

  //! Destructor
  virtual ~StandardFilledParticleGeometryModel()
  { /* ... */ }

  //! Get the total macroscopic cross section of a material
  double getMacroscopicTotalCrossSection(
                                     const ParticleStateType& particle ) const;

  //! Get the total macroscopic cross section of a material
  double getMacroscopicTotalCrossSection(
                                const Geometry::Model::EntityId cell,
                                const double energy ) const;

  //! Get the total macroscopic cross section of a material
  double getMacroscopicTotalCrossSectionQuick(
                                     const ParticleStateType& particle ) const;

  //! Get the total macroscopic cross section of a material
  double getMacroscopicTotalCrossSectionQuick(
                                const Geometry::Model::EntityId cell,
                                const double energy ) const;

  //! Get the total forward macroscopic cross section of a material
  double getMacroscopicTotalForwardCrossSection(
                                     const ParticleStateType& particle ) const;

  //! Get the total forward macroscopic cross section of a material
  virtual double getMacroscopicTotalForwardCrossSection(
                                const Geometry::Model::EntityId cell,
                                const double energy ) const;

  //! Get the total forward macroscopic cross section of a material
  double getMacroscopicTotalForwardCrossSectionQuick(
                                     const ParticleStateType& particle ) const;

  //! Get the total forward macroscopic cross section of a material
  virtual double getMacroscopicTotalForwardCrossSectionQuick(
                                const Geometry::Model::EntityId cell,
                                const double energy ) const;

  //! Get the macroscopic reaction cross section for a specific reaction
  double getMacroscopicReactionCrossSection(
                                       const ParticleStateType& particle,
                                       const ReactionEnumType reaction ) const;

  //! Get the macroscopic reaction cross section for a specific reaction
  double getMacroscopicReactionCrossSection(
                                const Geometry::Model::EntityId cell,
                                const double energy,
                                const ReactionEnumType reaction ) const;

  //! Get the macroscopic reaction cross section for a specific reaction
  double getMacroscopicReactionCrossSectionQuick(
                                       const ParticleStateType& particle,
                                       const ReactionEnumType reaction ) const;

  //! Get the macroscopic reaction cross section for a specific reaction
  double getMacroscopicReactionCrossSectionQuick(
                                const Geometry::Model::EntityId cell,
                                const double energy,
                                const ReactionEnumType reaction ) const;

  //! Get the unfilled model
  const Geometry::Model& getUnfilledModel() const;

protected:

  //! Default constructor
  StandardFilledParticleGeometryModel();

  //! Constructor
  StandardFilledParticleGeometryModel(
                const std::shared_ptr<const Geometry::Model>& unfilled_model );

  //! Set the unfilled model
  void setUnfilledModel( const std::shared_ptr<const Geometry::Model>& unfilled_model );

  //! Load the materials and fill the model
  void loadMaterialsAndFillModel(
       const boost::filesystem::path& database_path,
       const MaterialDefinitionDatabase::ScatteringCenterNameSet&
       unique_scattering_center_names,
       const ScatteringCenterDefinitionDatabase& scattering_center_definitions,
       const std::shared_ptr<AtomicRelaxationModelFactory>&
       atomic_relaxation_model_factory,
       const SimulationProperties& properties,
       const bool verbose_material_construction,
       const MaterialDefinitionDatabase& material_definitions,
       const Geometry::Model::CellIdMatIdMap& cell_id_mat_id_map,
       const Geometry::Model::CellIdDensityMap& cell_id_density_map );

  //! Load the scattering centers
  virtual void loadScatteringCenters(
       const boost::filesystem::path& database_path,
       const MaterialDefinitionDatabase::ScatteringCenterNameSet&
       unique_scattering_center_names,
       const ScatteringCenterDefinitionDatabase& scattering_center_definitions,
       const std::shared_ptr<AtomicRelaxationModelFactory>&
       atomic_relaxation_model_factory,
       const SimulationProperties& properties,
       const bool verbose,
       ScatteringCenterNameMap& scattering_center_name_map ) const = 0;

  //! Process the loaded scattering centers
  virtual void processLoadedScatteringCenters(
                   const ScatteringCenterNameMap& scattering_centers );

private:

  // Add a material to the collision kernel
  void addMaterial( const std::shared_ptr<const MaterialType>& material,
                    const std::vector<Geometry::Model::EntityId>&
                    cells_containing_material );

  // The unfilled model
  std::shared_ptr<const Geometry::Model> d_unfilled_model;

  // The scattering center name map
  ScatteringCenterNameMap d_scattering_center_name_map;

  // The material name map
  typedef std::unordered_map<std::string,std::shared_ptr<const MaterialType> >
  MaterialNameMap;

  MaterialNameMap d_material_name_map;

  // The cell id material map
  typedef std::unordered_map<Geometry::Model::EntityId,std::shared_ptr<const MaterialType> >
  CellIdMaterialMap;

  CellIdMaterialMap d_cell_id_material_map;
};

} // end MonteCarlo namespace

//---------------------------------------------------------------------------//
// Template Includes
//---------------------------------------------------------------------------//

#include "MonteCarlo_StandardFilledParticleGeometryModel_def.hpp"

//---------------------------------------------------------------------------//

#endif // end MONTE_CARLO_STANDARD_FILLED_PARTICLE_GEOMETRY_MODEL_HPP

//---------------------------------------------------------------------------//
// end MonteCarlo_StandardFilledParticleGeometryModel.hpp
//---------------------------------------------------------------------------//


text:
#pragma once

#include <skynet/utility/serialization.hpp>

#include <Eigen/Core>

namespace boost{namespace serialization{

	using namespace boost::serialization;

	template <typename Archive>
	void serialize(Archive &ar, Eigen::VectorXd &vec, const unsigned int&){
		if (Archive::is_saving::value){
			size_t size = vec.size();
			ar & make_nvp("size", size);

			if (vec.size() == 0)
				return;

			ar & make_array(&(vec[0]), vec.size());
		}
		else{
			size_t size = 0;
			ar & boost::serialization::make_nvp("size", size);
			vec.resize(size);

			if (vec.size() == 0)
				return;

			ar & make_array(&vec[0], vec.size());
		}
	}

	template <typename Archive>
	void serialize(Archive &ar, Eigen::MatrixXd &matrix, const unsigned int&){
		if (Archive::is_saving::value){
			size_t row = matrix.rows();
			size_t col = matrix.cols();
			ar & make_nvp("row_size", row);
			ar & make_nvp("col_size", col);

			ar & make_array(&matrix(0, 0), col * row);
		}
		else{
			size_t row = 0;
			size_t col = 0;
			ar & make_nvp("row_size", row);
			ar & make_nvp("col_size", col);
			matrix.resize(row, col);

			ar & make_array(&matrix(0, 0), col * row);
		}
	}
}}

max_stars_repo_name: zhangzhimin/skynet

max_issues_repo_name: zhangzhimin/skynet

max_forks_repo_name: zhangzhimin/skynet


text:
#ifndef RW_COMMON_PROGRAMOPTIONS_HPP_
#define RW_COMMON_PROGRAMOPTIONS_HPP_

#if !defined(SWIG)
#include <rw/core/PropertyMap.hpp>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/variables_map.hpp>
#endif
namespace rw { namespace common {

    /**
     * @brief a class for parsing program command line into a PropertyMap
     */
    class ProgramOptions
    {
      public:
        /**
         * @brief Construct new set of program options.
         * @param applicationName [in] the name of the application.
         * @param version [in] the version of the application.
         */
        ProgramOptions (const std::string& applicationName, const std::string& version) :
            _appName (applicationName), _version (version), _optionDesc ("Options")
        {}

        /**
         * @brief this initialize default options that can add simple properties to the propertymap.
         */
        void initOptions ();

        /**
         * @brief add a string option that is only allowed to occur once on the command line
         * @param name [in] name of option
         * @param defval [in] the default string value if any
         * @param desc [in] description of commandline option
         */
        void addStringOption (const std::string& name, const std::string& defval,
                              const std::string& desc);

        /**
         * @brief Set \b name of option number \b i.
         * @param name [in] the name.
         * @param i [in] index of the option.
         */
        void setPositionalOption (const std::string& name, int i);

        /**
         * @brief parses input, if
         * @param argc
         * @param argv
         * @return if 0 is returned then help or an error
         */
        int parse (int argc, char** argv);

        /**
         * @brief Parses input from a string.
         * @param string [in] input line.
         * @return 0 if success.
         */
        int parse (const std::string& string);

        /**
         * @brief Get the underlying program options description from boost.
         * @return reference to options_description.
         */
        boost::program_options::options_description& getOptionDescription () { return _optionDesc; }

        /**
         * @brief Get the underlying positional program options description from boost.
         * @return reference to positional_options_description.
         */
        boost::program_options::positional_options_description& getPosOptionDescription ()
        {
            return _posOptionDesc;
        }

        /**
         * @brief Get parsed properties in RobWork format in the form of a PropertyMap.
         * @return the property map with parsed options.
         */
        rw::core::PropertyMap getPropertyMap () { return _pmap; }

      private:
        int checkVariablesMap (boost::program_options::variables_map& vm);

        std::string _appName;
        rw::core::PropertyMap _pmap;
        std::string _inputFile, _version;
        std::vector< std::string > _additionalStringOptions;
        boost::program_options::options_description _optionDesc;
        boost::program_options::positional_options_description _posOptionDesc;
    };
}}    // namespace rw::common

#endif


text:
/**
 * Copyright (c) 2013-2016, The Kovri I2P Router Project
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be
 *    used to endorse or promote products derived from this software without specific
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Parts of the project are originally copyright (c) 2013-2015 The PurpleI2P Project
 */

#ifdef USE_UPNP
#include "UPnP.h"

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>

#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>

#ifdef _WIN32
#include <windows.h>
#define dlsym GetProcAddress
#else
#include <dlfcn.h>
#endif

#include <string>
#include <thread>

#include "NetworkDatabase.h"
#include "RouterContext.h"
#include "util/Log.h"

// These are per-process and are safe to reuse for all threads
#ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
UPNPDev* (*upnpDiscoverFunc) (
    int,
    const char *,
    const char *,
    int);

int(*UPNP_AddPortMappingFunc) (
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char*);
#else
/* miniupnpc 1.6 */
UPNPDev* (*upnpDiscoverFunc) (
    int,
    const char*,
    const char*,
    int,
    int,
    int*);

int(*UPNP_AddPortMappingFunc) (
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char*,
    const char *);
#endif
int(*UPNP_GetValidIGDFunc) (
    struct UPNPDev*,
    struct UPNPUrls*,
    struct IGDdatas*,
    char*,
    int);

int(*UPNP_GetExternalIPAddressFunc) (
    const char*,
    const char*,
    char*);

int(*UPNP_DeletePortMappingFunc) (
    const char*,
    const char*,
    const char*,
    const char*,
    const char*);

void(*freeUPNPDevlistFunc) (
    struct UPNPDev*);

void(*FreeUPNPUrlsFunc) (
    struct UPNPUrls*);

// Nice approach http://stackoverflow.com/a/21517513/673826
template<class M, typename F>
F GetKnownProcAddressImpl(
    M hmod,
    const char *name,
    F) {
  auto proc = reinterpret_cast<F>(dlsym(hmod, name));
  if (!proc) {
    LogPrint(eLogError,
        "UPnP: error resolving ", name,
        " from UPNP library. This often happens if there is version mismatch!");
  }
  return proc;
}
#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func);

namespace i2p {
namespace transport {

UPnP::UPnP()
    : m_Thread(nullptr),
      m_IsModuleLoaded(false) {}

void UPnP::Stop() {
  if (m_Thread) {
    m_Thread->join();
    m_Thread.reset(nullptr);
  }
}

void UPnP::Start() {
  if (!m_IsModuleLoaded) {
#ifdef MAC_OSX
    m_Module = dlopen("libminiupnpc.dylib", RTLD_LAZY);
#elif _WIN32
    // official prebuilt binary, e.g., in upnpc-exe-win32-20140422.zip
    m_Module = LoadLibrary("miniupnpc.dll");
#else
    m_Module = dlopen("libminiupnpc.so", RTLD_LAZY);
#endif
    if (m_Module == NULL) {
      LogPrint(eLogError,
          "UPnP: error loading UPNP library.",
          "This often happens if there is version mismatch!");
      return;
    } else {
      upnpDiscoverFunc = GetKnownProcAddress(
          m_Module,
          upnpDiscover);
      UPNP_GetValidIGDFunc = GetKnownProcAddress(
          m_Module,
          UPNP_GetValidIGD);
      UPNP_GetExternalIPAddressFunc = GetKnownProcAddress(
          m_Module,
          UPNP_GetExternalIPAddress);
      UPNP_AddPortMappingFunc = GetKnownProcAddress(
          m_Module,
          UPNP_AddPortMapping);
      UPNP_DeletePortMappingFunc = GetKnownProcAddress(
          m_Module,
          UPNP_DeletePortMapping);
      freeUPNPDevlistFunc = GetKnownProcAddress(
          m_Module,
          freeUPNPDevlist);
      FreeUPNPUrlsFunc = GetKnownProcAddress(
          m_Module,
          FreeUPNPUrls);
      if (upnpDiscoverFunc &&
          UPNP_GetValidIGDFunc &&
          UPNP_GetExternalIPAddressFunc &&
          UPNP_AddPortMappingFunc &&
          UPNP_DeletePortMappingFunc &&
          freeUPNPDevlistFunc &&
          FreeUPNPUrlsFunc)
        m_IsModuleLoaded = true;
    }
  }
  m_Thread =
    std::make_unique<std::thread>(
        std::bind(
            &UPnP::Run,
            this));
}

UPnP::~UPnP() {}

void UPnP::Run() {
  for (auto& address : context.GetRouterInfo().GetAddresses()) {
    if (!address.host.is_v6()) {
      Discover();
      if (address.transport_style == data::RouterInfo::eTransportSSU) {
        TryPortMapping(I2P_UPNP_UDP, address.port);
      } else if (address.transport_style == data::RouterInfo::eTransportNTCP) {
        TryPortMapping(I2P_UPNP_TCP, address.port);
      }
    }
  }
}

void UPnP::Discover() {
#ifndef UPNPDISCOVER_SUCCESS
  /* miniupnpc 1.5 */
  m_Devlist = upnpDiscoverFunc(
      2000,
      m_MulticastIf,
      m_Minissdpdpath,
      0);
#else
  /* miniupnpc 1.6 */
  int nerror = 0;
  m_Devlist = upnpDiscoverFunc(
      2000,
      m_MulticastIf,
      m_Minissdpdpath,
      0,
      0,
      &nerror);
#endif
  int r;
  r = UPNP_GetValidIGDFunc(
      m_Devlist,
      &m_upnpUrls,
      &m_upnpData,
      m_NetworkAddr,
      sizeof(m_NetworkAddr));
  if (r == 1) {
    r = UPNP_GetExternalIPAddressFunc(
        m_upnpUrls.controlURL,
        m_upnpData.first.servicetype,
        m_externalIPAddress);
    if (r != UPNPCOMMAND_SUCCESS) {
      LogPrint(eLogError,
          "UPnP: UPNP_GetExternalIPAddressFunc() returned ", r);
      return;
    } else {
      if (m_externalIPAddress[0]) {
        LogPrint(eLogInfo,
            "UPnP: external IP address: ", m_externalIPAddress);
        i2p::context.UpdateAddress(
            boost::asio::ip::address::from_string(
              m_externalIPAddress));
        return;
      } else {
        LogPrint(eLogError, "UPnP: GetExternalIPAddress failed.");
        return;
      }
    }
  }
}

void UPnP::TryPortMapping(
    int type,
    int port) {
  std::string strType;
  std::string strPort(std::to_string(port));
  switch (type) {
    case I2P_UPNP_TCP:
      strType = "TCP";
      break;
    case I2P_UPNP_UDP:
    default:
      strType = "UDP";
  }
  int r;
  std::string strDesc = "Kovri";
  try {
    for (;;) {
#ifndef UPNPDISCOVER_SUCCESS
      /* miniupnpc 1.5 */
      r = UPNP_AddPortMappingFunc(
          m_upnpUrls.controlURL,
          m_upnpData.first.servicetype,
          strPort.c_str(),
          strPort.c_str(),
          m_NetworkAddr,
          strDesc.c_str(),
          strType.c_str(),
          0);
#else
      /* miniupnpc 1.6 */
      r = UPNP_AddPortMappingFunc(
          m_upnpUrls.controlURL,
          m_upnpData.first.servicetype,
          strPort.c_str(),
          strPort.c_str(),
          m_NetworkAddr,
          strDesc.c_str(),
          strType.c_str(),
          0,
          "0");
#endif
      if (r != UPNPCOMMAND_SUCCESS) {
        LogPrint(eLogError,
            "UPnP: AddPortMapping (", strPort.c_str(),
            ", ", strPort.c_str(),
            ", ", m_NetworkAddr,
            ") failed with code ", r);
        return;
      } else {
        LogPrint(eLogInfo,
            "UPnP: port mapping successful. (", m_NetworkAddr,
            ":", strPort.c_str(),
            " type ", strType.c_str() ,
            " -> ", m_externalIPAddress,
            ":", strPort.c_str(), ")");
        return;
      }
      std::this_thread::sleep_for(std::chrono::minutes(20));  // c++11
      // boost::this_thread::sleep_for(); // pre c++11
      // sleep(20*60); // non-portable
    }
  } catch (boost::thread_interrupted) {
    CloseMapping(type, port);
    Close();
    throw;
  }
}

void UPnP::CloseMapping(
    int type,
    int port) {
  std::string strType,
              strPort(
                  std::to_string(
                    port));
  switch (type) {
    case I2P_UPNP_TCP:
      strType = "TCP";
      break;
    case I2P_UPNP_UDP:
    default:
      strType = "UDP";
  }
  int r = 0;
  r = UPNP_DeletePortMappingFunc(
      m_upnpUrls.controlURL,
      m_upnpData.first.servicetype,
      strPort.c_str(),
      strType.c_str(),
      0);
  LogPrint(eLogInfo,
      "UPnP: UPNP_DeletePortMappingFunc() returned : ", r, "\n");
}

void UPnP::Close() {
  freeUPNPDevlistFunc(m_Devlist);
  m_Devlist = 0;
  FreeUPNPUrlsFunc(&m_upnpUrls);
#ifndef _WIN32
  dlclose(m_Module);
#else
  FreeLibrary(m_Module);
#endif
}

}  // namespace transport
}  // namespace i2p

#endif

ext: cpp

max_stars_repo_name: moneromooo-monero/kovri

max_issues_repo_name: Menutra/kovri

max_forks_repo_name: Menutra/kovri


text:
// Copyright 2018-2019 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_HISTOGRAM_DETAIL_LARGE_INT_HPP
#define BOOST_HISTOGRAM_DETAIL_LARGE_INT_HPP

#include <boost/histogram/detail/operators.hpp>
#include <boost/histogram/detail/safe_comparison.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/function.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/utility.hpp>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
#include <vector>

namespace boost {
namespace histogram {
namespace detail {

template <class T>
using is_unsigned_integral = mp11::mp_and<std::is_integral<T>, std::is_unsigned<T>>;

template <class T>
bool safe_increment(T& t) {
  if (t < (std::numeric_limits<T>::max)()) {
    ++t;
    return true;
  }
  return false;
}

template <class T, class U>
bool safe_radd(T& t, const U& u) {
  static_assert(is_unsigned_integral<T>::value, "T must be unsigned integral type");
  static_assert(is_unsigned_integral<U>::value, "T must be unsigned integral type");
  if (static_cast<T>((std::numeric_limits<T>::max)() - t) >= u) {
    t += static_cast<T>(u); // static_cast to suppress conversion warning
    return true;
  }
  return false;
}

// An integer type which can grow arbitrarily large (until memory is exhausted).
// Use boost.multiprecision.cpp_int in your own code, it is much more sophisticated.
// We use it only to reduce coupling between boost libs.
template <class Allocator>
struct large_int : totally_ordered<large_int<Allocator>, large_int<Allocator>>,
                   partially_ordered<large_int<Allocator>, void> {
  explicit large_int(const Allocator& a = {}) : data(1, 0, a) {}
  explicit large_int(std::uint64_t v, const Allocator& a = {}) : data(1, v, a) {}

  large_int(const large_int&) = default;
  large_int& operator=(const large_int&) = default;
  large_int(large_int&&) = default;
  large_int& operator=(large_int&&) = default;

  large_int& operator=(std::uint64_t o) {
    data = decltype(data)(1, o);
    return *this;
  }

  large_int& operator++() {
    assert(data.size() > 0u);
    std::size_t i = 0;
    while (!safe_increment(data[i])) {
      data[i] = 0;
      ++i;
      if (i == data.size()) {
        data.push_back(1);
        break;
      }
    }
    return *this;
  }

  large_int& operator+=(const large_int& o) {
    if (this == &o) {
      auto tmp{o};
      return operator+=(tmp);
    }
    bool carry = false;
    std::size_t i = 0;
    for (std::uint64_t oi : o.data) {
      auto& di = maybe_extend(i);
      if (carry) {
        if (safe_increment(oi))
          carry = false;
        else {
          ++i;
          continue;
        }
      }
      if (!safe_radd(di, oi)) {
        add_remainder(di, oi);
        carry = true;
      }
      ++i;
    }
    while (carry) {
      auto& di = maybe_extend(i);
      if (safe_increment(di)) break;
      di = 0;
      ++i;
    }
    return *this;
  }

  large_int& operator+=(std::uint64_t o) {
    assert(data.size() > 0u);
    if (safe_radd(data[0], o)) return *this;
    add_remainder(data[0], o);
    // carry the one, data may grow several times
    std::size_t i = 1;
    while (true) {
      auto& di = maybe_extend(i);
      if (safe_increment(di)) break;
      di = 0;
      ++i;
    }
    return *this;
  }

  explicit operator double() const noexcept {
    assert(data.size() > 0u);
    double result = static_cast<double>(data[0]);
    std::size_t i = 0;
    while (++i < data.size())
      result += static_cast<double>(data[i]) * std::pow(2.0, i * 64);
    return result;
  }

  bool operator<(const large_int& o) const noexcept {
    assert(data.size() > 0u);
    assert(o.data.size() > 0u);
    // no leading zeros allowed
    assert(data.size() == 1 || data.back() > 0u);
    assert(o.data.size() == 1 || o.data.back() > 0u);
    if (data.size() < o.data.size()) return true;
    if (data.size() > o.data.size()) return false;
    auto s = data.size();
    while (s > 0u) {
      --s;
      if (data[s] < o.data[s]) return true;
      if (data[s] > o.data[s]) return false;
    }
    return false; // args are equal
  }

  bool operator==(const large_int& o) const noexcept {
    assert(data.size() > 0u);
    assert(o.data.size() > 0u);
    // no leading zeros allowed
    assert(data.size() == 1 || data.back() > 0u);
    assert(o.data.size() == 1 || o.data.back() > 0u);
    if (data.size() != o.data.size()) return false;
    return std::equal(data.begin(), data.end(), o.data.begin());
  }

  template <class U>
  std::enable_if_t<std::is_integral<U>::value, bool> operator<(const U& o) const
      noexcept {
    assert(data.size() > 0u);
    return data.size() == 1 && safe_less()(data[0], o);
  }

  template <class U>
  std::enable_if_t<std::is_integral<U>::value, bool> operator>(const U& o) const
      noexcept {
    assert(data.size() > 0u);
    assert(data.size() == 1 || data.back() > 0u); // no leading zeros allowed
    return data.size() > 1 || safe_less()(o, data[0]);
  }

  template <class U>
  std::enable_if_t<std::is_integral<U>::value, bool> operator==(const U& o) const
      noexcept {
    assert(data.size() > 0u);
    return data.size() == 1 && safe_equal()(data[0], o);
  }

  template <class U>
  std::enable_if_t<std::is_floating_point<U>::value, bool> operator<(const U& o) const
      noexcept {
    return operator double() < o;
  }
  template <class U>
  std::enable_if_t<std::is_floating_point<U>::value, bool> operator>(const U& o) const
      noexcept {
    return operator double() > o;
  }
  template <class U>
  std::enable_if_t<std::is_floating_point<U>::value, bool> operator==(const U& o) const
      noexcept {
    return operator double() == o;
  }

  std::uint64_t& maybe_extend(std::size_t i) {
    while (i >= data.size()) data.push_back(0);
    return data[i];
  }

  static void add_remainder(std::uint64_t& d, const std::uint64_t o) noexcept {
    assert(d > 0u);
    // in decimal system it would look like this:
    // 8 + 8 = 6 = 8 - (9 - 8) - 1
    // 9 + 1 = 0 = 9 - (9 - 1) - 1
    auto tmp = (std::numeric_limits<std::uint64_t>::max)();
    tmp -= o;
    --d -= tmp;
  }

  template <class Archive>
  void serialize(Archive& ar, unsigned /* version */) {
    ar& make_nvp("data", data);
  }

  std::vector<std::uint64_t, Allocator> data;
};

} // namespace detail
} // namespace histogram
} // namespace boost

#endif

max_stars_repo_name: mamil/demo

max_issues_repo_name: mamil/demo

max_forks_repo_name: mamil/demo