astyle
This commit is contained in:
		@@ -1,168 +1,176 @@
 | 
			
		||||
/*
 | 
			
		||||
A modified version of Bounded MPMC queue by Dmitry Vyukov.
 | 
			
		||||
 | 
			
		||||
Original code from:
 | 
			
		||||
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
 | 
			
		||||
 | 
			
		||||
licensed by Dmitry Vyukov under the terms below:
 | 
			
		||||
 | 
			
		||||
Simplified BSD license
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2010-2011 Dmitry Vyukov. 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.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "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 DMITRY VYUKOV 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.
 | 
			
		||||
 | 
			
		||||
The views and conclusions contained in the software and documentation are those of the authors and
 | 
			
		||||
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
The code in its current form adds the license below:
 | 
			
		||||
 | 
			
		||||
Copyright(c) 2015 Gabi Melman.
 | 
			
		||||
Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "spdlog/common.h"
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace spdlog
 | 
			
		||||
{
 | 
			
		||||
	namespace details
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
		template<typename T>
 | 
			
		||||
		class mpmc_bounded_queue
 | 
			
		||||
		{
 | 
			
		||||
		public:
 | 
			
		||||
 | 
			
		||||
			using item_type = T;
 | 
			
		||||
			mpmc_bounded_queue(size_t buffer_size)
 | 
			
		||||
				:max_size_(buffer_size),
 | 
			
		||||
				buffer_(new cell_t[buffer_size]),
 | 
			
		||||
				buffer_mask_(buffer_size - 1)
 | 
			
		||||
			{
 | 
			
		||||
				//queue size must be power of two
 | 
			
		||||
				if (!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
 | 
			
		||||
					throw spdlog_ex("async logger queue size must be power of two");
 | 
			
		||||
 | 
			
		||||
				for (size_t i = 0; i != buffer_size; i += 1)
 | 
			
		||||
					buffer_[i].sequence_.store(i, std::memory_order_relaxed);
 | 
			
		||||
				enqueue_pos_.store(0, std::memory_order_relaxed);
 | 
			
		||||
				dequeue_pos_.store(0, std::memory_order_relaxed);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			~mpmc_bounded_queue()
 | 
			
		||||
			{
 | 
			
		||||
				delete[] buffer_;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			bool enqueue(T&& data)
 | 
			
		||||
			{
 | 
			
		||||
				cell_t* cell;
 | 
			
		||||
				size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
				for (;;) {
 | 
			
		||||
					cell = &buffer_[pos & buffer_mask_];
 | 
			
		||||
					size_t seq = cell->sequence_.load(std::memory_order_acquire);
 | 
			
		||||
					intptr_t dif = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos);
 | 
			
		||||
					if (dif == 0) {
 | 
			
		||||
						if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
					else if (dif < 0) {
 | 
			
		||||
						return false;
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						pos = enqueue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				cell->data_ = std::move(data);
 | 
			
		||||
				cell->sequence_.store(pos + 1, std::memory_order_release);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool dequeue(T& data)
 | 
			
		||||
			{
 | 
			
		||||
				cell_t* cell;
 | 
			
		||||
				size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
				for (;;) {
 | 
			
		||||
					cell = &buffer_[pos & buffer_mask_];
 | 
			
		||||
					size_t seq =
 | 
			
		||||
						cell->sequence_.load(std::memory_order_acquire);
 | 
			
		||||
					intptr_t dif = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos + 1);
 | 
			
		||||
					if (dif == 0) {
 | 
			
		||||
						if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
					else if (dif < 0)
 | 
			
		||||
						return false;
 | 
			
		||||
					else
 | 
			
		||||
						pos = dequeue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
				}
 | 
			
		||||
				data = std::move(cell->data_);
 | 
			
		||||
				cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool is_empty()
 | 
			
		||||
			{				
 | 
			
		||||
				size_t front, front1, back;
 | 
			
		||||
				// try to take a consistent snapshot of front/tail.
 | 
			
		||||
				do {					
 | 
			
		||||
					front = enqueue_pos_.load(std::memory_order_acquire);
 | 
			
		||||
					back = dequeue_pos_.load(std::memory_order_acquire);
 | 
			
		||||
					front1 = enqueue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
				} while (front != front1);
 | 
			
		||||
				return back == front;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
			struct cell_t
 | 
			
		||||
			{
 | 
			
		||||
				std::atomic<size_t>   sequence_;
 | 
			
		||||
				T                     data_;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			size_t const max_size_;
 | 
			
		||||
 | 
			
		||||
			static size_t const     cacheline_size = 64;
 | 
			
		||||
			typedef char            cacheline_pad_t[cacheline_size];
 | 
			
		||||
 | 
			
		||||
			cacheline_pad_t         pad0_;
 | 
			
		||||
			cell_t* const           buffer_;
 | 
			
		||||
			size_t const            buffer_mask_;
 | 
			
		||||
			cacheline_pad_t         pad1_;
 | 
			
		||||
			std::atomic<size_t>     enqueue_pos_;
 | 
			
		||||
			cacheline_pad_t         pad2_;
 | 
			
		||||
			std::atomic<size_t>     dequeue_pos_;
 | 
			
		||||
			cacheline_pad_t         pad3_;
 | 
			
		||||
 | 
			
		||||
			mpmc_bounded_queue(mpmc_bounded_queue const&) = delete;
 | 
			
		||||
			void operator= (mpmc_bounded_queue const&) = delete;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	} // ns details
 | 
			
		||||
} // ns spdlog
 | 
			
		||||
/*
 | 
			
		||||
A modified version of Bounded MPMC queue by Dmitry Vyukov.
 | 
			
		||||
 | 
			
		||||
Original code from:
 | 
			
		||||
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
 | 
			
		||||
 | 
			
		||||
licensed by Dmitry Vyukov under the terms below:
 | 
			
		||||
 | 
			
		||||
Simplified BSD license
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2010-2011 Dmitry Vyukov. 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.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "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 DMITRY VYUKOV 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.
 | 
			
		||||
 | 
			
		||||
The views and conclusions contained in the software and documentation are those of the authors and
 | 
			
		||||
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
The code in its current form adds the license below:
 | 
			
		||||
 | 
			
		||||
Copyright(c) 2015 Gabi Melman.
 | 
			
		||||
Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "spdlog/common.h"
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace spdlog
 | 
			
		||||
{
 | 
			
		||||
namespace details
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
class mpmc_bounded_queue
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    using item_type = T;
 | 
			
		||||
    mpmc_bounded_queue(size_t buffer_size)
 | 
			
		||||
        :max_size_(buffer_size),
 | 
			
		||||
         buffer_(new cell_t[buffer_size]),
 | 
			
		||||
         buffer_mask_(buffer_size - 1)
 | 
			
		||||
    {
 | 
			
		||||
        //queue size must be power of two
 | 
			
		||||
        if (!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
 | 
			
		||||
            throw spdlog_ex("async logger queue size must be power of two");
 | 
			
		||||
 | 
			
		||||
        for (size_t i = 0; i != buffer_size; i += 1)
 | 
			
		||||
            buffer_[i].sequence_.store(i, std::memory_order_relaxed);
 | 
			
		||||
        enqueue_pos_.store(0, std::memory_order_relaxed);
 | 
			
		||||
        dequeue_pos_.store(0, std::memory_order_relaxed);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~mpmc_bounded_queue()
 | 
			
		||||
    {
 | 
			
		||||
        delete[] buffer_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    bool enqueue(T&& data)
 | 
			
		||||
    {
 | 
			
		||||
        cell_t* cell;
 | 
			
		||||
        size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
        for (;;)
 | 
			
		||||
        {
 | 
			
		||||
            cell = &buffer_[pos & buffer_mask_];
 | 
			
		||||
            size_t seq = cell->sequence_.load(std::memory_order_acquire);
 | 
			
		||||
            intptr_t dif = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos);
 | 
			
		||||
            if (dif == 0)
 | 
			
		||||
            {
 | 
			
		||||
                if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            else if (dif < 0)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                pos = enqueue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        cell->data_ = std::move(data);
 | 
			
		||||
        cell->sequence_.store(pos + 1, std::memory_order_release);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool dequeue(T& data)
 | 
			
		||||
    {
 | 
			
		||||
        cell_t* cell;
 | 
			
		||||
        size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
        for (;;)
 | 
			
		||||
        {
 | 
			
		||||
            cell = &buffer_[pos & buffer_mask_];
 | 
			
		||||
            size_t seq =
 | 
			
		||||
                cell->sequence_.load(std::memory_order_acquire);
 | 
			
		||||
            intptr_t dif = static_cast<intptr_t>(seq) - static_cast<intptr_t>(pos + 1);
 | 
			
		||||
            if (dif == 0)
 | 
			
		||||
            {
 | 
			
		||||
                if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            else if (dif < 0)
 | 
			
		||||
                return false;
 | 
			
		||||
            else
 | 
			
		||||
                pos = dequeue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
        }
 | 
			
		||||
        data = std::move(cell->data_);
 | 
			
		||||
        cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_empty()
 | 
			
		||||
    {
 | 
			
		||||
        size_t front, front1, back;
 | 
			
		||||
        // try to take a consistent snapshot of front/tail.
 | 
			
		||||
        do
 | 
			
		||||
        {
 | 
			
		||||
            front = enqueue_pos_.load(std::memory_order_acquire);
 | 
			
		||||
            back = dequeue_pos_.load(std::memory_order_acquire);
 | 
			
		||||
            front1 = enqueue_pos_.load(std::memory_order_relaxed);
 | 
			
		||||
        }
 | 
			
		||||
        while (front != front1);
 | 
			
		||||
        return back == front;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct cell_t
 | 
			
		||||
    {
 | 
			
		||||
        std::atomic<size_t>   sequence_;
 | 
			
		||||
        T                     data_;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    size_t const max_size_;
 | 
			
		||||
 | 
			
		||||
    static size_t const     cacheline_size = 64;
 | 
			
		||||
    typedef char            cacheline_pad_t[cacheline_size];
 | 
			
		||||
 | 
			
		||||
    cacheline_pad_t         pad0_;
 | 
			
		||||
    cell_t* const           buffer_;
 | 
			
		||||
    size_t const            buffer_mask_;
 | 
			
		||||
    cacheline_pad_t         pad1_;
 | 
			
		||||
    std::atomic<size_t>     enqueue_pos_;
 | 
			
		||||
    cacheline_pad_t         pad2_;
 | 
			
		||||
    std::atomic<size_t>     dequeue_pos_;
 | 
			
		||||
    cacheline_pad_t         pad3_;
 | 
			
		||||
 | 
			
		||||
    mpmc_bounded_queue(mpmc_bounded_queue const&) = delete;
 | 
			
		||||
    void operator= (mpmc_bounded_queue const&) = delete;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // ns details
 | 
			
		||||
} // ns spdlog
 | 
			
		||||
 
 | 
			
		||||
@@ -1,469 +1,469 @@
 | 
			
		||||
//
 | 
			
		||||
// Copyright(c) 2015 Gabi Melman.
 | 
			
		||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | 
			
		||||
//
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "spdlog/common.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <ctime>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
#ifndef NOMINMAX
 | 
			
		||||
#define NOMINMAX //prevent windows redefining min/max
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#endif
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <process.h> //  _get_pid support
 | 
			
		||||
#include <io.h> // _get_osfhandle and _isatty support
 | 
			
		||||
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
#include <share.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else // unix
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
 | 
			
		||||
 | 
			
		||||
#elif __FreeBSD__
 | 
			
		||||
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif //unix
 | 
			
		||||
 | 
			
		||||
#ifndef __has_feature       // Clang - feature checking macros.
 | 
			
		||||
#define __has_feature(x) 0  // Compatibility with non-clang compilers.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace spdlog
 | 
			
		||||
{
 | 
			
		||||
namespace details
 | 
			
		||||
{
 | 
			
		||||
namespace os
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
inline spdlog::log_clock::time_point now()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
 | 
			
		||||
    timespec ts;
 | 
			
		||||
    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
 | 
			
		||||
    return std::chrono::time_point<log_clock, typename log_clock::duration>(
 | 
			
		||||
               std::chrono::duration_cast<typename log_clock::duration>(
 | 
			
		||||
                   std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    return log_clock::now();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
inline std::tm localtime(const std::time_t &time_tt)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    localtime_s(&tm, &time_tt);
 | 
			
		||||
#else
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    localtime_r(&time_tt, &tm);
 | 
			
		||||
#endif
 | 
			
		||||
    return tm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::tm localtime()
 | 
			
		||||
{
 | 
			
		||||
    std::time_t now_t = time(nullptr);
 | 
			
		||||
    return localtime(now_t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline std::tm gmtime(const std::time_t &time_tt)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    gmtime_s(&tm, &time_tt);
 | 
			
		||||
#else
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    gmtime_r(&time_tt, &tm);
 | 
			
		||||
#endif
 | 
			
		||||
    return tm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::tm gmtime()
 | 
			
		||||
{
 | 
			
		||||
    std::time_t now_t = time(nullptr);
 | 
			
		||||
    return gmtime(now_t);
 | 
			
		||||
}
 | 
			
		||||
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
 | 
			
		||||
{
 | 
			
		||||
    return (tm1.tm_sec == tm2.tm_sec &&
 | 
			
		||||
            tm1.tm_min == tm2.tm_min &&
 | 
			
		||||
            tm1.tm_hour == tm2.tm_hour &&
 | 
			
		||||
            tm1.tm_mday == tm2.tm_mday &&
 | 
			
		||||
            tm1.tm_mon == tm2.tm_mon &&
 | 
			
		||||
            tm1.tm_year == tm2.tm_year &&
 | 
			
		||||
            tm1.tm_isdst == tm2.tm_isdst);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
 | 
			
		||||
{
 | 
			
		||||
    return !(tm1 == tm2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eol definition
 | 
			
		||||
#if !defined (SPDLOG_EOL)
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define SPDLOG_EOL "\r\n"
 | 
			
		||||
#else
 | 
			
		||||
#define SPDLOG_EOL "\n"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL;
 | 
			
		||||
SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1;
 | 
			
		||||
 | 
			
		||||
inline void prevent_child_fd(FILE *f)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
 | 
			
		||||
    if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
 | 
			
		||||
        throw spdlog_ex("SetHandleInformation failed", errno);
 | 
			
		||||
#else
 | 
			
		||||
    auto fd = fileno(f);
 | 
			
		||||
    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
 | 
			
		||||
        throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//fopen_s on non windows for writing
 | 
			
		||||
inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#ifdef SPDLOG_WCHAR_FILENAMES
 | 
			
		||||
    *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
 | 
			
		||||
#else
 | 
			
		||||
    *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
 | 
			
		||||
#endif
 | 
			
		||||
#else //unix
 | 
			
		||||
    *fp = fopen((filename.c_str()), mode.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef SPDLOG_PREVENT_CHILD_FD
 | 
			
		||||
    if (*fp != nullptr)
 | 
			
		||||
        prevent_child_fd(*fp);
 | 
			
		||||
#endif
 | 
			
		||||
    return *fp == nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline int remove(const filename_t &filename)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
 | 
			
		||||
    return _wremove(filename.c_str());
 | 
			
		||||
#else
 | 
			
		||||
    return std::remove(filename.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int rename(const filename_t& filename1, const filename_t& filename2)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
 | 
			
		||||
    return _wrename(filename1.c_str(), filename2.c_str());
 | 
			
		||||
#else
 | 
			
		||||
    return std::rename(filename1.c_str(), filename2.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Return if file exists
 | 
			
		||||
inline bool file_exists(const filename_t& filename)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#ifdef SPDLOG_WCHAR_FILENAMES
 | 
			
		||||
    auto attribs = GetFileAttributesW(filename.c_str());
 | 
			
		||||
#else
 | 
			
		||||
    auto attribs = GetFileAttributesA(filename.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
    return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
 | 
			
		||||
#else //common linux/unix all have the stat system call
 | 
			
		||||
    struct stat buffer;
 | 
			
		||||
    return (stat(filename.c_str(), &buffer) == 0);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Return file size according to open FILE* object
 | 
			
		||||
inline size_t filesize(FILE *f)
 | 
			
		||||
{
 | 
			
		||||
    if (f == nullptr)
 | 
			
		||||
        throw spdlog_ex("Failed getting file size. fd is null");
 | 
			
		||||
#if defined ( _WIN32) && !defined(__CYGWIN__)
 | 
			
		||||
    int fd = _fileno(f);
 | 
			
		||||
#if _WIN64 //64 bits
 | 
			
		||||
    struct _stat64 st;
 | 
			
		||||
    if (_fstat64(fd, &st) == 0)
 | 
			
		||||
        return st.st_size;
 | 
			
		||||
 | 
			
		||||
#else //windows 32 bits
 | 
			
		||||
    long ret = _filelength(fd);
 | 
			
		||||
    if (ret >= 0)
 | 
			
		||||
        return static_cast<size_t>(ret);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else // unix
 | 
			
		||||
    int fd = fileno(f);
 | 
			
		||||
    //64 bits(but not in osx or cygwin, where fstat64 is deprecated)
 | 
			
		||||
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
 | 
			
		||||
    struct stat64 st;
 | 
			
		||||
    if (fstat64(fd, &st) == 0)
 | 
			
		||||
        return static_cast<size_t>(st.st_size);
 | 
			
		||||
#else // unix 32 bits or cygwin
 | 
			
		||||
    struct stat st;
 | 
			
		||||
    if (fstat(fd, &st) == 0)
 | 
			
		||||
        return static_cast<size_t>(st.st_size);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
    throw spdlog_ex("Failed getting file size from fd", errno);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Return utc offset in minutes or throw spdlog_ex on failure
 | 
			
		||||
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
 | 
			
		||||
    TIME_ZONE_INFORMATION tzinfo;
 | 
			
		||||
    auto rv = GetTimeZoneInformation(&tzinfo);
 | 
			
		||||
#else
 | 
			
		||||
    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
 | 
			
		||||
    auto rv = GetDynamicTimeZoneInformation(&tzinfo);
 | 
			
		||||
#endif
 | 
			
		||||
    if (rv == TIME_ZONE_ID_INVALID)
 | 
			
		||||
        throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
 | 
			
		||||
 | 
			
		||||
    int offset = -tzinfo.Bias;
 | 
			
		||||
    if (tm.tm_isdst)
 | 
			
		||||
        offset -= tzinfo.DaylightBias;
 | 
			
		||||
    else
 | 
			
		||||
        offset -= tzinfo.StandardBias;
 | 
			
		||||
    return offset;
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#if defined(sun) || defined(__sun)
 | 
			
		||||
    // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
 | 
			
		||||
    struct helper
 | 
			
		||||
    {
 | 
			
		||||
        static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime())
 | 
			
		||||
        {
 | 
			
		||||
            int local_year = localtm.tm_year + (1900 - 1);
 | 
			
		||||
            int gmt_year = gmtm.tm_year + (1900 - 1);
 | 
			
		||||
 | 
			
		||||
            long int days = (
 | 
			
		||||
                                // difference in day of year
 | 
			
		||||
                                localtm.tm_yday - gmtm.tm_yday
 | 
			
		||||
 | 
			
		||||
                                // + intervening leap days
 | 
			
		||||
                                + ((local_year >> 2) - (gmt_year >> 2))
 | 
			
		||||
                                - (local_year / 100 - gmt_year / 100)
 | 
			
		||||
                                + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
 | 
			
		||||
 | 
			
		||||
                                // + difference in years * 365 */
 | 
			
		||||
                                + (long int)(local_year - gmt_year) * 365
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
            long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
 | 
			
		||||
            long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
 | 
			
		||||
            long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
 | 
			
		||||
 | 
			
		||||
            return secs;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    long int offset_seconds = helper::calculate_gmt_offset(tm);
 | 
			
		||||
