43#include <condition_variable> 
   54        template <std::
size_t Instance = 0>
 
   61            typedef std::string buffer_t;
 
   63            typedef std::map<category_id, std::pair<bool, std::string>> category_map_t;
 
   64            typedef std::map<std::thread::id, std::pair<std::shared_ptr<buffer_t>, std::shared_ptr<buffer_t>>> buffer_list_t;
 
   65            typedef std::vector<i_logger*> copy_list_t;
 
   77                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
   78                copies().push_back(&aLogger);
 
 
   82                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
   83                copies().erase(std::remove(copies().begin(), copies().end(), &aLogger), copies().end());
 
 
   87                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
   88                return iLoggingThread != std::nullopt;
 
 
   92                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
   94                    throw logging_thread_already_created();
 
   95                iLoggingThread.emplace([&]()
 
  100                        iCommitSignal.wait(lk, [&]() { 
return any_available() || 
is_destroying(); });
 
 
  110                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  111                return iFilterSeverity;
 
 
  115                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  116                iFilterSeverity = aSeverity;
 
 
  124                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  125                iCategories[aId].first = 
true;
 
  126                iCategories[aId].second = aName.to_std_string_view();
 
  127                for (
auto& copy : copies())
 
  128                    copy->register_category(aId, aName);
 
 
  132                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  133                auto existing = iCategories.find(aId);
 
  134                return existing != iCategories.end() && existing->second.first;
 
 
  138                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  139                auto existing = iCategories.find(aId);
 
  140                if (existing != iCategories.end())
 
  141                    existing->second.first = 
true;
 
  142                for (
auto& copy : copies())
 
  143                    copy->enable_category(aId);
 
 
  147                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  148                auto existing = iCategories.find(aId);
 
  149                if (existing != iCategories.end())
 
  150                    existing->second.first = 
false;
 
  151                for (
auto& copy : copies())
 
  152                    copy->disable_category(aId);
 
 
  157                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  158                return iFormatter != 
nullptr;
 
 
  162                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  163                if (iFormatter != 
nullptr)
 
 
  169                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  170                iFormatter = std::shared_ptr<i_formatter>{ std::shared_ptr<i_formatter>{}, &aFormatter };
 
 
  174                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  175                iFormatter = 
nullptr;
 
 
  187            using i_logger::operator<<;
 
  190                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  192                for (
auto& copy : copies())
 
  193                    (*copy) << aSeverity;
 
 
  198                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  200                for (
auto& copy : copies())
 
  201                    (*copy) << aCategory;
 
 
  211                return iCommitSignalMutex;
 
 
  215                return iCommitSignal;
 
 
  220                    iLoggingThread->join();
 
 
  224                return message_severity_ref();
 
 
  228                message_severity_ref() = aMessageSeverity;
 
 
  232                return message_category_ref();
 
 
  236                message_category_ref() = aid;
 
 
  240                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  242                return existing == iCategories.end() || existing->second.first;
 
 
  247                if (!iLoggingThread || std::this_thread::get_id() == iLoggingThread->get_id())
 
  250                        std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  251                        for (
auto& entry : buffers())
 
  253                            auto& buffers = entry.second;
 
  254                            std::swap(buffers.first, buffers.second);
 
  257                    thread_local buffer_t tempBuffer;
 
  258                    for (
auto& entry : buffers())
 
  260                        auto& buffer = *entry.second.second;
 
  263                            tempBuffer += buffer;
 
 
  277                    while (any_available())
 
  279                        using namespace std::chrono_literals;
 
  280                        std::this_thread::sleep_for(10ms);
 
 
  294                            buffer() += aMessage.to_std_string_view();
 
  295                            NewLogMessage.trigger(aMessage);
 
  299                            thread_local string tempFormattedMessage;
 
  302                            NewLogMessage.trigger(tempFormattedMessage);
 
  303                            tempFormattedMessage.
clear();
 
  308                    for (
auto& copy : copies())
 
  309                        copy->flush(aMessage);
 
 
  315            virtual void commit(buffer_t 
const& aBuffer) = 0;
 
  336            severity const& message_severity_ref()
 const 
  339                return tMessageSeverity;
 
  343                return const_cast<severity&
>(
const_cast<self_type const&
>(*this).message_severity_ref());
 
  348                return tMessageCategory;
 
  352                return const_cast<category_id&
>(
const_cast<self_type const&
>(*this).message_category_ref());
 
  354            bool any_available()
 const 
  356                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  357                for (
auto& entry : buffers())
 
  359                    auto& buffer = *entry.second.first;
 
  365            buffer_t 
const& buffer()
 const 
  367                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  368                thread_local struct cleanup
 
  374                        if (!parentDestroyed)
 
  377                            std::lock_guard<std::recursive_mutex> lg{ parent.mutex() };
 
  378                            parent.buffers().erase(std::this_thread::get_id());
 
  381                } cleanup{ *
this, *
this };
 
  382                auto existing = iBuffers.find(std::this_thread::get_id());
 
  383                if (existing != iBuffers.end())
 
  384                    return *existing->second.first;
 
  385                existing = iBuffers.insert(buffer_list_t::value_type{ std::this_thread::get_id(), buffer_list_t::mapped_type{ std::make_shared<buffer_t>(), std::make_shared<buffer_t>() } }).first;
 
  386                return *existing->second.first;
 
  390                return const_cast<buffer_t&
>(
const_cast<logger const&
>(*this).buffer());
 
  392            buffer_list_t& buffers()
 const 
  394                std::lock_guard<std::recursive_mutex> lg{ 
mutex() };
 
  397            copy_list_t 
const& copies()
 const 
  401            copy_list_t& copies()
 
  406            mutable std::recursive_mutex iMutex;
 
  407            mutable std::mutex iCommitSignalMutex;
 
  408            mutable std::condition_variable iCommitSignal;
 
  409            std::optional<std::thread> iLoggingThread;
 
  411            category_map_t iCategories;
 
  412            std::shared_ptr<i_formatter> iFormatter;
 
  414            mutable buffer_list_t iBuffers;
 
  417            static uuid const& 
iid() { 
static uuid const sIid{ Instance + 0x442ed95b, 0x215c, 0x4b6e, 0xb945, { 0xf9, 0x61, 0xc4, 0xca, 0xd8, 0x7b } }; 
return sIid; }
 
 
void set_destroying() override
bool is_destroying() const final
virtual bool category_enabled(category_id aId) const =0
virtual void enable_category(category_id aId)=0
virtual void register_category(category_id aId, i_string const &aName)=0
virtual void disable_category(category_id aId)=0
bool has_logging_thread() const final
void set_formatter(i_formatter &aFormatter) final
i_logger & operator<<(category_id aCategory) final
void flush(i_string const &aMessage) final
void create_logging_thread() final
void set_message_category(category_id aid)
void reset_line_id(line_id_t aLineId=DefaultInitialLineId) final
void clear_formatter() final
bool has_formatter() const final
severity message_severity() const
void cancel_copy_to(i_logger &aLogger) final
void enable_category(category_id aId) final
void set_message_severity(severity aMessageSeverity)
void disable_category(category_id aId) final
virtual void commit(buffer_t const &aBuffer)=0
std::mutex & commit_signal_mutex() const
void set_filter_severity(severity aSeverity) final
severity filter_severity() const final
std::condition_variable & commit_signal() const
void copy_to(i_logger &aLogger) final
bool category_enabled(category_id aId) const final
i_logger & operator<<(severity aSeverity) final
bool message_category_enabled() const
std::recursive_mutex & mutex() const
line_id_t line_id() const final
void register_category(category_id aId, i_string const &aName) final
static uuid const & iid()
category_id message_category() const
void join_logging_thread()
i_formatter & formatter() const final
std::string_view to_std_string_view() const noexcept
neolib::logger::logger< 9999 > logger
constexpr line_id_t DefaultInitialLineId
lifetime_flag< lifetime_state::Destroyed > destroyed_flag
void swap(plf::hive< element_type, allocator_type > &a, plf::hive< element_type, allocator_type > &b) noexcept(std::allocator_traits< allocator_type >::propagate_on_container_swap::value||std::allocator_traits< allocator_type >::is_always_equal::value)
#define define_declared_event(name, declName,...)