#else
 | 
			
		||||
    long int offset_seconds = tm.tm_gmtoff;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return static_cast<int>(offset_seconds / 60);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Return current thread id as size_t
 | 
			
		||||
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
 | 
			
		||||
inline size_t _thread_id()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return  static_cast<size_t>(::GetCurrentThreadId());
 | 
			
		||||
#elif __linux__
 | 
			
		||||
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
 | 
			
		||||
#  define SYS_gettid __NR_gettid
 | 
			
		||||
# endif
 | 
			
		||||
    return  static_cast<size_t>(syscall(SYS_gettid));
 | 
			
		||||
#elif __FreeBSD__
 | 
			
		||||
    long tid;
 | 
			
		||||
    thr_self(&tid);
 | 
			
		||||
    return static_cast<size_t>(tid);
 | 
			
		||||
#elif __APPLE__
 | 
			
		||||
    uint64_t tid;
 | 
			
		||||
    pthread_threadid_np(nullptr, &tid);
 | 
			
		||||
    return static_cast<size_t>(tid);
 | 
			
		||||
#else //Default to standard C++11 (other Unix)
 | 
			
		||||
    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Return current thread id as size_t (from thread local storage)
 | 
			
		||||
inline size_t thread_id()
 | 
			
		||||
{
 | 
			
		||||
#if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local)
 | 
			
		||||
    return _thread_id();
 | 
			
		||||
#else
 | 
			
		||||
    static thread_local const size_t tid = _thread_id();
 | 
			
		||||
    return tid;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
 | 
			
		||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
 | 
			
		||||
#define SPDLOG_FILENAME_T(s) L ## s
 | 
			
		||||
inline std::string filename_to_str(const filename_t& filename)
 | 
			
		||||
{
 | 
			
		||||
    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
 | 
			
		||||
    return c.to_bytes(filename);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define SPDLOG_FILENAME_T(s) s
 | 
			
		||||
inline std::string filename_to_str(const filename_t& filename)
 | 
			
		||||
{
 | 
			
		||||
    return filename;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline std::string errno_to_string(char[256], char* res)
 | 
			
		||||
{
 | 
			
		||||
    return std::string(res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::string errno_to_string(char buf[256], int res)
 | 
			
		||||
{
 | 
			
		||||
    if (res == 0)
 | 
			
		||||
    {
 | 
			
		||||
        return std::string(buf);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return "Unknown error";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return errno string (thread safe)
 | 
			
		||||
inline std::string errno_str(int err_num)
 | 
			
		||||
{
 | 
			
		||||
    char buf[256];
 | 
			
		||||
    SPDLOG_CONSTEXPR auto buf_size = sizeof(buf);
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    if (strerror_s(buf, buf_size, err_num) == 0)
 | 
			
		||||
        return std::string(buf);
 | 
			
		||||
    else
 | 
			
		||||
        return "Unknown error";
 | 
			
		||||
 | 
			
		||||
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
 | 
			
		||||
      ((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version
 | 
			
		||||
 | 
			
		||||
    if (strerror_r(err_num, buf, buf_size) == 0)
 | 
			
		||||
        return std::string(buf);
 | 
			
		||||
    else
 | 
			
		||||
        return "Unknown error";
 | 
			
		||||
 | 
			
		||||
#else  // gnu version (might not use the given buf, so its retval pointer must be used)
 | 
			
		||||
    auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type
 | 
			
		||||
    return errno_to_string(buf, err); // use overloading to select correct stringify function
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int pid()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return ::_getpid();
 | 
			
		||||
#else
 | 
			
		||||
    return static_cast<int>(::getpid());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Detrmine if the terminal supports colors
 | 
			
		||||
// Source: https://github.com/agauniyal/rang/
 | 
			
		||||
inline bool is_color_terminal()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return true;
 | 
			
		||||
#else
 | 
			
		||||
    static constexpr const char* Terms[] =
 | 
			
		||||
    {
 | 
			
		||||
        "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
 | 
			
		||||
        "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const char *env_p = std::getenv("TERM");
 | 
			
		||||
    if (env_p == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const bool result = std::any_of(
 | 
			
		||||
                                   std::begin(Terms), std::end(Terms), [&](const char* term)
 | 
			
		||||
    {
 | 
			
		||||
        return std::strstr(env_p, term) != nullptr;
 | 
			
		||||
    });
 | 
			
		||||
    return result;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Detrmine if the terminal attached
 | 
			
		||||
// Source: https://github.com/agauniyal/rang/
 | 
			
		||||
inline bool in_terminal(FILE* file)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return _isatty(_fileno(file)) ? true : false;
 | 
			
		||||
#else
 | 
			
		||||
    return isatty(fileno(file)) ? true : false;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
} //os
 | 
			
		||||
} //details
 | 
			
		||||
} //spdlog
 | 
			
		||||
//
 | 
			
		||||
// Copyright(c) 2015 Gabi Melman.
 | 
			
		||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | 
			
		||||
//
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "spdlog/common.h"
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <ctime>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 | 
			
		||||
#ifndef NOMINMAX
 | 
			
		||||
#define NOMINMAX //prevent windows redefining min/max
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#endif
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <process.h> //  _get_pid support
 | 
			
		||||
#include <io.h> // _get_osfhandle and _isatty support
 | 
			
		||||
 | 
			
		||||
#ifdef __MINGW32__
 | 
			
		||||
#include <share.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else // unix
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
 | 
			
		||||
 | 
			
		||||
#elif __FreeBSD__
 | 
			
		||||
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif //unix
 | 
			
		||||
 | 
			
		||||
#ifndef __has_feature       // Clang - feature checking macros.
 | 
			
		||||
#define __has_feature(x) 0  // Compatibility with non-clang compilers.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace spdlog
 | 
			
		||||
{
 | 
			
		||||
namespace details
 | 
			
		||||
{
 | 
			
		||||
namespace os
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
inline spdlog::log_clock::time_point now()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
 | 
			
		||||
    timespec ts;
 | 
			
		||||
    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
 | 
			
		||||
    return std::chrono::time_point<log_clock, typename log_clock::duration>(
 | 
			
		||||
               std::chrono::duration_cast<typename log_clock::duration>(
 | 
			
		||||
                   std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    return log_clock::now();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
inline std::tm localtime(const std::time_t &time_tt)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    localtime_s(&tm, &time_tt);
 | 
			
		||||
#else
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    localtime_r(&time_tt, &tm);
 | 
			
		||||
#endif
 | 
			
		||||
    return tm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::tm localtime()
 | 
			
		||||
{
 | 
			
		||||
    std::time_t now_t = time(nullptr);
 | 
			
		||||
    return localtime(now_t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline std::tm gmtime(const std::time_t &time_tt)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    gmtime_s(&tm, &time_tt);
 | 
			
		||||
#else
 | 
			
		||||
    std::tm tm;
 | 
			
		||||
    gmtime_r(&time_tt, &tm);
 | 
			
		||||
#endif
 | 
			
		||||
    return tm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::tm gmtime()
 | 
			
		||||
{
 | 
			
		||||
    std::time_t now_t = time(nullptr);
 | 
			
		||||
    return gmtime(now_t);
 | 
			
		||||
}
 | 
			
		||||
inline bool operator==(const std::tm& tm1, const std::tm& tm2)
 | 
			
		||||
{
 | 
			
		||||
    return (tm1.tm_sec == tm2.tm_sec &&
 | 
			
		||||
            tm1.tm_min == tm2.tm_min &&
 | 
			
		||||
            tm1.tm_hour == tm2.tm_hour &&
 | 
			
		||||
            tm1.tm_mday == tm2.tm_mday &&
 | 
			
		||||
            tm1.tm_mon == tm2.tm_mon &&
 | 
			
		||||
            tm1.tm_year == tm2.tm_year &&
 | 
			
		||||
            tm1.tm_isdst == tm2.tm_isdst);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
 | 
			
		||||
{
 | 
			
		||||
    return !(tm1 == tm2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eol definition
 | 
			
		||||
#if !defined (SPDLOG_EOL)
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define SPDLOG_EOL "\r\n"
 | 
			
		||||
#else
 | 
			
		||||
#define SPDLOG_EOL "\n"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL;
 | 
			
		||||
SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1;
 | 
			
		||||
 | 
			
		||||
inline void prevent_child_fd(FILE *f)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
 | 
			
		||||
    if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
 | 
			
		||||
        throw spdlog_ex("SetHandleInformation failed", errno);
 | 
			
		||||
#else
 | 
			
		||||
    auto fd = fileno(f);
 | 
			
		||||
    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
 | 
			
		||||
        throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//fopen_s on non windows for writing
 | 
			
		||||
inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#ifdef SPDLOG_WCHAR_FILENAMES
 | 
			
		||||
    *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
 | 
			
		||||
#else
 | 
			
		||||
    *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
 | 
			
		||||
#endif
 | 
			
		||||
#else //unix
 | 
			
		||||
    *fp = fopen((filename.c_str()), mode.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef SPDLOG_PREVENT_CHILD_FD
 | 
			
		||||
    if (*fp != nullptr)
 | 
			
		||||
        prevent_child_fd(*fp);
 | 
			
		||||
#endif
 | 
			
		||||
    return *fp == nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline int remove(const filename_t &filename)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
 | 
			
		||||
    return _wremove(filename.c_str());
 | 
			
		||||
#else
 | 
			
		||||
    return std::remove(filename.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int rename(const filename_t& filename1, const filename_t& filename2)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
 | 
			
		||||
    return _wrename(filename1.c_str(), filename2.c_str());
 | 
			
		||||
#else
 | 
			
		||||
    return std::rename(filename1.c_str(), filename2.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Return if file exists
 | 
			
		||||
inline bool file_exists(const filename_t& filename)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#ifdef SPDLOG_WCHAR_FILENAMES
 | 
			
		||||
    auto attribs = GetFileAttributesW(filename.c_str());
 | 
			
		||||
#else
 | 
			
		||||
    auto attribs = GetFileAttributesA(filename.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
    return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
 | 
			
		||||
#else //common linux/unix all have the stat system call
 | 
			
		||||
    struct stat buffer;
 | 
			
		||||
    return (stat(filename.c_str(), &buffer) == 0);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Return file size according to open FILE* object
 | 
			
		||||
inline size_t filesize(FILE *f)
 | 
			
		||||
{
 | 
			
		||||
    if (f == nullptr)
 | 
			
		||||
        throw spdlog_ex("Failed getting file size. fd is null");
 | 
			
		||||
#if defined ( _WIN32) && !defined(__CYGWIN__)
 | 
			
		||||
    int fd = _fileno(f);
 | 
			
		||||
#if _WIN64 //64 bits
 | 
			
		||||
    struct _stat64 st;
 | 
			
		||||
    if (_fstat64(fd, &st) == 0)
 | 
			
		||||
        return st.st_size;
 | 
			
		||||
 | 
			
		||||
#else //windows 32 bits
 | 
			
		||||
    long ret = _filelength(fd);
 | 
			
		||||
    if (ret >= 0)
 | 
			
		||||
        return static_cast<size_t>(ret);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else // unix
 | 
			
		||||
    int fd = fileno(f);
 | 
			
		||||
    //64 bits(but not in osx or cygwin, where fstat64 is deprecated)
 | 
			
		||||
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
 | 
			
		||||
    struct stat64 st;
 | 
			
		||||
    if (fstat64(fd, &st) == 0)
 | 
			
		||||
        return static_cast<size_t>(st.st_size);
 | 
			
		||||
#else // unix 32 bits or cygwin
 | 
			
		||||
    struct stat st;
 | 
			
		||||
    if (fstat(fd, &st) == 0)
 | 
			
		||||
        return static_cast<size_t>(st.st_size);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
    throw spdlog_ex("Failed getting file size from fd", errno);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//Return utc offset in minutes or throw spdlog_ex on failure
 | 
			
		||||
inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
 | 
			
		||||
    TIME_ZONE_INFORMATION tzinfo;
 | 
			
		||||
    auto rv = GetTimeZoneInformation(&tzinfo);
 | 
			
		||||
#else
 | 
			
		||||
    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
 | 
			
		||||
    auto rv = GetDynamicTimeZoneInformation(&tzinfo);
 | 
			
		||||
#endif
 | 
			
		||||
    if (rv == TIME_ZONE_ID_INVALID)
 | 
			
		||||
        throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
 | 
			
		||||
 | 
			
		||||
    int offset = -tzinfo.Bias;
 | 
			
		||||
    if (tm.tm_isdst)
 | 
			
		||||
        offset -= tzinfo.DaylightBias;
 | 
			
		||||
    else
 | 
			
		||||
        offset -= tzinfo.StandardBias;
 | 
			
		||||
    return offset;
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#if defined(sun) || defined(__sun)
 | 
			
		||||
    // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
 | 
			
		||||
    struct helper
 | 
			
		||||
    {
 | 
			
		||||
        static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime())
 | 
			
		||||
        {
 | 
			
		||||
            int local_year = localtm.tm_year + (1900 - 1);
 | 
			
		||||
            int gmt_year = gmtm.tm_year + (1900 - 1);
 | 
			
		||||
 | 
			
		||||
            long int days = (
 | 
			
		||||
                                // difference in day of year
 | 
			
		||||
                                localtm.tm_yday - gmtm.tm_yday
 | 
			
		||||
 | 
			
		||||
                                // + intervening leap days
 | 
			
		||||
                                + ((local_year >> 2) - (gmt_year >> 2))
 | 
			
		||||
                                - (local_year / 100 - gmt_year / 100)
 | 
			
		||||
                                + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
 | 
			
		||||
 | 
			
		||||
                                // + difference in years * 365 */
 | 
			
		||||
                                + (long int)(local_year - gmt_year) * 365
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
            long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
 | 
			
		||||
            long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
 | 
			
		||||
            long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
 | 
			
		||||
 | 
			
		||||
            return secs;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    long int offset_seconds = helper::calculate_gmt_offset(tm);
 | 
			
		||||
#else
 | 
			
		||||
    long int offset_seconds = tm.tm_gmtoff;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return static_cast<int>(offset_seconds / 60);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Return current thread id as size_t
 | 
			
		||||
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
 | 
			
		||||
inline size_t _thread_id()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return  static_cast<size_t>(::GetCurrentThreadId());
 | 
			
		||||
#elif __linux__
 | 
			
		||||
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
 | 
			
		||||
#  define SYS_gettid __NR_gettid
 | 
			
		||||
# endif
 | 
			
		||||
    return  static_cast<size_t>(syscall(SYS_gettid));
 | 
			
		||||
#elif __FreeBSD__
 | 
			
		||||
    long tid;
 | 
			
		||||
    thr_self(&tid);
 | 
			
		||||
    return static_cast<size_t>(tid);
 | 
			
		||||
#elif __APPLE__
 | 
			
		||||
    uint64_t tid;
 | 
			
		||||
    pthread_threadid_np(nullptr, &tid);
 | 
			
		||||
    return static_cast<size_t>(tid);
 | 
			
		||||
#else //Default to standard C++11 (other Unix)
 | 
			
		||||
    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Return current thread id as size_t (from thread local storage)
 | 
			
		||||
inline size_t thread_id()
 | 
			
		||||
{
 | 
			
		||||
#if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local)
 | 
			
		||||
    return _thread_id();
 | 
			
		||||
#else
 | 
			
		||||
    static thread_local const size_t tid = _thread_id();
 | 
			
		||||
    return tid;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
 | 
			
		||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
 | 
			
		||||
#define SPDLOG_FILENAME_T(s) L ## s
 | 
			
		||||
inline std::string filename_to_str(const filename_t& filename)
 | 
			
		||||
{
 | 
			
		||||
    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
 | 
			
		||||
    return c.to_bytes(filename);
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define SPDLOG_FILENAME_T(s) s
 | 
			
		||||
inline std::string filename_to_str(const filename_t& filename)
 | 
			
		||||
{
 | 
			
		||||
    return filename;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline std::string errno_to_string(char[256], char* res)
 | 
			
		||||
{
 | 
			
		||||
    return std::string(res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline std::string errno_to_string(char buf[256], int res)
 | 
			
		||||
{
 | 
			
		||||
    if (res == 0)
 | 
			
		||||
    {
 | 
			
		||||
        return std::string(buf);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return "Unknown error";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Return errno string (thread safe)
 | 
			
		||||
inline std::string errno_str(int err_num)
 | 
			
		||||
{
 | 
			
		||||
    char buf[256];
 | 
			
		||||
    SPDLOG_CONSTEXPR auto buf_size = sizeof(buf);
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    if (strerror_s(buf, buf_size, err_num) == 0)
 | 
			
		||||
        return std::string(buf);
 | 
			
		||||
    else
 | 
			
		||||
        return "Unknown error";
 | 
			
		||||
 | 
			
		||||
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
 | 
			
		||||
      ((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version
 | 
			
		||||
 | 
			
		||||
    if (strerror_r(err_num, buf, buf_size) == 0)
 | 
			
		||||
        return std::string(buf);
 | 
			
		||||
    else
 | 
			
		||||
        return "Unknown error";
 | 
			
		||||
 | 
			
		||||
#else  // gnu version (might not use the given buf, so its retval pointer must be used)
 | 
			
		||||
    auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type
 | 
			
		||||
    return errno_to_string(buf, err); // use overloading to select correct stringify function
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int pid()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return ::_getpid();
 | 
			
		||||
#else
 | 
			
		||||
    return static_cast<int>(::getpid());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Detrmine if the terminal supports colors
 | 
			
		||||
// Source: https://github.com/agauniyal/rang/
 | 
			
		||||
inline bool is_color_terminal()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return true;
 | 
			
		||||
#else
 | 
			
		||||
    static constexpr const char* Terms[] =
 | 
			
		||||
    {
 | 
			
		||||
        "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
 | 
			
		||||
        "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const char *env_p = std::getenv("TERM");
 | 
			
		||||
    if (env_p == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static const bool result = std::any_of(
 | 
			
		||||
                                   std::begin(Terms), std::end(Terms), [&](const char* term)
 | 
			
		||||
    {
 | 
			
		||||
        return std::strstr(env_p, term) != nullptr;
 | 
			
		||||
    });
 | 
			
		||||
    return result;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Detrmine if the terminal attached
 | 
			
		||||
// Source: https://github.com/agauniyal/rang/
 | 
			
		||||
inline bool in_terminal(FILE* file)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    return _isatty(_fileno(file)) ? true : false;
 | 
			
		||||
#else
 | 
			
		||||
    return isatty(fileno(file)) ? true : false;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
} //os
 | 
			
		||||
} //details
 | 
			
		||||
} //spdlog
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -13,57 +13,65 @@
 | 
			
		||||
#include "format.h"
 | 
			
		||||
#include <ostream>
 | 
			
		||||
 | 
			
		||||
namespace fmt {
 | 
			
		||||
namespace fmt
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace internal {
 | 
			
		||||
namespace internal
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <class Char>
 | 
			
		||||
class FormatBuf : public std::basic_streambuf<Char> {
 | 
			
		||||
 private:
 | 
			
		||||
  typedef typename std::basic_streambuf<Char>::int_type int_type;
 | 
			
		||||
  typedef typename std::basic_streambuf<Char>::traits_type traits_type;
 | 
			
		||||
class FormatBuf : public std::basic_streambuf<Char>
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    typedef typename std::basic_streambuf<Char>::int_type int_type;
 | 
			
		||||
    typedef typename std::basic_streambuf<Char>::traits_type traits_type;
 | 
			
		||||
 | 
			
		||||
  Buffer<Char> &buffer_;
 | 
			
		||||
    Buffer<Char> &buffer_;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
 | 
			
		||||
public:
 | 
			
		||||
    FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  // The put-area is actually always empty. This makes the implementation
 | 
			
		||||
  // simpler and has the advantage that the streambuf and the buffer are always
 | 
			
		||||
  // in sync and sputc never writes into uninitialized memory. The obvious
 | 
			
		||||
  // disadvantage is that each call to sputc always results in a (virtual) call
 | 
			
		||||
  // to overflow. There is no disadvantage here for sputn since this always
 | 
			
		||||
  // results in a call to xsputn.
 | 
			
		||||
protected:
 | 
			
		||||
    // The put-area is actually always empty. This makes the implementation
 | 
			
		||||
    // simpler and has the advantage that the streambuf and the buffer are always
 | 
			
		||||
    // in sync and sputc never writes into uninitialized memory. The obvious
 | 
			
		||||
    // disadvantage is that each call to sputc always results in a (virtual) call
 | 
			
		||||
    // to overflow. There is no disadvantage here for sputn since this always
 | 
			
		||||
    // results in a call to xsputn.
 | 
			
		||||
 | 
			
		||||
  int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
 | 
			
		||||
    if (!traits_type::eq_int_type(ch, traits_type::eof()))
 | 
			
		||||
      buffer_.push_back(static_cast<Char>(ch));
 | 
			
		||||
    return ch;
 | 
			
		||||
  }
 | 
			
		||||
    int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE
 | 
			
		||||
    {
 | 
			
		||||
        if (!traits_type::eq_int_type(ch, traits_type::eof()))
 | 
			
		||||
            buffer_.push_back(static_cast<Char>(ch));
 | 
			
		||||
        return ch;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
 | 
			
		||||
    buffer_.append(s, s + count);
 | 
			
		||||
    return count;
 | 
			
		||||
  }
 | 
			
		||||
    std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE
 | 
			
		||||
    {
 | 
			
		||||
        buffer_.append(s, s + count);
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Yes &convert(std::ostream &);
 | 
			
		||||
 | 
			
		||||
struct DummyStream : std::ostream {
 | 
			
		||||
  DummyStream();  // Suppress a bogus warning in MSVC.
 | 
			
		||||
  // Hide all operator<< overloads from std::ostream.
 | 
			
		||||
  void operator<<(Null<>);
 | 
			
		||||
struct DummyStream : std::ostream
 | 
			
		||||
{
 | 
			
		||||
    DummyStream();  // Suppress a bogus warning in MSVC.
 | 
			
		||||
    // Hide all operator<< overloads from std::ostream.
 | 
			
		||||
    void operator<<(Null<>);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
No &operator<<(std::ostream &, int);
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct ConvertToIntImpl<T, true> {
 | 
			
		||||
  // Convert to int only if T doesn't have an overloaded operator<<.
 | 
			
		||||
  enum {
 | 
			
		||||
    value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
 | 
			
		||||
  };
 | 
			
		||||
struct ConvertToIntImpl<T, true>
 | 
			
		||||
{
 | 
			
		||||
    // Convert to int only if T doesn't have an overloaded operator<<.
 | 
			
		||||
    enum
 | 
			
		||||
    {
 | 
			
		||||
        value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Write the content of w to os.
 | 
			
		||||
@@ -73,16 +81,17 @@ FMT_API void write(std::ostream &os, Writer &w);
 | 
			
		||||
// Formats a value.
 | 
			
		||||
template <typename Char, typename ArgFormatter_, typename T>
 | 
			
		||||
void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
 | 
			
		||||
                const Char *&format_str, const T &value) {
 | 
			
		||||
  internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
 | 
			
		||||
                const Char *&format_str, const T &value)
 | 
			
		||||
{
 | 
			
		||||
    internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
 | 
			
		||||
 | 
			
		||||
  internal::FormatBuf<Char> format_buf(buffer);
 | 
			
		||||
  std::basic_ostream<Char> output(&format_buf);
 | 
			
		||||
  output << value;
 | 
			
		||||
    internal::FormatBuf<Char> format_buf(buffer);
 | 
			
		||||
    std::basic_ostream<Char> output(&format_buf);
 | 
			
		||||
    output << value;
 | 
			
		||||
 | 
			
		||||
  BasicStringRef<Char> str(&buffer[0], buffer.size());
 | 
			
		||||
  typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
 | 
			
		||||
  format_str = f.format(format_str, MakeArg(str));
 | 
			
		||||
    BasicStringRef<Char> str(&buffer[0], buffer.size());
 | 
			
		||||
    typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
 | 
			
		||||
    format_str = f.format(format_str, MakeArg(str));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -64,112 +64,134 @@
 | 
			
		||||
 | 
			
		||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
 | 
			
		||||
 | 
			
		||||
namespace fmt {
 | 
			
		||||
namespace fmt
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
// An error code.
 | 
			
		||||
class ErrorCode {
 | 
			
		||||
 private:
 | 
			
		||||
  int value_;
 | 
			
		||||
class ErrorCode
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    int value_;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
 | 
			
		||||
public:
 | 
			
		||||
explicit ErrorCode(int value = 0) FMT_NOEXCEPT :
 | 
			
		||||
    value_(value) {}
 | 
			
		||||
 | 
			
		||||
  int get() const FMT_NOEXCEPT { return value_; }
 | 
			
		||||
    int get() const FMT_NOEXCEPT
 | 
			
		||||
    {
 | 
			
		||||
        return value_;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// A buffered file.
 | 
			
		||||
class BufferedFile {
 | 
			
		||||
 private:
 | 
			
		||||
  FILE *file_;
 | 
			
		||||
class BufferedFile
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    FILE *file_;
 | 
			
		||||
 | 
			
		||||
  friend class File;
 | 
			
		||||
    friend class File;
 | 
			
		||||
 | 
			
		||||
  explicit BufferedFile(FILE *f) : file_(f) {}
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  // Constructs a BufferedFile object which doesn't represent any file.
 | 
			
		||||
  BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
 | 
			
		||||
 | 
			
		||||
  // Destroys the object closing the file it represents if any.
 | 
			
		||||
  FMT_API ~BufferedFile() FMT_NOEXCEPT;
 | 
			
		||||
 | 
			
		||||
#if !FMT_USE_RVALUE_REFERENCES
 | 
			
		||||
  // Emulate a move constructor and a move assignment operator if rvalue
 | 
			
		||||
  // references are not supported.
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  // A proxy object to emulate a move constructor.
 | 
			
		||||
  // It is private to make it impossible call operator Proxy directly.
 | 
			
		||||
  struct Proxy {
 | 
			
		||||
    FILE *file;
 | 
			
		||||
  };
 | 
			
		||||
    explicit BufferedFile(FILE *f) : file_(f) {}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  // A "move constructor" for moving from a temporary.
 | 
			
		||||
  BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
 | 
			
		||||
    // Constructs a BufferedFile object which doesn't represent any file.
 | 
			
		||||
BufferedFile() FMT_NOEXCEPT :
 | 
			
		||||
    file_(FMT_NULL) {}
 | 
			
		||||
 | 
			
		||||
  // A "move constructor" for moving from an lvalue.
 | 
			
		||||
  BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
 | 
			
		||||
    f.file_ = FMT_NULL;
 | 
			
		||||
  }
 | 
			
		||||
    // Destroys the object closing the file it represents if any.
 | 
			
		||||
    FMT_API ~BufferedFile() FMT_NOEXCEPT;
 | 
			
		||||
 | 
			
		||||
  // A "move assignment operator" for moving from a temporary.
 | 
			
		||||
  BufferedFile &operator=(Proxy p) {
 | 
			
		||||
    close();
 | 
			
		||||
    file_ = p.file;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
#if !FMT_USE_RVALUE_REFERENCES
 | 
			
		||||
    // Emulate a move constructor and a move assignment operator if rvalue
 | 
			
		||||
    // references are not supported.
 | 
			
		||||
 | 
			
		||||
  // A "move assignment operator" for moving from an lvalue.
 | 
			
		||||
  BufferedFile &operator=(BufferedFile &other) {
 | 
			
		||||
    close();
 | 
			
		||||
    file_ = other.file_;
 | 
			
		||||
    other.file_ = FMT_NULL;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
private:
 | 
			
		||||
    // A proxy object to emulate a move constructor.
 | 
			
		||||
    // It is private to make it impossible call operator Proxy directly.
 | 
			
		||||
    struct Proxy
 | 
			
		||||
    {
 | 
			
		||||
        FILE *file;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  // Returns a proxy object for moving from a temporary:
 | 
			
		||||
  //   BufferedFile file = BufferedFile(...);
 | 
			
		||||
  operator Proxy() FMT_NOEXCEPT {
 | 
			
		||||
    Proxy p = {file_};
 | 
			
		||||
    file_ = FMT_NULL;
 | 
			
		||||
    return p;
 | 
			
		||||
  }
 | 
			
		||||
public:
 | 
			
		||||
    // A "move constructor" for moving from a temporary.
 | 
			
		||||
BufferedFile(Proxy p) FMT_NOEXCEPT :
 | 
			
		||||
    file_(p.file) {}
 | 
			
		||||
 | 
			
		||||
    // A "move constructor" for moving from an lvalue.
 | 
			
		||||
BufferedFile(BufferedFile &f) FMT_NOEXCEPT :
 | 
			
		||||
    file_(f.file_)
 | 
			
		||||
    {
 | 
			
		||||
        f.file_ = FMT_NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A "move assignment operator" for moving from a temporary.
 | 
			
		||||
    BufferedFile &operator=(Proxy p)
 | 
			
		||||
    {
 | 
			
		||||
        close();
 | 
			
		||||
        file_ = p.file;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A "move assignment operator" for moving from an lvalue.
 | 
			
		||||
    BufferedFile &operator=(BufferedFile &other)
 | 
			
		||||
    {
 | 
			
		||||
        close();
 | 
			
		||||
        file_ = other.file_;
 | 
			
		||||
        other.file_ = FMT_NULL;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns a proxy object for moving from a temporary:
 | 
			
		||||
    //   BufferedFile file = BufferedFile(...);
 | 
			
		||||
    operator Proxy() FMT_NOEXCEPT
 | 
			
		||||
    {
 | 
			
		||||
        Proxy p = {file_};
 | 
			
		||||
        file_ = FMT_NULL;
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 private:
 | 
			
		||||
  FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
 | 
			
		||||
private:
 | 
			
		||||
    FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
 | 
			
		||||
    other.file_ = FMT_NULL;
 | 
			
		||||
  }
 | 
			
		||||
public:
 | 
			
		||||
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT :
 | 
			
		||||
    file_(other.file_)
 | 
			
		||||
    {
 | 
			
		||||
        other.file_ = FMT_NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  BufferedFile& operator=(BufferedFile &&other) {
 | 
			
		||||
    close();
 | 
			
		||||
    file_ = other.file_;
 | 
			
		||||
    other.file_ = FMT_NULL;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
    BufferedFile& operator=(BufferedFile &&other)
 | 
			
		||||
    {
 | 
			
		||||
        close();
 | 
			
		||||
        file_ = other.file_;
 | 
			
		||||
        other.file_ = FMT_NULL;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Opens a file.
 | 
			
		||||
  FMT_API BufferedFile(CStringRef filename, CStringRef mode);
 | 
			
		||||
    // Opens a file.
 | 
			
		||||
    FMT_API BufferedFile(CStringRef filename, CStringRef mode);
 | 
			
		||||
 | 
			
		||||
  // Closes the file.
 | 
			
		||||
  FMT_API void close();
 | 
			
		||||
    // Closes the file.
 | 
			
		||||
    FMT_API void close();
 | 
			
		||||
 | 
			
		||||
  // Returns the pointer to a FILE object representing this file.
 | 
			
		||||
  FILE *get() const FMT_NOEXCEPT { return file_; }
 | 
			
		||||
    // Returns the pointer to a FILE object representing this file.
 | 
			
		||||
    FILE *get() const FMT_NOEXCEPT
 | 
			
		||||
    {
 | 
			
		||||
        return file_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // We place parentheses around fileno to workaround a bug in some versions
 | 
			
		||||
  // of MinGW that define fileno as a macro.
 | 
			
		||||
  FMT_API int (fileno)() const;
 | 
			
		||||
    // We place parentheses around fileno to workaround a bug in some versions
 | 
			
		||||
    // of MinGW that define fileno as a macro.
 | 
			
		||||
    FMT_API int (fileno)() const;
 | 
			
		||||
 | 
			
		||||
  void print(CStringRef format_str, const ArgList &args) {
 | 
			
		||||
    fmt::print(file_, format_str, args);
 | 
			
		||||
  }
 | 
			
		||||
  FMT_VARIADIC(void, print, CStringRef)
 | 
			
		||||
    void print(CStringRef format_str, const ArgList &args)
 | 
			
		||||
    {
 | 
			
		||||
        fmt::print(file_, format_str, args);
 | 
			
		||||
    }
 | 
			
		||||
    FMT_VARIADIC(void, print, CStringRef)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// A file. Closed file is represented by a File object with descriptor -1.
 | 
			
		||||
@@ -178,125 +200,141 @@ public:
 | 
			
		||||
// closing the file multiple times will cause a crash on Windows rather
 | 
			
		||||
// than an exception. You can get standard behavior by overriding the
 | 
			
		||||
// invalid parameter handler with _set_invalid_parameter_handler.
 | 
			
		||||
class File {
 | 
			
		||||
 private:
 | 
			
		||||
  int fd_;  // File descriptor.
 | 
			
		||||
class File
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    int fd_;  // File descriptor.
 | 
			
		||||
 | 
			
		||||
  // Constructs a File object with a given descriptor.
 | 
			
		||||
  explicit File(int fd) : fd_(fd) {}
 | 
			
		||||
    // Constructs a File object with a given descriptor.
 | 
			
		||||
    explicit File(int fd) : fd_(fd) {}
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  // Possible values for the oflag argument to the constructor.
 | 
			
		||||
  enum {
 | 
			
		||||
    RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
 | 
			
		||||
    WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
 | 
			
		||||
    RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing.
 | 
			
		||||
  };
 | 
			
		||||
public:
 | 
			
		||||
    // Possible values for the oflag argument to the constructor.
 | 
			
		||||
    enum
 | 
			
		||||
    {
 | 
			
		||||
        RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
 | 
			
		||||
        WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
 | 
			
		||||
        RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing.
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
  // Constructs a File object which doesn't represent any file.
 | 
			
		||||
  File() FMT_NOEXCEPT : fd_(-1) {}
 | 
			
		||||
    // Constructs a File object which doesn't represent any file.
 | 
			
		||||
File() FMT_NOEXCEPT :
 | 
			
		||||
    fd_(-1) {}
 | 
			
		||||
 | 
			
		||||
  // Opens a file and constructs a File object representing this file.
 | 
			
		||||
  FMT_API File(CStringRef path, int oflag);
 | 
			
		||||
    // Opens a file and constructs a File object representing this file.
 | 
			
		||||
    FMT_API File(CStringRef path, int oflag);
 | 
			
		||||
 | 
			
		||||
#if !FMT_USE_RVALUE_REFERENCES
 | 
			
		||||
  // Emulate a move constructor and a move assignment operator if rvalue
 | 
			
		||||
  // references are not supported.
 | 
			
		||||
    // Emulate a move constructor and a move assignment operator if rvalue
 | 
			
		||||
    // references are not supported.
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  // A proxy object to emulate a move constructor.
 | 
			
		||||
  // It is private to make it impossible call operator Proxy directly.
 | 
			
		||||
  struct Proxy {
 | 
			
		||||
    int fd;
 | 
			
		||||
  };
 | 
			
		||||
private:
 | 
			
		||||
    // A proxy object to emulate a move constructor.
 | 
			
		||||
    // It is private to make it impossible call operator Proxy directly.
 | 
			
		||||
    struct Proxy
 | 
			
		||||
    {
 | 
			
		||||
        int fd;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  // A "move constructor" for moving from a temporary.
 | 
			
		||||
  File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
 | 
			
		||||
public:
 | 
			
		||||
    // A "move constructor" for moving from a temporary.
 | 
			
		||||
File(Proxy p) FMT_NOEXCEPT :
 | 
			
		||||
    fd_(p.fd) {}
 | 
			
		||||
 | 
			
		||||
  // A "move constructor" for moving from an lvalue.
 | 
			
		||||
  File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
 | 
			
		||||
    other.fd_ = -1;
 | 
			
		||||
  }
 | 
			
		||||
    // A "move constructor" for moving from an lvalue.
 | 
			
		||||
File(File &other) FMT_NOEXCEPT :
 | 
			
		||||
    fd_(other.fd_)
 | 
			
		||||
    {
 | 
			
		||||
        other.fd_ = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // A "move assignment operator" for moving from a temporary.
 | 
			
		||||
  File &operator=(Proxy p) {
 | 
			
		||||
    close();
 | 
			
		||||
    fd_ = p.fd;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
    // A "move assignment operator" for moving from a temporary.
 | 
			
		||||
    File &operator=(Proxy p)
 | 
			
		||||
    {
 | 
			
		||||
        close();
 | 
			
		||||
        fd_ = p.fd;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // A "move assignment operator" for moving from an lvalue.
 | 
			
		||||
  File &operator=(File &other) {
 | 
			
		||||
    close();
 | 
			
		||||
    fd_ = other.fd_;
 | 
			
		||||
    other.fd_ = -1;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
    // A "move assignment operator" for moving from an lvalue.
 | 
			
		||||
    File &operator=(File &other)
 | 
			
		||||
    {
 | 
			
		||||
        close();
 | 
			
		||||
        fd_ = other.fd_;
 | 
			
		||||
        other.fd_ = -1;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // Returns a proxy object for moving from a temporary:
 | 
			
		||||
  //   File file = File(...);
 | 
			
		||||
  operator Proxy() FMT_NOEXCEPT {
 | 
			
		||||
    Proxy p = {fd_};
 | 
			
		||||
    fd_ = -1;
 | 
			
		||||
    return p;
 | 
			
		||||
  }
 | 
			
		||||
    // Returns a proxy object for moving from a temporary:
 | 
			
		||||
    //   File file = File(...);
 | 
			
		||||
    operator Proxy() FMT_NOEXCEPT
 | 
			
		||||
    {
 | 
			
		||||
        Proxy p = {fd_};
 | 
			
		||||
        fd_ = -1;
 | 
			
		||||
        return p;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 private:
 | 
			
		||||
  FMT_DISALLOW_COPY_AND_ASSIGN(File);
 | 
			
		||||
private:
 | 
			
		||||
    FMT_DISALLOW_COPY_AND_ASSIGN(File);
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
 | 
			
		||||
    other.fd_ = -1;
 | 
			
		||||
  }
 | 
			
		||||
public:
 | 
			
		||||
File(File &&other) FMT_NOEXCEPT :
 | 
			
		||||
    fd_(other.fd_)
 | 
			
		||||
    {
 | 
			
		||||
        other.fd_ = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  File& operator=(File &&other) {
 | 
			
		||||
    close();
 | 
			
		||||
    fd_ = other.fd_;
 | 
			
		||||
    other.fd_ = -1;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
    File& operator=(File &&other)
 | 
			
		||||
    {
 | 
			
		||||
        close();
 | 
			
		||||
        fd_ = other.fd_;
 | 
			
		||||
        other.fd_ = -1;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Destroys the object closing the file it represents if any.
 | 
			
		||||
  FMT_API ~File() FMT_NOEXCEPT;
 | 
			
		||||
    // Destroys the object closing the file it represents if any.
 | 
			
		||||
    FMT_API ~File() FMT_NOEXCEPT;
 | 
			
		||||
 | 
			
		||||
  // Returns the file descriptor.
 | 
			
		||||
  int descriptor() const FMT_NOEXCEPT { return fd_; }
 | 
			
		||||
    // Returns the file descriptor.
 | 
			
		||||
    int descriptor() const FMT_NOEXCEPT
 | 
			
		||||
    {
 | 
			
		||||
        return fd_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // Closes the file.
 | 
			
		||||
  FMT_API void close();
 | 
			
		||||
    // Closes the file.
 | 
			
		||||
    FMT_API void close();
 | 
			
		||||
 | 
			
		||||
  // Returns the file size. The size has signed type for consistency with
 | 
			
		||||
  // stat::st_size.
 | 
			
		||||
  FMT_API LongLong size() const;
 | 
			
		||||
    // Returns the file size. The size has signed type for consistency with
 | 
			
		||||
    // stat::st_size.
 | 
			
		||||
    FMT_API LongLong size() const;
 | 
			
		||||
 | 
			
		||||
  // Attempts to read count bytes from the file into the specified buffer.
 | 
			
		||||
  FMT_API std::size_t read(void *buffer, std::size_t count);
 | 
			
		||||
    // Attempts to read count bytes from the file into the specified buffer.
 | 
			
		||||
    FMT_API std::size_t read(void *buffer, std::size_t count);
 | 
			
		||||
 | 
			
		||||
  // Attempts to write count bytes from the specified buffer to the file.
 | 
			
		||||
  FMT_API std::size_t write(const void *buffer, std::size_t count);
 | 
			
		||||
    // Attempts to write count bytes from the specified buffer to the file.
 | 
			
		||||
    FMT_API std::size_t write(const void *buffer, std::size_t count);
 | 
			
		||||
 | 
			
		||||
  // Duplicates a file descriptor with the dup function and returns
 | 
			
		||||
  // the duplicate as a file object.
 | 
			
		||||
  FMT_API static File dup(int fd);
 | 
			
		||||
    // Duplicates a file descriptor with the dup function and returns
 | 
			
		||||
    // the duplicate as a file object.
 | 
			
		||||
    FMT_API static File dup(int fd);
 | 
			
		||||
 | 
			
		||||
  // Makes fd be the copy of this file descriptor, closing fd first if
 | 
			
		||||
  // necessary.
 | 
			
		||||
  FMT_API void dup2(int fd);
 | 
			
		||||
    // Makes fd be the copy of this file descriptor, closing fd first if
 | 
			
		||||
    // necessary.
 | 
			
		||||
    FMT_API void dup2(int fd);
 | 
			
		||||
 | 
			
		||||
  // Makes fd be the copy of this file descriptor, closing fd first if
 | 
			
		||||
  // necessary.
 | 
			
		||||
  FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
 | 
			
		||||
    // Makes fd be the copy of this file descriptor, closing fd first if
 | 
			
		||||
    // necessary.
 | 
			
		||||
    FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
 | 
			
		||||
 | 
			
		||||
  // Creates a pipe setting up read_end and write_end file objects for reading
 | 
			
		||||
  // and writing respectively.
 | 
			
		||||
  FMT_API static void pipe(File &read_end, File &write_end);
 | 
			
		||||
    // Creates a pipe setting up read_end and write_end file objects for reading
 | 
			
		||||
    // and writing respectively.
 | 
			
		||||
    FMT_API static void pipe(File &read_end, File &write_end);
 | 
			
		||||
 | 
			
		||||
  // Creates a BufferedFile object associated with this file and detaches
 | 
			
		||||
  // this File object from the file.
 | 
			
		||||
  FMT_API BufferedFile fdopen(const char *mode);
 | 
			
		||||
    // Creates a BufferedFile object associated with this file and detaches
 | 
			
		||||
    // this File object from the file.
 | 
			
		||||
    FMT_API BufferedFile fdopen(const char *mode);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Returns the memory page size.
 | 
			
		||||
@@ -309,58 +347,77 @@ long getpagesize();
 | 
			
		||||
 | 
			
		||||
#ifdef FMT_LOCALE
 | 
			
		||||
// A "C" numeric locale.
 | 
			
		||||
class Locale {
 | 
			
		||||
 private:
 | 
			
		||||
class Locale
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
# ifdef _MSC_VER
 | 
			
		||||
  typedef _locale_t locale_t;
 | 
			
		||||
    typedef _locale_t locale_t;
 | 
			
		||||
 | 
			
		||||
  enum { LC_NUMERIC_MASK = LC_NUMERIC };
 | 
			
		||||
    enum { LC_NUMERIC_MASK = LC_NUMERIC };
 | 
			
		||||
 | 
			
		||||
  static locale_t newlocale(int category_mask, const char *locale, locale_t) {
 | 
			
		||||
    return _create_locale(category_mask, locale);
 | 
			
		||||
  }
 | 
			
		||||
    static locale_t newlocale(int category_mask, const char *locale, locale_t)
 | 
			
		||||
    {
 | 
			
		||||
        return _create_locale(category_mask, locale);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  static void freelocale(locale_t locale) {
 | 
			
		||||
    _free_locale(locale);
 | 
			
		||||
  }
 | 
			
		||||
    static void freelocale(locale_t locale)
 | 
			
		||||
    {
 | 
			
		||||
        _free_locale(locale);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
 | 
			
		||||
    return _strtod_l(nptr, endptr, locale);
 | 
			
		||||
  }
 | 
			
		||||
    static double strtod_l(const char *nptr, char **endptr, _locale_t locale)
 | 
			
		||||
    {
 | 
			
		||||
        return _strtod_l(nptr, endptr, locale);
 | 
			
		||||
    }
 | 
			
		||||
# endif
 | 
			
		||||
 | 
			
		||||
  locale_t locale_;
 | 
			
		||||
    locale_t locale_;
 | 
			
		||||
 | 
			
		||||
  FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
 | 
			
		||||
    FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  typedef locale_t Type;
 | 
			
		||||
public:
 | 
			
		||||
    typedef locale_t Type;
 | 
			
		||||
 | 
			
		||||
  Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
 | 
			
		||||
    if (!locale_)
 | 
			
		||||
      FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
 | 
			
		||||
  }
 | 
			
		||||
  ~Locale() { freelocale(locale_); }
 | 
			
		||||
    Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL))
 | 
			
		||||
    {
 | 
			
		||||
        if (!locale_)
 | 
			
		||||
            FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
 | 
			
		||||
    }
 | 
			
		||||
    ~Locale()
 | 
			
		||||
    {
 | 
			
		||||
        freelocale(locale_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  Type get() const { return locale_; }
 | 
			
		||||
    Type get() const
 | 
			
		||||
    {
 | 
			
		||||
        return locale_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // Converts string to floating-point number and advances str past the end
 | 
			
		||||
  // of the parsed input.
 | 
			
		||||
  double strtod(const char *&str) const {
 | 
			
		||||
    char *end = FMT_NULL;
 | 
			
		||||
    double result = strtod_l(str, &end, locale_);
 | 
			
		||||
    str = end;
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
    // Converts string to floating-point number and advances str past the end
 | 
			
		||||
    // of the parsed input.
 | 
			
		||||
    double strtod(const char *&str) const
 | 
			
		||||
    {
 | 
			
		||||
        char *end = FMT_NULL;
 | 
			
		||||
        double result = strtod_l(str, &end, locale_);
 | 
			
		||||
        str = end;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
#endif  // FMT_LOCALE
 | 
			
		||||
}  // namespace fmt
 | 
			
		||||
 | 
			
		||||
#if !FMT_USE_RVALUE_REFERENCES
 | 
			
		||||
namespace std {
 | 
			
		||||
namespace std
 | 
			
		||||
{
 | 
			
		||||
// For compatibility with C++98.
 | 
			
		||||
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
 | 
			
		||||
inline fmt::File &move(fmt::File &f) { return f; }
 | 
			
		||||
inline fmt::BufferedFile &move(fmt::BufferedFile &f)
 | 
			
		||||
{
 | 
			
		||||
    return f;
 | 
			
		||||
}
 | 
			
		||||
inline fmt::File &move(fmt::File &f)
 | 
			
		||||
{
 | 
			
		||||
    return f;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -19,120 +19,160 @@
 | 
			
		||||
# pragma warning(disable: 4996)  // "deprecated" functions
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace fmt {
 | 
			
		||||
namespace fmt
 | 
			
		||||
{
 | 
			
		||||
template <typename ArgFormatter>
 | 
			
		||||
void format_arg(BasicFormatter<char, ArgFormatter> &f,
 | 
			
		||||
                const char *&format_str, const std::tm &tm) {
 | 
			
		||||
  if (*format_str == ':')
 | 
			
		||||
    ++format_str;
 | 
			
		||||
  const char *end = format_str;
 | 
			
		||||
  while (*end && *end != '}')
 | 
			
		||||
    ++end;
 | 
			
		||||
  if (*end != '}')
 | 
			
		||||
    FMT_THROW(FormatError("missing '}' in format string"));
 | 
			
		||||
  internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
 | 
			
		||||
  format.append(format_str, end + 1);
 | 
			
		||||
  format[format.size() - 1] = '\0';
 | 
			
		||||
  Buffer<char> &buffer = f.writer().buffer();
 | 
			
		||||
  std::size_t start = buffer.size();
 | 
			
		||||
  for (;;) {
 | 
			
		||||
    std::size_t size = buffer.capacity() - start;
 | 
			
		||||
    std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
 | 
			
		||||
    if (count != 0) {
 | 
			
		||||
      buffer.resize(start + count);
 | 
			
		||||
      break;
 | 
			
		||||
                const char *&format_str, const std::tm &tm)
 | 
			
		||||
{
 | 
			
		||||
    if (*format_str == ':')
 | 
			
		||||
        ++format_str;
 | 
			
		||||
    const char *end = format_str;
 | 
			
		||||
    while (*end && *end != '}')
 | 
			
		||||
        ++end;
 | 
			
		||||
    if (*end != '}')
 | 
			
		||||
        FMT_THROW(FormatError("missing '}' in format string"));
 | 
			
		||||
    internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
 | 
			
		||||
    format.append(format_str, end + 1);
 | 
			
		||||
    format[format.size() - 1] = '\0';
 | 
			
		||||
    Buffer<char> &buffer = f.writer().buffer();
 | 
			
		||||
    std::size_t start = buffer.size();
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        std::size_t size = buffer.capacity() - start;
 | 
			
		||||
        std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
 | 
			
		||||
        if (count != 0)
 | 
			
		||||
        {
 | 
			
		||||
            buffer.resize(start + count);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        if (size >= format.size() * 256)
 | 
			
		||||
        {
 | 
			
		||||
            // If the buffer is 256 times larger than the format string, assume
 | 
			
		||||
            // that `strftime` gives an empty result. There doesn't seem to be a
 | 
			
		||||
            // better way to distinguish the two cases:
 | 
			
		||||
            // https://github.com/fmtlib/fmt/issues/367
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        const std::size_t MIN_GROWTH = 10;
 | 
			
		||||
        buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
 | 
			
		||||
    }
 | 
			
		||||
    if (size >= format.size() * 256) {
 | 
			
		||||
      // If the buffer is 256 times larger than the format string, assume
 | 
			
		||||
      // that `strftime` gives an empty result. There doesn't seem to be a
 | 
			
		||||
      // better way to distinguish the two cases:
 | 
			
		||||
      // https://github.com/fmtlib/fmt/issues/367
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    const std::size_t MIN_GROWTH = 10;
 | 
			
		||||
    buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
 | 
			
		||||
  }
 | 
			
		||||
  format_str = end + 1;
 | 
			
		||||
    format_str = end + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace internal{
 | 
			
		||||
inline Null<> localtime_r(...) { return Null<>(); }
 | 
			
		||||
inline Null<> localtime_s(...) { return Null<>(); }
 | 
			
		||||
inline Null<> gmtime_r(...) { return Null<>(); }
 | 
			
		||||
inline Null<> gmtime_s(...) { return Null<>(); }
 | 
			
		||||
namespace internal
 | 
			
		||||
{
 | 
			
		||||
inline Null<> localtime_r(...)
 | 
			
		||||
{
 | 
			
		||||
    return Null<>();
 | 
			
		||||
}
 | 
			
		||||
inline Null<> localtime_s(...)
 | 
			
		||||
{
 | 
			
		||||
    return Null<>();
 | 
			
		||||
}
 | 
			
		||||
inline Null<> gmtime_r(...)
 | 
			
		||||
{
 | 
			
		||||
    return Null<>();
 | 
			
		||||
}
 | 
			
		||||
inline Null<> gmtime_s(...)
 | 
			
		||||
{
 | 
			
		||||
    return Null<>();
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Thread-safe replacement for std::localtime
 | 
			
		||||
inline std::tm localtime(std::time_t time) {
 | 
			
		||||
  struct LocalTime {
 | 
			
		||||
    std::time_t time_;
 | 
			
		||||
    std::tm tm_;
 | 
			
		||||
inline std::tm localtime(std::time_t time)
 | 
			
		||||
{
 | 
			
		||||
    struct LocalTime
 | 
			
		||||
    {
 | 
			
		||||
        std::time_t time_;
 | 
			
		||||
        std::tm tm_;
 | 
			
		||||
 | 
			
		||||
    LocalTime(std::time_t t): time_(t) {}
 | 
			
		||||
        LocalTime(std::time_t t): time_(t) {}
 | 
			
		||||
 | 
			
		||||
    bool run() {
 | 
			
		||||
      using namespace fmt::internal;
 | 
			
		||||
      return handle(localtime_r(&time_, &tm_));
 | 
			
		||||
    }
 | 
			
		||||
        bool run()
 | 
			
		||||
        {
 | 
			
		||||
            using namespace fmt::internal;
 | 
			
		||||
            return handle(localtime_r(&time_, &tm_));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool handle(std::tm *tm) { return tm != FMT_NULL; }
 | 
			
		||||
        bool handle(std::tm *tm)
 | 
			
		||||
        {
 | 
			
		||||
            return tm != FMT_NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool handle(internal::Null<>) {
 | 
			
		||||
      using namespace fmt::internal;
 | 
			
		||||
      return fallback(localtime_s(&tm_, &time_));
 | 
			
		||||
    }
 | 
			
		||||
        bool handle(internal::Null<>)
 | 
			
		||||
        {
 | 
			
		||||
            using namespace fmt::internal;
 | 
			
		||||
            return fallback(localtime_s(&tm_, &time_));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool fallback(int res) { return res == 0; }
 | 
			
		||||
        bool fallback(int res)
 | 
			
		||||
        {
 | 
			
		||||
            return res == 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool fallback(internal::Null<>) {
 | 
			
		||||
      using namespace fmt::internal;
 | 
			
		||||
      std::tm *tm = std::localtime(&time_);
 | 
			
		||||
      if (tm) tm_ = *tm;
 | 
			
		||||
      return tm != FMT_NULL;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  LocalTime lt(time);
 | 
			
		||||
  if (lt.run())
 | 
			
		||||
    return lt.tm_;
 | 
			
		||||
  // Too big time values may be unsupported.
 | 
			
		||||
  FMT_THROW(fmt::FormatError("time_t value out of range"));
 | 
			
		||||
  return std::tm();
 | 
			
		||||
        bool fallback(internal::Null<>)
 | 
			
		||||
        {
 | 
			
		||||
            using namespace fmt::internal;
 | 
			
		||||
            std::tm *tm = std::localtime(&time_);
 | 
			
		||||
            if (tm) tm_ = *tm;
 | 
			
		||||
            return tm != FMT_NULL;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    LocalTime lt(time);
 | 
			
		||||
    if (lt.run())
 | 
			
		||||
        return lt.tm_;
 | 
			
		||||
    // Too big time values may be unsupported.
 | 
			
		||||
    FMT_THROW(fmt::FormatError("time_t value out of range"));
 | 
			
		||||
    return std::tm();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Thread-safe replacement for std::gmtime
 | 
			
		||||
inline std::tm gmtime(std::time_t time) {
 | 
			
		||||
  struct GMTime {
 | 
			
		||||
    std::time_t time_;
 | 
			
		||||
    std::tm tm_;
 | 
			
		||||
inline std::tm gmtime(std::time_t time)
 | 
			
		||||
{
 | 
			
		||||
    struct GMTime
 | 
			
		||||
    {
 | 
			
		||||
        std::time_t time_;
 | 
			
		||||
        std::tm tm_;
 | 
			
		||||
 | 
			
		||||
    GMTime(std::time_t t): time_(t) {}
 | 
			
		||||
        GMTime(std::time_t t): time_(t) {}
 | 
			
		||||
 | 
			
		||||
    bool run() {
 | 
			
		||||
      using namespace fmt::internal;
 | 
			
		||||
      return handle(gmtime_r(&time_, &tm_));
 | 
			
		||||
    }
 | 
			
		||||
        bool run()
 | 
			
		||||
        {
 | 
			
		||||
            using namespace fmt::internal;
 | 
			
		||||
            return handle(gmtime_r(&time_, &tm_));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool handle(std::tm *tm) { return tm != FMT_NULL; }
 | 
			
		||||
        bool handle(std::tm *tm)
 | 
			
		||||
        {
 | 
			
		||||
            return tm != FMT_NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool handle(internal::Null<>) {
 | 
			
		||||
      using namespace fmt::internal;
 | 
			
		||||
      return fallback(gmtime_s(&tm_, &time_));
 | 
			
		||||
    }
 | 
			
		||||
        bool handle(internal::Null<>)
 | 
			
		||||
        {
 | 
			
		||||
            using namespace fmt::internal;
 | 
			
		||||
            return fallback(gmtime_s(&tm_, &time_));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool fallback(int res) { return res == 0; }
 | 
			
		||||
        bool fallback(int res)
 | 
			
		||||
        {
 | 
			
		||||
            return res == 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    bool fallback(internal::Null<>) {
 | 
			
		||||
      std::tm *tm = std::gmtime(&time_);
 | 
			
		||||
      if (tm != FMT_NULL) tm_ = *tm;
 | 
			
		||||
      return tm != FMT_NULL;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  GMTime gt(time);
 | 
			
		||||
  if (gt.run())
 | 
			
		||||
    return gt.tm_;
 | 
			
		||||
  // Too big time values may be unsupported.
 | 
			
		||||
  FMT_THROW(fmt::FormatError("time_t value out of range"));
 | 
			
		||||
  return std::tm();
 | 
			
		||||
        bool fallback(internal::Null<>)
 | 
			
		||||
        {
 | 
			
		||||
            std::tm *tm = std::gmtime(&time_);
 | 
			
		||||
            if (tm != FMT_NULL) tm_ = *tm;
 | 
			
		||||
            return tm != FMT_NULL;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    GMTime gt(time);
 | 
			
		||||
    if (gt.run())
 | 
			
		||||
        return gt.tm_;
 | 
			
		||||
    // Too big time values may be unsupported.
 | 
			
		||||
    FMT_THROW(fmt::FormatError("time_t value out of range"));
 | 
			
		||||
    return std::tm();
 | 
			
		||||
}
 | 
			
		||||
} //namespace fmt
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -169,11 +169,11 @@ void drop_all();
 | 
			
		||||
#define SPDLOG_STR_H(x) #x
 | 
			
		||||
#define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
  #define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
 | 
			
		||||
  #define SPDLOG_TRACE_IF(logger, flag, ...) logger->trace_if(flag, "[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
 | 
			
		||||
#define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
 | 
			
		||||
#define SPDLOG_TRACE_IF(logger, flag, ...) logger->trace_if(flag, "[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
 | 
			
		||||
#else
 | 
			
		||||
  #define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__)
 | 
			
		||||
  #define SPDLOG_TRACE_IF(logger, flag, ...) logger->trace_if(flag, "[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__)
 | 
			
		||||
#define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__)
 | 
			
		||||
#define SPDLOG_TRACE_IF(logger, flag, ...) logger->trace_if(flag, "[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__)
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#define SPDLOG_TRACE(logger, ...)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user