Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
S
spdlog
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
spdlog
Commits
93be7713
Commit
93be7713
authored
Nov 06, 2017
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
astyle
parent
6ab2f0e0
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1689 additions
and
1466 deletions
+1689
-1466
mpmc_bounded_q.h
include/spdlog/details/mpmc_bounded_q.h
+176
-168
os.h
include/spdlog/details/os.h
+469
-469
format.h
include/spdlog/fmt/bundled/format.h
+0
-0
ostream.h
include/spdlog/fmt/bundled/ostream.h
+56
-47
posix.h
include/spdlog/fmt/bundled/posix.h
+275
-218
printf.h
include/spdlog/fmt/bundled/printf.h
+532
-423
time.h
include/spdlog/fmt/bundled/time.h
+143
-103
spdlog.h
include/spdlog/spdlog.h
+4
-4
includes.h
tests/includes.h
+2
-2
test_macros.cpp
tests/test_macros.cpp
+28
-28
utils.cpp
tests/utils.cpp
+4
-4
No files found.
include/spdlog/details/mpmc_bounded_q.h
View file @
93be7713
/*
/*
A modified version of Bounded MPMC queue by Dmitry Vyukov.
A modified version of Bounded MPMC queue by Dmitry Vyukov.
Original code from:
Original code from:
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
licensed by Dmitry Vyukov under the terms below:
licensed by Dmitry Vyukov under the terms below:
Simplified BSD license
Simplified BSD license
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
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
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
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
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and
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.
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:
The code in its current form adds the license below:
Copyright(c) 2015 Gabi Melman.
Copyright(c) 2015 Gabi Melman.
Distributed under the MIT License (http://opensource.org/licenses/MIT)
Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/
*/
#pragma once
#pragma once
#include "spdlog/common.h"
#include "spdlog/common.h"
#include <atomic>
#include <atomic>
#include <utility>
#include <utility>
namespace
spdlog
namespace
spdlog
{
{
namespace
details
namespace
details
{
{
template
<
typename
T
>
template
<
typename
T
>
class
mpmc_bounded_queue
class
mpmc_bounded_queue
{
{
public
:
public
:
using
item_type
=
T
;
using
item_type
=
T
;
mpmc_bounded_queue
(
size_t
buffer_size
)
mpmc_bounded_queue
(
size_t
buffer_size
)
:
max_size_
(
buffer_size
),
:
max_size_
(
buffer_size
),
buffer_
(
new
cell_t
[
buffer_size
]),
buffer_
(
new
cell_t
[
buffer_size
]),
buffer_mask_
(
buffer_size
-
1
)
buffer_mask_
(
buffer_size
-
1
)
{
{
//queue size must be power of two
//queue size must be power of two
if
(
!
((
buffer_size
>=
2
)
&&
((
buffer_size
&
(
buffer_size
-
1
))
==
0
)))
if
(
!
((
buffer_size
>=
2
)
&&
((
buffer_size
&
(
buffer_size
-
1
))
==
0
)))
throw
spdlog_ex
(
"async logger queue size must be power of two"
);
throw
spdlog_ex
(
"async logger queue size must be power of two"
);
for
(
size_t
i
=
0
;
i
!=
buffer_size
;
i
+=
1
)
for
(
size_t
i
=
0
;
i
!=
buffer_size
;
i
+=
1
)
buffer_
[
i
].
sequence_
.
store
(
i
,
std
::
memory_order_relaxed
);
buffer_
[
i
].
sequence_
.
store
(
i
,
std
::
memory_order_relaxed
);
enqueue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
enqueue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
dequeue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
dequeue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
}
}
~
mpmc_bounded_queue
()
~
mpmc_bounded_queue
()
{
{
delete
[]
buffer_
;
delete
[]
buffer_
;
}
}
bool
enqueue
(
T
&&
data
)
bool
enqueue
(
T
&&
data
)
{
{
cell_t
*
cell
;
cell_t
*
cell
;
size_t
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
size_t
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
for
(;;)
{
for
(;;)
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
{
size_t
seq
=
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
intptr_t
dif
=
static_cast
<
intptr_t
>
(
seq
)
-
static_cast
<
intptr_t
>
(
pos
);
size_t
seq
=
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
if
(
dif
==
0
)
{
intptr_t
dif
=
static_cast
<
intptr_t
>
(
seq
)
-
static_cast
<
intptr_t
>
(
pos
);
if
(
enqueue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
if
(
dif
==
0
)
break
;
{
}
if
(
enqueue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
else
if
(
dif
<
0
)
{
break
;
return
false
;
}
}
else
if
(
dif
<
0
)
else
{
{
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
return
false
;
}
}
}
else
cell
->
data_
=
std
::
move
(
data
);
{
cell
->
sequence_
.
store
(
pos
+
1
,
std
::
memory_order_release
);
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
return
true
;
}
}
}
cell
->
data_
=
std
::
move
(
data
);
bool
dequeue
(
T
&
data
)
cell
->
sequence_
.
store
(
pos
+
1
,
std
::
memory_order_release
);
{
return
true
;
cell_t
*
cell
;
}
size_t
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
for
(;;)
{
bool
dequeue
(
T
&
data
)
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
{
size_t
seq
=
cell_t
*
cell
;
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
size_t
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
intptr_t
dif
=
static_cast
<
intptr_t
>
(
seq
)
-
static_cast
<
intptr_t
>
(
pos
+
1
);
for
(;;)
if
(
dif
==
0
)
{
{
if
(
dequeue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
break
;
size_t
seq
=
}
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
else
if
(
dif
<
0
)
intptr_t
dif
=
static_cast
<
intptr_t
>
(
seq
)
-
static_cast
<
intptr_t
>
(
pos
+
1
);
return
false
;
if
(
dif
==
0
)
else
{
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
if
(
dequeue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
}
break
;
data
=
std
::
move
(
cell
->
data_
);
}
cell
->
sequence_
.
store
(
pos
+
buffer_mask_
+
1
,
std
::
memory_order_release
);
else
if
(
dif
<
0
)
return
true
;
return
false
;
}
else
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
bool
is_empty
()
}
{
data
=
std
::
move
(
cell
->
data_
);
size_t
front
,
front1
,
back
;
cell
->
sequence_
.
store
(
pos
+
buffer_mask_
+
1
,
std
::
memory_order_release
);
// try to take a consistent snapshot of front/tail.
return
true
;
do
{
}
front
=
enqueue_pos_
.
load
(
std
::
memory_order_acquire
);
back
=
dequeue_pos_
.
load
(
std
::
memory_order_acquire
);
bool
is_empty
()
front1
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
{
}
while
(
front
!=
front1
);
size_t
front
,
front1
,
back
;
return
back
==
front
;
// try to take a consistent snapshot of front/tail.
}
do
{
private
:
front
=
enqueue_pos_
.
load
(
std
::
memory_order_acquire
);
struct
cell_t
back
=
dequeue_pos_
.
load
(
std
::
memory_order_acquire
);
{
front1
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
std
::
atomic
<
size_t
>
sequence_
;
}
T
data_
;
while
(
front
!=
front1
);
};
return
back
==
front
;
}
size_t
const
max_size_
;
private
:
static
size_t
const
cacheline_size
=
64
;
struct
cell_t
typedef
char
cacheline_pad_t
[
cacheline_size
];
{
std
::
atomic
<
size_t
>
sequence_
;
cacheline_pad_t
pad0_
;
T
data_
;
cell_t
*
const
buffer_
;
};
size_t
const
buffer_mask_
;
cacheline_pad_t
pad1_
;
size_t
const
max_size_
;
std
::
atomic
<
size_t
>
enqueue_pos_
;
cacheline_pad_t
pad2_
;
static
size_t
const
cacheline_size
=
64
;
std
::
atomic
<
size_t
>
dequeue_pos_
;
typedef
char
cacheline_pad_t
[
cacheline_size
];
cacheline_pad_t
pad3_
;
cacheline_pad_t
pad0_
;
mpmc_bounded_queue
(
mpmc_bounded_queue
const
&
)
=
delete
;
cell_t
*
const
buffer_
;
void
operator
=
(
mpmc_bounded_queue
const
&
)
=
delete
;
size_t
const
buffer_mask_
;
};
cacheline_pad_t
pad1_
;
std
::
atomic
<
size_t
>
enqueue_pos_
;
}
// ns details
cacheline_pad_t
pad2_
;
}
// ns spdlog
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
include/spdlog/details/os.h
View file @
93be7713
//
//
// Copyright(c) 2015 Gabi Melman.
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
#pragma once
#pragma once
#include "spdlog/common.h"
#include "spdlog/common.h"
#include <cstdio>
#include <cstdio>
#include <ctime>
#include <ctime>
#include <functional>
#include <functional>
#include <string>
#include <string>
#include <chrono>
#include <chrono>
#include <thread>
#include <thread>
#include <algorithm>
#include <algorithm>
#include <cstring>
#include <cstring>
#include <cstdlib>
#include <cstdlib>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/types.h>
#ifdef _WIN32
#ifdef _WIN32
#ifndef NOMINMAX
#ifndef NOMINMAX
#define NOMINMAX //prevent windows redefining min/max
#define NOMINMAX //prevent windows redefining min/max
#endif
#endif
#ifndef WIN32_LEAN_AND_MEAN
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif
#include <windows.h>
#include <windows.h>
#include <process.h> // _get_pid support
#include <process.h> // _get_pid support
#include <io.h> // _get_osfhandle and _isatty support
#include <io.h> // _get_osfhandle and _isatty support
#ifdef __MINGW32__
#ifdef __MINGW32__
#include <share.h>
#include <share.h>
#endif
#endif
#else // unix
#else // unix
#include <unistd.h>
#include <unistd.h>
#include <fcntl.h>
#include <fcntl.h>
#ifdef __linux__
#ifdef __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#elif __FreeBSD__
#elif __FreeBSD__
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
#endif
#endif
#endif //unix
#endif //unix
#ifndef __has_feature // Clang - feature checking macros.
#ifndef __has_feature // Clang - feature checking macros.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#endif
namespace
spdlog
namespace
spdlog
{
{
namespace
details
namespace
details
{
{
namespace
os
namespace
os
{
{
inline
spdlog
::
log_clock
::
time_point
now
()
inline
spdlog
::
log_clock
::
time_point
now
()
{
{
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
timespec
ts
;
timespec
ts
;
::
clock_gettime
(
CLOCK_REALTIME_COARSE
,
&
ts
);
::
clock_gettime
(
CLOCK_REALTIME_COARSE
,
&
ts
);
return
std
::
chrono
::
time_point
<
log_clock
,
typename
log_clock
::
duration
>
(
return
std
::
chrono
::
time_point
<
log_clock
,
typename
log_clock
::
duration
>
(
std
::
chrono
::
duration_cast
<
typename
log_clock
::
duration
>
(
std
::
chrono
::
duration_cast
<
typename
log_clock
::
duration
>
(
std
::
chrono
::
seconds
(
ts
.
tv_sec
)
+
std
::
chrono
::
nanoseconds
(
ts
.
tv_nsec
)));
std
::
chrono
::
seconds
(
ts
.
tv_sec
)
+
std
::
chrono
::
nanoseconds
(
ts
.
tv_nsec
)));
#else
#else
return
log_clock
::
now
();
return
log_clock
::
now
();
#endif
#endif
}
}
inline
std
::
tm
localtime
(
const
std
::
time_t
&
time_tt
)
inline
std
::
tm
localtime
(
const
std
::
time_t
&
time_tt
)
{
{
#ifdef _WIN32
#ifdef _WIN32
std
::
tm
tm
;
std
::
tm
tm
;
localtime_s
(
&
tm
,
&
time_tt
);
localtime_s
(
&
tm
,
&
time_tt
);
#else
#else
std
::
tm
tm
;
std
::
tm
tm
;
localtime_r
(
&
time_tt
,
&
tm
);
localtime_r
(
&
time_tt
,
&
tm
);
#endif
#endif
return
tm
;
return
tm
;
}
}
inline
std
::
tm
localtime
()
inline
std
::
tm
localtime
()
{
{
std
::
time_t
now_t
=
time
(
nullptr
);
std
::
time_t
now_t
=
time
(
nullptr
);
return
localtime
(
now_t
);
return
localtime
(
now_t
);
}
}
inline
std
::
tm
gmtime
(
const
std
::
time_t
&
time_tt
)
inline
std
::
tm
gmtime
(
const
std
::
time_t
&
time_tt
)
{
{
#ifdef _WIN32
#ifdef _WIN32
std
::
tm
tm
;
std
::
tm
tm
;
gmtime_s
(
&
tm
,
&
time_tt
);
gmtime_s
(
&
tm
,
&
time_tt
);
#else
#else
std
::
tm
tm
;
std
::
tm
tm
;
gmtime_r
(
&
time_tt
,
&
tm
);
gmtime_r
(
&
time_tt
,
&
tm
);
#endif
#endif
return
tm
;
return
tm
;
}
}
inline
std
::
tm
gmtime
()
inline
std
::
tm
gmtime
()
{
{
std
::
time_t
now_t
=
time
(
nullptr
);
std
::
time_t
now_t
=
time
(
nullptr
);
return
gmtime
(
now_t
);
return
gmtime
(
now_t
);
}
}
inline
bool
operator
==
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
inline
bool
operator
==
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
{
{
return
(
tm1
.
tm_sec
==
tm2
.
tm_sec
&&
return
(
tm1
.
tm_sec
==
tm2
.
tm_sec
&&
tm1
.
tm_min
==
tm2
.
tm_min
&&
tm1
.
tm_min
==
tm2
.
tm_min
&&
tm1
.
tm_hour
==
tm2
.
tm_hour
&&
tm1
.
tm_hour
==
tm2
.
tm_hour
&&
tm1
.
tm_mday
==
tm2
.
tm_mday
&&
tm1
.
tm_mday
==
tm2
.
tm_mday
&&
tm1
.
tm_mon
==
tm2
.
tm_mon
&&
tm1
.
tm_mon
==
tm2
.
tm_mon
&&
tm1
.
tm_year
==
tm2
.
tm_year
&&
tm1
.
tm_year
==
tm2
.
tm_year
&&
tm1
.
tm_isdst
==
tm2
.
tm_isdst
);
tm1
.
tm_isdst
==
tm2
.
tm_isdst
);
}
}
inline
bool
operator
!=
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
inline
bool
operator
!=
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
{
{
return
!
(
tm1
==
tm2
);
return
!
(
tm1
==
tm2
);
}
}
// eol definition
// eol definition
#if !defined (SPDLOG_EOL)
#if !defined (SPDLOG_EOL)
#ifdef _WIN32
#ifdef _WIN32
#define SPDLOG_EOL "\r\n"
#define SPDLOG_EOL "\r\n"
#else
#else
#define SPDLOG_EOL "\n"
#define SPDLOG_EOL "\n"
#endif
#endif
#endif
#endif
SPDLOG_CONSTEXPR
static
const
char
*
eol
=
SPDLOG_EOL
;
SPDLOG_CONSTEXPR
static
const
char
*
eol
=
SPDLOG_EOL
;
SPDLOG_CONSTEXPR
static
int
eol_size
=
sizeof
(
SPDLOG_EOL
)
-
1
;
SPDLOG_CONSTEXPR
static
int
eol_size
=
sizeof
(
SPDLOG_EOL
)
-
1
;
inline
void
prevent_child_fd
(
FILE
*
f
)
inline
void
prevent_child_fd
(
FILE
*
f
)
{
{
#ifdef _WIN32
#ifdef _WIN32
auto
file_handle
=
(
HANDLE
)
_get_osfhandle
(
_fileno
(
f
));
auto
file_handle
=
(
HANDLE
)
_get_osfhandle
(
_fileno
(
f
));
if
(
!::
SetHandleInformation
(
file_handle
,
HANDLE_FLAG_INHERIT
,
0
))
if
(
!::
SetHandleInformation
(
file_handle
,
HANDLE_FLAG_INHERIT
,
0
))
throw
spdlog_ex
(
"SetHandleInformation failed"
,
errno
);
throw
spdlog_ex
(
"SetHandleInformation failed"
,
errno
);
#else
#else
auto
fd
=
fileno
(
f
);
auto
fd
=
fileno
(
f
);
if
(
fcntl
(
fd
,
F_SETFD
,
FD_CLOEXEC
)
==
-
1
)
if
(
fcntl
(
fd
,
F_SETFD
,
FD_CLOEXEC
)
==
-
1
)
throw
spdlog_ex
(
"fcntl with FD_CLOEXEC failed"
,
errno
);
throw
spdlog_ex
(
"fcntl with FD_CLOEXEC failed"
,
errno
);
#endif
#endif
}
}
//fopen_s on non windows for writing
//fopen_s on non windows for writing
inline
int
fopen_s
(
FILE
**
fp
,
const
filename_t
&
filename
,
const
filename_t
&
mode
)
inline
int
fopen_s
(
FILE
**
fp
,
const
filename_t
&
filename
,
const
filename_t
&
mode
)
{
{
#ifdef _WIN32
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
#ifdef SPDLOG_WCHAR_FILENAMES
*
fp
=
_wfsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
*
fp
=
_wfsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
#else
#else
*
fp
=
_fsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
*
fp
=
_fsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
#endif
#endif
#else //unix
#else //unix
*
fp
=
fopen
((
filename
.
c_str
()),
mode
.
c_str
());
*
fp
=
fopen
((
filename
.
c_str
()),
mode
.
c_str
());
#endif
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
#ifdef SPDLOG_PREVENT_CHILD_FD
if
(
*
fp
!=
nullptr
)
if
(
*
fp
!=
nullptr
)
prevent_child_fd
(
*
fp
);
prevent_child_fd
(
*
fp
);
#endif
#endif
return
*
fp
==
nullptr
;
return
*
fp
==
nullptr
;
}
}
inline
int
remove
(
const
filename_t
&
filename
)
inline
int
remove
(
const
filename_t
&
filename
)
{
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return
_wremove
(
filename
.
c_str
());
return
_wremove
(
filename
.
c_str
());
#else
#else
return
std
::
remove
(
filename
.
c_str
());
return
std
::
remove
(
filename
.
c_str
());
#endif
#endif
}
}
inline
int
rename
(
const
filename_t
&
filename1
,
const
filename_t
&
filename2
)
inline
int
rename
(
const
filename_t
&
filename1
,
const
filename_t
&
filename2
)
{
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return
_wrename
(
filename1
.
c_str
(),
filename2
.
c_str
());
return
_wrename
(
filename1
.
c_str
(),
filename2
.
c_str
());
#else
#else
return
std
::
rename
(
filename1
.
c_str
(),
filename2
.
c_str
());
return
std
::
rename
(
filename1
.
c_str
(),
filename2
.
c_str
());
#endif
#endif
}
}
//Return if file exists
//Return if file exists
inline
bool
file_exists
(
const
filename_t
&
filename
)
inline
bool
file_exists
(
const
filename_t
&
filename
)
{
{
#ifdef _WIN32
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
#ifdef SPDLOG_WCHAR_FILENAMES
auto
attribs
=
GetFileAttributesW
(
filename
.
c_str
());
auto
attribs
=
GetFileAttributesW
(
filename
.
c_str
());
#else
#else
auto
attribs
=
GetFileAttributesA
(
filename
.
c_str
());
auto
attribs
=
GetFileAttributesA
(
filename
.
c_str
());
#endif
#endif
return
(
attribs
!=
INVALID_FILE_ATTRIBUTES
&&
!
(
attribs
&
FILE_ATTRIBUTE_DIRECTORY
));
return
(
attribs
!=
INVALID_FILE_ATTRIBUTES
&&
!
(
attribs
&
FILE_ATTRIBUTE_DIRECTORY
));
#else //common linux/unix all have the stat system call
#else //common linux/unix all have the stat system call
struct
stat
buffer
;
struct
stat
buffer
;
return
(
stat
(
filename
.
c_str
(),
&
buffer
)
==
0
);
return
(
stat
(
filename
.
c_str
(),
&
buffer
)
==
0
);
#endif
#endif
}
}
//Return file size according to open FILE* object
//Return file size according to open FILE* object
inline
size_t
filesize
(
FILE
*
f
)
inline
size_t
filesize
(
FILE
*
f
)
{
{
if
(
f
==
nullptr
)
if
(
f
==
nullptr
)
throw
spdlog_ex
(
"Failed getting file size. fd is null"
);
throw
spdlog_ex
(
"Failed getting file size. fd is null"
);
#if defined ( _WIN32) && !defined(__CYGWIN__)
#if defined ( _WIN32) && !defined(__CYGWIN__)
int
fd
=
_fileno
(
f
);
int
fd
=
_fileno
(
f
);
#if _WIN64 //64 bits
#if _WIN64 //64 bits
struct
_stat64
st
;
struct
_stat64
st
;
if
(
_fstat64
(
fd
,
&
st
)
==
0
)
if
(
_fstat64
(
fd
,
&
st
)
==
0
)
return
st
.
st_size
;
return
st
.
st_size
;
#else //windows 32 bits
#else //windows 32 bits
long
ret
=
_filelength
(
fd
);
long
ret
=
_filelength
(
fd
);
if
(
ret
>=
0
)
if
(
ret
>=
0
)
return
static_cast
<
size_t
>
(
ret
);
return
static_cast
<
size_t
>
(
ret
);
#endif
#endif
#else // unix
#else // unix
int
fd
=
fileno
(
f
);
int
fd
=
fileno
(
f
);
//64 bits(but not in osx or cygwin, where fstat64 is deprecated)
//64 bits(but not in osx or cygwin, where fstat64 is deprecated)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
struct
stat64
st
;
struct
stat64
st
;
if
(
fstat64
(
fd
,
&
st
)
==
0
)
if
(
fstat64
(
fd
,
&
st
)
==
0
)
return
static_cast
<
size_t
>
(
st
.
st_size
);
return
static_cast
<
size_t
>
(
st
.
st_size
);
#else // unix 32 bits or cygwin
#else // unix 32 bits or cygwin
struct
stat
st
;
struct
stat
st
;
if
(
fstat
(
fd
,
&
st
)
==
0
)
if
(
fstat
(
fd
,
&
st
)
==
0
)
return
static_cast
<
size_t
>
(
st
.
st_size
);
return
static_cast
<
size_t
>
(
st
.
st_size
);
#endif
#endif
#endif
#endif
throw
spdlog_ex
(
"Failed getting file size from fd"
,
errno
);
throw
spdlog_ex
(
"Failed getting file size from fd"
,
errno
);
}
}
//Return utc offset in minutes or throw spdlog_ex on failure
//Return utc offset in minutes or throw spdlog_ex on failure
inline
int
utc_minutes_offset
(
const
std
::
tm
&
tm
=
details
::
os
::
localtime
())
inline
int
utc_minutes_offset
(
const
std
::
tm
&
tm
=
details
::
os
::
localtime
())
{
{
#ifdef _WIN32
#ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08
#if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION
tzinfo
;
TIME_ZONE_INFORMATION
tzinfo
;
auto
rv
=
GetTimeZoneInformation
(
&
tzinfo
);
auto
rv
=
GetTimeZoneInformation
(
&
tzinfo
);
#else
#else
DYNAMIC_TIME_ZONE_INFORMATION
tzinfo
;
DYNAMIC_TIME_ZONE_INFORMATION
tzinfo
;
auto
rv
=
GetDynamicTimeZoneInformation
(
&
tzinfo
);
auto
rv
=
GetDynamicTimeZoneInformation
(
&
tzinfo
);
#endif
#endif
if
(
rv
==
TIME_ZONE_ID_INVALID
)
if
(
rv
==
TIME_ZONE_ID_INVALID
)
throw
spdlog
::
spdlog_ex
(
"Failed getting timezone info. "
,
errno
);
throw
spdlog
::
spdlog_ex
(
"Failed getting timezone info. "
,
errno
);
int
offset
=
-
tzinfo
.
Bias
;
int
offset
=
-
tzinfo
.
Bias
;
if
(
tm
.
tm_isdst
)
if
(
tm
.
tm_isdst
)
offset
-=
tzinfo
.
DaylightBias
;
offset
-=
tzinfo
.
DaylightBias
;
else
else
offset
-=
tzinfo
.
StandardBias
;
offset
-=
tzinfo
.
StandardBias
;
return
offset
;
return
offset
;
#else
#else
#if defined(sun) || defined(__sun)
#if defined(sun) || defined(__sun)
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
struct
helper
struct
helper
{
{
static
long
int
calculate_gmt_offset
(
const
std
::
tm
&
localtm
=
details
::
os
::
localtime
(),
const
std
::
tm
&
gmtm
=
details
::
os
::
gmtime
())
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
local_year
=
localtm
.
tm_year
+
(
1900
-
1
);
int
gmt_year
=
gmtm
.
tm_year
+
(
1900
-
1
);
int
gmt_year
=
gmtm
.
tm_year
+
(
1900
-
1
);
long
int
days
=
(
long
int
days
=
(
// difference in day of year
// difference in day of year
localtm
.
tm_yday
-
gmtm
.
tm_yday
localtm
.
tm_yday
-
gmtm
.
tm_yday
// + intervening leap days
// + intervening leap days
+
((
local_year
>>
2
)
-
(
gmt_year
>>
2
))
+
((
local_year
>>
2
)
-
(
gmt_year
>>
2
))
-
(
local_year
/
100
-
gmt_year
/
100
)
-
(
local_year
/
100
-
gmt_year
/
100
)
+
((
local_year
/
100
>>
2
)
-
(
gmt_year
/
100
>>
2
))
+
((
local_year
/
100
>>
2
)
-
(
gmt_year
/
100
>>
2
))
// + difference in years * 365 */
// + difference in years * 365 */
+
(
long
int
)(
local_year
-
gmt_year
)
*
365
+
(
long
int
)(
local_year
-
gmt_year
)
*
365
);
);
long
int
hours
=
(
24
*
days
)
+
(
localtm
.
tm_hour
-
gmtm
.
tm_hour
);
long
int
hours
=
(
24
*
days
)
+
(
localtm
.
tm_hour
-
gmtm
.
tm_hour
);
long
int
mins
=
(
60
*
hours
)
+
(
localtm
.
tm_min
-
gmtm
.
tm_min
);
long
int
mins
=
(
60
*
hours
)
+
(
localtm
.
tm_min
-
gmtm
.
tm_min
);
long
int
secs
=
(
60
*
mins
)
+
(
localtm
.
tm_sec
-
gmtm
.
tm_sec
);
long
int
secs
=
(
60
*
mins
)
+
(
localtm
.
tm_sec
-
gmtm
.
tm_sec
);
return
secs
;
return
secs
;
}
}
};
};
long
int
offset_seconds
=
helper
::
calculate_gmt_offset
(
tm
);
long
int
offset_seconds
=
helper
::
calculate_gmt_offset
(
tm
);
#else
#else
long
int
offset_seconds
=
tm
.
tm_gmtoff
;
long
int
offset_seconds
=
tm
.
tm_gmtoff
;
#endif
#endif
return
static_cast
<
int
>
(
offset_seconds
/
60
);
return
static_cast
<
int
>
(
offset_seconds
/
60
);
#endif
#endif
}
}
//Return current thread id as size_t
//Return current thread id as size_t
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
inline
size_t
_thread_id
()
inline
size_t
_thread_id
()
{
{
#ifdef _WIN32
#ifdef _WIN32
return
static_cast
<
size_t
>
(
::
GetCurrentThreadId
());
return
static_cast
<
size_t
>
(
::
GetCurrentThreadId
());
#elif __linux__
#elif __linux__
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
# define SYS_gettid __NR_gettid
# define SYS_gettid __NR_gettid
# endif
# endif
return
static_cast
<
size_t
>
(
syscall
(
SYS_gettid
));
return
static_cast
<
size_t
>
(
syscall
(
SYS_gettid
));
#elif __FreeBSD__
#elif __FreeBSD__
long
tid
;
long
tid
;
thr_self
(
&
tid
);
thr_self
(
&
tid
);
return
static_cast
<
size_t
>
(
tid
);
return
static_cast
<
size_t
>
(
tid
);
#elif __APPLE__
#elif __APPLE__
uint64_t
tid
;
uint64_t
tid
;
pthread_threadid_np
(
nullptr
,
&
tid
);
pthread_threadid_np
(
nullptr
,
&
tid
);
return
static_cast
<
size_t
>
(
tid
);
return
static_cast
<
size_t
>
(
tid
);
#else //Default to standard C++11 (other Unix)
#else //Default to standard C++11 (other Unix)
return
static_cast
<
size_t
>
(
std
::
hash
<
std
::
thread
::
id
>
()(
std
::
this_thread
::
get_id
()));
return
static_cast
<
size_t
>
(
std
::
hash
<
std
::
thread
::
id
>
()(
std
::
this_thread
::
get_id
()));
#endif
#endif
}
}
//Return current thread id as size_t (from thread local storage)
//Return current thread id as size_t (from thread local storage)
inline
size_t
thread_id
()
inline
size_t
thread_id
()
{
{
#if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local)
#if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local)
return
_thread_id
();
return
_thread_id
();
#else
#else
static
thread_local
const
size_t
tid
=
_thread_id
();
static
thread_local
const
size_t
tid
=
_thread_id
();
return
tid
;
return
tid
;
#endif
#endif
}
}
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#define SPDLOG_FILENAME_T(s) L ## s
#define SPDLOG_FILENAME_T(s) L ## s
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
{
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>
,
wchar_t
>
c
;
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>
,
wchar_t
>
c
;
return
c
.
to_bytes
(
filename
);
return
c
.
to_bytes
(
filename
);
}
}
#else
#else
#define SPDLOG_FILENAME_T(s) s
#define SPDLOG_FILENAME_T(s) s
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
{
return
filename
;
return
filename
;
}
}
#endif
#endif
inline
std
::
string
errno_to_string
(
char
[
256
],
char
*
res
)
inline
std
::
string
errno_to_string
(
char
[
256
],
char
*
res
)
{
{
return
std
::
string
(
res
);
return
std
::
string
(
res
);
}
}
inline
std
::
string
errno_to_string
(
char
buf
[
256
],
int
res
)
inline
std
::
string
errno_to_string
(
char
buf
[
256
],
int
res
)
{
{
if
(
res
==
0
)
if
(
res
==
0
)
{
{
return
std
::
string
(
buf
);
return
std
::
string
(
buf
);
}
}
else
else
{
{
return
"Unknown error"
;
return
"Unknown error"
;
}
}
}
}
// Return errno string (thread safe)
// Return errno string (thread safe)
inline
std
::
string
errno_str
(
int
err_num
)
inline
std
::
string
errno_str
(
int
err_num
)
{
{
char
buf
[
256
];
char
buf
[
256
];
SPDLOG_CONSTEXPR
auto
buf_size
=
sizeof
(
buf
);
SPDLOG_CONSTEXPR
auto
buf_size
=
sizeof
(
buf
);
#ifdef _WIN32
#ifdef _WIN32
if
(
strerror_s
(
buf
,
buf_size
,
err_num
)
==
0
)
if
(
strerror_s
(
buf
,
buf_size
,
err_num
)
==
0
)
return
std
::
string
(
buf
);
return
std
::
string
(
buf
);
else
else
return
"Unknown error"
;
return
"Unknown error"
;
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
((
_POSIX_C_SOURCE
>=
200112L
)
&&
!
defined
(
_GNU_SOURCE
))
// posix version
((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version
if
(
strerror_r
(
err_num
,
buf
,
buf_size
)
==
0
)
if
(
strerror_r
(
err_num
,
buf
,
buf_size
)
==
0
)
return
std
::
string
(
buf
);
return
std
::
string
(
buf
);
else
else
return
"Unknown error"
;
return
"Unknown error"
;
#else // gnu version (might not use the given buf, so its retval pointer must be used)
#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
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
return
errno_to_string
(
buf
,
err
);
// use overloading to select correct stringify function
#endif
#endif
}
}
inline
int
pid
()
inline
int
pid
()
{
{
#ifdef _WIN32
#ifdef _WIN32
return
::
_getpid
();
return
::
_getpid
();
#else
#else
return
static_cast
<
int
>
(
::
getpid
());
return
static_cast
<
int
>
(
::
getpid
());
#endif
#endif
}
}
// Detrmine if the terminal supports colors
// Detrmine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/
// Source: https://github.com/agauniyal/rang/
inline
bool
is_color_terminal
()
inline
bool
is_color_terminal
()
{
{
#ifdef _WIN32
#ifdef _WIN32
return
true
;
return
true
;
#else
#else
static
constexpr
const
char
*
Terms
[]
=
static
constexpr
const
char
*
Terms
[]
=
{
{
"ansi"
,
"color"
,
"console"
,
"cygwin"
,
"gnome"
,
"konsole"
,
"kterm"
,
"ansi"
,
"color"
,
"console"
,
"cygwin"
,
"gnome"
,
"konsole"
,
"kterm"
,
"linux"
,
"msys"
,
"putty"
,
"rxvt"
,
"screen"
,
"vt100"
,
"xterm"
"linux"
,
"msys"
,
"putty"
,
"rxvt"
,
"screen"
,
"vt100"
,
"xterm"
};
};
const
char
*
env_p
=
std
::
getenv
(
"TERM"
);
const
char
*
env_p
=
std
::
getenv
(
"TERM"
);
if
(
env_p
==
nullptr
)
if
(
env_p
==
nullptr
)
{
{
return
false
;
return
false
;
}
}
static
const
bool
result
=
std
::
any_of
(
static
const
bool
result
=
std
::
any_of
(
std
::
begin
(
Terms
),
std
::
end
(
Terms
),
[
&
](
const
char
*
term
)
std
::
begin
(
Terms
),
std
::
end
(
Terms
),
[
&
](
const
char
*
term
)
{
{
return
std
::
strstr
(
env_p
,
term
)
!=
nullptr
;
return
std
::
strstr
(
env_p
,
term
)
!=
nullptr
;
});
});
return
result
;
return
result
;
#endif
#endif
}
}
// Detrmine if the terminal attached
// Detrmine if the terminal attached
// Source: https://github.com/agauniyal/rang/
// Source: https://github.com/agauniyal/rang/
inline
bool
in_terminal
(
FILE
*
file
)
inline
bool
in_terminal
(
FILE
*
file
)
{
{
#ifdef _WIN32
#ifdef _WIN32
return
_isatty
(
_fileno
(
file
))
?
true
:
false
;
return
_isatty
(
_fileno
(
file
))
?
true
:
false
;
#else
#else
return
isatty
(
fileno
(
file
))
?
true
:
false
;
return
isatty
(
fileno
(
file
))
?
true
:
false
;
#endif
#endif
}
}
}
//os
}
//os
}
//details
}
//details
}
//spdlog
}
//spdlog
include/spdlog/fmt/bundled/format.h
View file @
93be7713
This source diff could not be displayed because it is too large. You can
view the blob
instead.
include/spdlog/fmt/bundled/ostream.h
View file @
93be7713
...
@@ -13,57 +13,65 @@
...
@@ -13,57 +13,65 @@
#include "format.h"
#include "format.h"
#include <ostream>
#include <ostream>
namespace
fmt
{
namespace
fmt
{
namespace
internal
{
namespace
internal
{
template
<
class
Char
>
template
<
class
Char
>
class
FormatBuf
:
public
std
::
basic_streambuf
<
Char
>
{
class
FormatBuf
:
public
std
::
basic_streambuf
<
Char
>
private
:
{
typedef
typename
std
::
basic_streambuf
<
Char
>::
int_type
int_type
;
private
:
typedef
typename
std
::
basic_streambuf
<
Char
>::
traits_type
traits_type
;
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
protected
:
// simpler and has the advantage that the streambuf and the buffer are always
// The put-area is actually always empty. This makes the implementation
// in sync and sputc never writes into uninitialized memory. The obvious
// simpler and has the advantage that the streambuf and the buffer are always
// disadvantage is that each call to sputc always results in a (virtual) call
// in sync and sputc never writes into uninitialized memory. The obvious
// to overflow. There is no disadvantage here for sputn since this always
// disadvantage is that each call to sputc always results in a (virtual) call
// results in a call to xsputn.
// 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
()))
int_type
overflow
(
int_type
ch
=
traits_type
::
eof
())
FMT_OVERRIDE
buffer_
.
push_back
(
static_cast
<
Char
>
(
ch
));
{
return
ch
;
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
&
);
Yes
&
convert
(
std
::
ostream
&
);
struct
DummyStream
:
std
::
ostream
{
struct
DummyStream
:
std
::
ostream
DummyStream
();
// Suppress a bogus warning in MSVC.
{
// Hide all operator<< overloads from std::ostream.
DummyStream
();
// Suppress a bogus warning in MSVC.
void
operator
<<
(
Null
<>
);
// Hide all operator<< overloads from std::ostream.
void
operator
<<
(
Null
<>
);
};
};
No
&
operator
<<
(
std
::
ostream
&
,
int
);
No
&
operator
<<
(
std
::
ostream
&
,
int
);
template
<
typename
T
>
template
<
typename
T
>
struct
ConvertToIntImpl
<
T
,
true
>
{
struct
ConvertToIntImpl
<
T
,
true
>
// Convert to int only if T doesn't have an overloaded operator<<.
{
enum
{
// Convert to int only if T doesn't have an overloaded operator<<.
value
=
sizeof
(
convert
(
get
<
DummyStream
>
()
<<
get
<
T
>
()))
==
sizeof
(
No
)
enum
};
{
value
=
sizeof
(
convert
(
get
<
DummyStream
>
()
<<
get
<
T
>
()))
==
sizeof
(
No
)
};
};
};
// Write the content of w to os.
// Write the content of w to os.
...
@@ -73,16 +81,17 @@ FMT_API void write(std::ostream &os, Writer &w);
...
@@ -73,16 +81,17 @@ FMT_API void write(std::ostream &os, Writer &w);
// Formats a value.
// Formats a value.
template
<
typename
Char
,
typename
ArgFormatter_
,
typename
T
>
template
<
typename
Char
,
typename
ArgFormatter_
,
typename
T
>
void
format_arg
(
BasicFormatter
<
Char
,
ArgFormatter_
>
&
f
,
void
format_arg
(
BasicFormatter
<
Char
,
ArgFormatter_
>
&
f
,
const
Char
*&
format_str
,
const
T
&
value
)
{
const
Char
*&
format_str
,
const
T
&
value
)
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
>
buffer
;
{
internal
::
MemoryBuffer
<
Char
,
internal
::
INLINE_BUFFER_SIZE
>
buffer
;
internal
::
FormatBuf
<
Char
>
format_buf
(
buffer
);
internal
::
FormatBuf
<
Char
>
format_buf
(
buffer
);
std
::
basic_ostream
<
Char
>
output
(
&
format_buf
);
std
::
basic_ostream
<
Char
>
output
(
&
format_buf
);
output
<<
value
;
output
<<
value
;
BasicStringRef
<
Char
>
str
(
&
buffer
[
0
],
buffer
.
size
());
BasicStringRef
<
Char
>
str
(
&
buffer
[
0
],
buffer
.
size
());
typedef
internal
::
MakeArg
<
BasicFormatter
<
Char
>
>
MakeArg
;
typedef
internal
::
MakeArg
<
BasicFormatter
<
Char
>
>
MakeArg
;
format_str
=
f
.
format
(
format_str
,
MakeArg
(
str
));
format_str
=
f
.
format
(
format_str
,
MakeArg
(
str
));
}
}
/**
/**
...
...
include/spdlog/fmt/bundled/posix.h
View file @
93be7713
...
@@ -64,112 +64,134 @@
...
@@ -64,112 +64,134 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace
fmt
{
namespace
fmt
{
// An error code.
// An error code.
class
ErrorCode
{
class
ErrorCode
private
:
{
int
value_
;
private
:
int
value_
;
public
:
public
:
explicit
ErrorCode
(
int
value
=
0
)
FMT_NOEXCEPT
:
value_
(
value
)
{}
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.
// A buffered file.
class
BufferedFile
{
class
BufferedFile
private
:
{
FILE
*
file_
;
private
:
FILE
*
file_
;
friend
class
File
;
friend
class
File
;
explicit
BufferedFile
(
FILE
*
f
)
:
file_
(
f
)
{}
explicit
BufferedFile
(
FILE
*
f
)
:
file_
(
f
)
{}
public
:
public
:
// Constructs a BufferedFile object which doesn't represent any file.
// Constructs a BufferedFile object which doesn't represent any file.
BufferedFile
()
FMT_NOEXCEPT
:
file_
(
FMT_NULL
)
{}
BufferedFile
()
FMT_NOEXCEPT
:
file_
(
FMT_NULL
)
{}
// Destroys the object closing the file it represents if any.
// Destroys the object closing the file it represents if any.
FMT_API
~
BufferedFile
()
FMT_NOEXCEPT
;
FMT_API
~
BufferedFile
()
FMT_NOEXCEPT
;
#if !FMT_USE_RVALUE_REFERENCES
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
// references are not supported.
private
:
private
:
// A proxy object to emulate a move constructor.
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
// It is private to make it impossible call operator Proxy directly.
struct
Proxy
{
struct
Proxy
FILE
*
file
;
{
};
FILE
*
file
;
};
public
:
public
:
// A "move constructor" for moving from a temporary.
// A "move constructor" for moving from a temporary.
BufferedFile
(
Proxy
p
)
FMT_NOEXCEPT
:
file_
(
p
.
file
)
{}
BufferedFile
(
Proxy
p
)
FMT_NOEXCEPT
:
file_
(
p
.
file
)
{}
// A "move constructor" for moving from an lvalue.
BufferedFile
(
BufferedFile
&
f
)
FMT_NOEXCEPT
:
file_
(
f
.
file_
)
{
// A "move constructor" for moving from an lvalue.
f
.
file_
=
FMT_NULL
;
BufferedFile
(
BufferedFile
&
f
)
FMT_NOEXCEPT
:
}
file_
(
f
.
file_
)
{
// A "move assignment operator" for moving from a temporary.
f
.
file_
=
FMT_NULL
;
BufferedFile
&
operator
=
(
Proxy
p
)
{
}
close
();
file_
=
p
.
file
;
// A "move assignment operator" for moving from a temporary.
return
*
this
;
BufferedFile
&
operator
=
(
Proxy
p
)
}
{
close
();
// A "move assignment operator" for moving from an lvalue.
file_
=
p
.
file
;
BufferedFile
&
operator
=
(
BufferedFile
&
other
)
{
return
*
this
;
close
();
}
file_
=
other
.
file_
;
other
.
file_
=
FMT_NULL
;
// A "move assignment operator" for moving from an lvalue.
return
*
this
;
BufferedFile
&
operator
=
(
BufferedFile
&
other
)
}
{
close
();
// Returns a proxy object for moving from a temporary:
file_
=
other
.
file_
;
// BufferedFile file = BufferedFile(...);
other
.
file_
=
FMT_NULL
;
operator
Proxy
()
FMT_NOEXCEPT
{
return
*
this
;
Proxy
p
=
{
file_
};
}
file_
=
FMT_NULL
;
return
p
;
// 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
#else
private
:
private
:
FMT_DISALLOW_COPY_AND_ASSIGN
(
BufferedFile
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
BufferedFile
);
public
:
public
:
BufferedFile
(
BufferedFile
&&
other
)
FMT_NOEXCEPT
:
file_
(
other
.
file_
)
{
BufferedFile
(
BufferedFile
&&
other
)
FMT_NOEXCEPT
:
other
.
file_
=
FMT_NULL
;
file_
(
other
.
file_
)
}
{
other
.
file_
=
FMT_NULL
;
BufferedFile
&
operator
=
(
BufferedFile
&&
other
)
{
}
close
();
file_
=
other
.
file_
;
BufferedFile
&
operator
=
(
BufferedFile
&&
other
)
other
.
file_
=
FMT_NULL
;
{
return
*
this
;
close
();
}
file_
=
other
.
file_
;
other
.
file_
=
FMT_NULL
;
return
*
this
;
}
#endif
#endif
// Opens a file.
// Opens a file.
FMT_API
BufferedFile
(
CStringRef
filename
,
CStringRef
mode
);
FMT_API
BufferedFile
(
CStringRef
filename
,
CStringRef
mode
);
// Closes the file.
// Closes the file.
FMT_API
void
close
();
FMT_API
void
close
();
// Returns the pointer to a FILE object representing this file.
// Returns the pointer to a FILE object representing this file.
FILE
*
get
()
const
FMT_NOEXCEPT
{
return
file_
;
}
FILE
*
get
()
const
FMT_NOEXCEPT
{
return
file_
;
}
// We place parentheses around fileno to workaround a bug in some versions
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
// of MinGW that define fileno as a macro.
FMT_API
int
(
fileno
)()
const
;
FMT_API
int
(
fileno
)()
const
;
void
print
(
CStringRef
format_str
,
const
ArgList
&
args
)
{
void
print
(
CStringRef
format_str
,
const
ArgList
&
args
)
fmt
::
print
(
file_
,
format_str
,
args
);
{
}
fmt
::
print
(
file_
,
format_str
,
args
);
FMT_VARIADIC
(
void
,
print
,
CStringRef
)
}
FMT_VARIADIC
(
void
,
print
,
CStringRef
)
};
};
// A file. Closed file is represented by a File object with descriptor -1.
// A file. Closed file is represented by a File object with descriptor -1.
...
@@ -178,125 +200,141 @@ public:
...
@@ -178,125 +200,141 @@ public:
// closing the file multiple times will cause a crash on Windows rather
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
// invalid parameter handler with _set_invalid_parameter_handler.
class
File
{
class
File
private
:
{
int
fd_
;
// File descriptor.
private
:
int
fd_
;
// File descriptor.
// Constructs a File object with a given descriptor.
// Constructs a File object with a given descriptor.
explicit
File
(
int
fd
)
:
fd_
(
fd
)
{}
explicit
File
(
int
fd
)
:
fd_
(
fd
)
{}
public
:
public
:
// Possible values for the oflag argument to the constructor.
// Possible values for the oflag argument to the constructor.
enum
{
enum
RDONLY
=
FMT_POSIX
(
O_RDONLY
),
// Open for reading only.
{
WRONLY
=
FMT_POSIX
(
O_WRONLY
),
// Open for writing only.
RDONLY
=
FMT_POSIX
(
O_RDONLY
),
// Open for reading only.
RDWR
=
FMT_POSIX
(
O_RDWR
)
// Open for reading and writing.
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.
// Constructs a File object which doesn't represent any file.
File
()
FMT_NOEXCEPT
:
fd_
(
-
1
)
{}
File
()
FMT_NOEXCEPT
:
fd_
(
-
1
)
{}
// Opens a file and constructs a File object representing this file.
// Opens a file and constructs a File object representing this file.
FMT_API
File
(
CStringRef
path
,
int
oflag
);
FMT_API
File
(
CStringRef
path
,
int
oflag
);
#if !FMT_USE_RVALUE_REFERENCES
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
// references are not supported.
private
:
private
:
// A proxy object to emulate a move constructor.
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
// It is private to make it impossible call operator Proxy directly.
struct
Proxy
{
struct
Proxy
int
fd
;
{
};
int
fd
;
};
public
:
// A "move constructor" for moving from a temporary.
public
:
File
(
Proxy
p
)
FMT_NOEXCEPT
:
fd_
(
p
.
fd
)
{}
// A "move constructor" for moving from a temporary.
File
(
Proxy
p
)
FMT_NOEXCEPT
:
// A "move constructor" for moving from an lvalue.
fd_
(
p
.
fd
)
{}
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_
)
// A "move assignment operator" for moving from a temporary.
{
File
&
operator
=
(
Proxy
p
)
{
other
.
fd_
=
-
1
;
close
();
}
fd_
=
p
.
fd
;
return
*
this
;
// A "move assignment operator" for moving from a temporary.
}
File
&
operator
=
(
Proxy
p
)
{
// A "move assignment operator" for moving from an lvalue.
close
();
File
&
operator
=
(
File
&
other
)
{
fd_
=
p
.
fd
;
close
();
return
*
this
;
fd_
=
other
.
fd_
;
}
other
.
fd_
=
-
1
;
return
*
this
;
// A "move assignment operator" for moving from an lvalue.
}
File
&
operator
=
(
File
&
other
)
{
// Returns a proxy object for moving from a temporary:
close
();
// File file = File(...);
fd_
=
other
.
fd_
;
operator
Proxy
()
FMT_NOEXCEPT
{
other
.
fd_
=
-
1
;
Proxy
p
=
{
fd_
};
return
*
this
;
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
#else
private
:
private
:
FMT_DISALLOW_COPY_AND_ASSIGN
(
File
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
File
);
public
:
public
:
File
(
File
&&
other
)
FMT_NOEXCEPT
:
fd_
(
other
.
fd_
)
{
File
(
File
&&
other
)
FMT_NOEXCEPT
:
other
.
fd_
=
-
1
;
fd_
(
other
.
fd_
)
}
{
other
.
fd_
=
-
1
;
File
&
operator
=
(
File
&&
other
)
{
}
close
();
fd_
=
other
.
fd_
;
File
&
operator
=
(
File
&&
other
)
other
.
fd_
=
-
1
;
{
return
*
this
;
close
();
}
fd_
=
other
.
fd_
;
other
.
fd_
=
-
1
;
return
*
this
;
}
#endif
#endif
// Destroys the object closing the file it represents if any.
// Destroys the object closing the file it represents if any.
FMT_API
~
File
()
FMT_NOEXCEPT
;
FMT_API
~
File
()
FMT_NOEXCEPT
;
// Returns the file descriptor.
// Returns the file descriptor.
int
descriptor
()
const
FMT_NOEXCEPT
{
return
fd_
;
}
int
descriptor
()
const
FMT_NOEXCEPT
{
return
fd_
;
}
// Closes the file.
// Closes the file.
FMT_API
void
close
();
FMT_API
void
close
();
// Returns the file size. The size has signed type for consistency with
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
// stat::st_size.
FMT_API
LongLong
size
()
const
;
FMT_API
LongLong
size
()
const
;
// Attempts to read count bytes from the file into the specified buffer.
// Attempts to read count bytes from the file into the specified buffer.
FMT_API
std
::
size_t
read
(
void
*
buffer
,
std
::
size_t
count
);
FMT_API
std
::
size_t
read
(
void
*
buffer
,
std
::
size_t
count
);
// Attempts to write count bytes from the specified buffer to the file.
// 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
);
FMT_API
std
::
size_t
write
(
const
void
*
buffer
,
std
::
size_t
count
);
// Duplicates a file descriptor with the dup function and returns
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
// the duplicate as a file object.
FMT_API
static
File
dup
(
int
fd
);
FMT_API
static
File
dup
(
int
fd
);
// Makes fd be the copy of this file descriptor, closing fd first if
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
// necessary.
FMT_API
void
dup2
(
int
fd
);
FMT_API
void
dup2
(
int
fd
);
// Makes fd be the copy of this file descriptor, closing fd first if
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
// necessary.
FMT_API
void
dup2
(
int
fd
,
ErrorCode
&
ec
)
FMT_NOEXCEPT
;
FMT_API
void
dup2
(
int
fd
,
ErrorCode
&
ec
)
FMT_NOEXCEPT
;
// Creates a pipe setting up read_end and write_end file objects for reading
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
// and writing respectively.
FMT_API
static
void
pipe
(
File
&
read_end
,
File
&
write_end
);
FMT_API
static
void
pipe
(
File
&
read_end
,
File
&
write_end
);
// Creates a BufferedFile object associated with this file and detaches
// Creates a BufferedFile object associated with this file and detaches
// this File object from the file.
// this File object from the file.
FMT_API
BufferedFile
fdopen
(
const
char
*
mode
);
FMT_API
BufferedFile
fdopen
(
const
char
*
mode
);
};
};
// Returns the memory page size.
// Returns the memory page size.
...
@@ -309,58 +347,77 @@ long getpagesize();
...
@@ -309,58 +347,77 @@ long getpagesize();
#ifdef FMT_LOCALE
#ifdef FMT_LOCALE
// A "C" numeric locale.
// A "C" numeric locale.
class
Locale
{
class
Locale
private
:
{
private
:
# ifdef _MSC_VER
# 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
)
{
static
locale_t
newlocale
(
int
category_mask
,
const
char
*
locale
,
locale_t
)
return
_create_locale
(
category_mask
,
locale
);
{
}
return
_create_locale
(
category_mask
,
locale
);
}
static
void
freelocale
(
locale_t
locale
)
{
static
void
freelocale
(
locale_t
locale
)
_free_locale
(
locale
);
{
}
_free_locale
(
locale
);
}
static
double
strtod_l
(
const
char
*
nptr
,
char
**
endptr
,
_locale_t
locale
)
{
static
double
strtod_l
(
const
char
*
nptr
,
char
**
endptr
,
_locale_t
locale
)
return
_strtod_l
(
nptr
,
endptr
,
locale
);
{
}
return
_strtod_l
(
nptr
,
endptr
,
locale
);
}
# endif
# endif
locale_t
locale_
;
locale_t
locale_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
Locale
);
public
:
typedef
locale_t
Type
;
Locale
()
:
locale_
(
newlocale
(
LC_NUMERIC_MASK
,
"C"
,
FMT_NULL
))
{
FMT_DISALLOW_COPY_AND_ASSIGN
(
Locale
);
if
(
!
locale_
)
FMT_THROW
(
fmt
::
SystemError
(
errno
,
"cannot create locale"
));
}
~
Locale
()
{
freelocale
(
locale_
);
}
Type
get
()
const
{
return
locale_
;
}
public
:
typedef
locale_t
Type
;
// Converts string to floating-point number and advances str past the end
// of the parsed input.
Locale
()
:
locale_
(
newlocale
(
LC_NUMERIC_MASK
,
"C"
,
FMT_NULL
))
double
strtod
(
const
char
*&
str
)
const
{
{
char
*
end
=
FMT_NULL
;
if
(
!
locale_
)
double
result
=
strtod_l
(
str
,
&
end
,
locale_
);
FMT_THROW
(
fmt
::
SystemError
(
errno
,
"cannot create locale"
));
str
=
end
;
}
return
result
;
~
Locale
()
}
{
freelocale
(
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
;
}
};
};
#endif // FMT_LOCALE
#endif // FMT_LOCALE
}
// namespace fmt
}
// namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
#if !FMT_USE_RVALUE_REFERENCES
namespace
std
{
namespace
std
{
// For compatibility with C++98.
// For compatibility with C++98.
inline
fmt
::
BufferedFile
&
move
(
fmt
::
BufferedFile
&
f
)
{
return
f
;
}
inline
fmt
::
BufferedFile
&
move
(
fmt
::
BufferedFile
&
f
)
inline
fmt
::
File
&
move
(
fmt
::
File
&
f
)
{
return
f
;
}
{
return
f
;
}
inline
fmt
::
File
&
move
(
fmt
::
File
&
f
)
{
return
f
;
}
}
}
#endif
#endif
...
...
include/spdlog/fmt/bundled/printf.h
View file @
93be7713
...
@@ -15,78 +15,118 @@
...
@@ -15,78 +15,118 @@
#include "ostream.h"
#include "ostream.h"
namespace
fmt
{
namespace
fmt
namespace
internal
{
{
namespace
internal
{
// Checks if a value fits in int - used to avoid warnings about comparing
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
// signed and unsigned integers.
template
<
bool
IsSigned
>
template
<
bool
IsSigned
>
struct
IntChecker
{
struct
IntChecker
template
<
typename
T
>
{
static
bool
fits_in_int
(
T
value
)
{
template
<
typename
T
>
unsigned
max
=
std
::
numeric_limits
<
int
>::
max
();
static
bool
fits_in_int
(
T
value
)
return
value
<=
max
;
{
}
unsigned
max
=
std
::
numeric_limits
<
int
>::
max
();
static
bool
fits_in_int
(
bool
)
{
return
true
;
}
return
value
<=
max
;
}
static
bool
fits_in_int
(
bool
)
{
return
true
;
}
};
};
template
<>
template
<>
struct
IntChecker
<
true
>
{
struct
IntChecker
<
true
>
template
<
typename
T
>
{
static
bool
fits_in_int
(
T
value
)
{
template
<
typename
T
>
return
value
>=
std
::
numeric_limits
<
int
>::
min
()
&&
static
bool
fits_in_int
(
T
value
)
value
<=
std
::
numeric_limits
<
int
>::
max
();
{
}
return
value
>=
std
::
numeric_limits
<
int
>::
min
()
&&
static
bool
fits_in_int
(
int
)
{
return
true
;
}
value
<=
std
::
numeric_limits
<
int
>::
max
();
}
static
bool
fits_in_int
(
int
)
{
return
true
;
}
};
};
class
PrecisionHandler
:
public
ArgVisitor
<
PrecisionHandler
,
int
>
{
class
PrecisionHandler
:
public
ArgVisitor
<
PrecisionHandler
,
int
>
public
:
{
void
report_unhandled_arg
()
{
public
:
FMT_THROW
(
FormatError
(
"precision is not integer"
));
void
report_unhandled_arg
()
}
{
FMT_THROW
(
FormatError
(
"precision is not integer"
));
template
<
typename
T
>
}
int
visit_any_int
(
T
value
)
{
if
(
!
IntChecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
fits_in_int
(
value
))
template
<
typename
T
>
FMT_THROW
(
FormatError
(
"number is too big"
));
int
visit_any_int
(
T
value
)
return
static_cast
<
int
>
(
value
);
{
}
if
(
!
IntChecker
<
std
::
numeric_limits
<
T
>::
is_signed
>::
fits_in_int
(
value
))
FMT_THROW
(
FormatError
(
"number is too big"
));
return
static_cast
<
int
>
(
value
);
}
};
};
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class
IsZeroInt
:
public
ArgVisitor
<
IsZeroInt
,
bool
>
{
class
IsZeroInt
:
public
ArgVisitor
<
IsZeroInt
,
bool
>
public
:
{
template
<
typename
T
>
public
:
bool
visit_any_int
(
T
value
)
{
return
value
==
0
;
}
template
<
typename
T
>
bool
visit_any_int
(
T
value
)
{
return
value
==
0
;
}
};
};
// returns the default type for format specific "%s"
// returns the default type for format specific "%s"
class
DefaultType
:
public
ArgVisitor
<
DefaultType
,
char
>
{
class
DefaultType
:
public
ArgVisitor
<
DefaultType
,
char
>
public
:
{
char
visit_char
(
int
)
{
return
'c'
;
}
public
:
char
visit_char
(
int
)
{
return
'c'
;
}
char
visit_bool
(
bool
)
{
return
's'
;
}
char
visit_bool
(
bool
)
{
return
's'
;
}
char
visit_pointer
(
const
void
*
)
{
return
'p'
;
}
char
visit_pointer
(
const
void
*
)
{
return
'p'
;
}
template
<
typename
T
>
template
<
typename
T
>
char
visit_any_int
(
T
)
{
return
'd'
;
}
char
visit_any_int
(
T
)
{
return
'd'
;
}
template
<
typename
T
>
template
<
typename
T
>
char
visit_any_double
(
T
)
{
return
'g'
;
}
char
visit_any_double
(
T
)
{
return
'g'
;
}
char
visit_unhandled_arg
()
{
return
's'
;
}
char
visit_unhandled_arg
()
{
return
's'
;
}
};
};
template
<
typename
T
,
typename
U
>
template
<
typename
T
,
typename
U
>
struct
is_same
{
struct
is_same
enum
{
value
=
0
};
{
enum
{
value
=
0
};
};
};
template
<
typename
T
>
template
<
typename
T
>
struct
is_same
<
T
,
T
>
{
struct
is_same
<
T
,
T
>
enum
{
value
=
1
};
{
enum
{
value
=
1
};
};
};
// An argument visitor that converts an integer argument to T for printf,
// An argument visitor that converts an integer argument to T for printf,
...
@@ -94,108 +134,128 @@ struct is_same<T, T> {
...
@@ -94,108 +134,128 @@ struct is_same<T, T> {
// corresponding signed or unsigned type depending on the type specifier:
// corresponding signed or unsigned type depending on the type specifier:
// 'd' and 'i' - signed, other - unsigned)
// 'd' and 'i' - signed, other - unsigned)
template
<
typename
T
=
void
>
template
<
typename
T
=
void
>
class
ArgConverter
:
public
ArgVisitor
<
ArgConverter
<
T
>
,
void
>
{
class
ArgConverter
:
public
ArgVisitor
<
ArgConverter
<
T
>
,
void
>
private
:
{
internal
::
Arg
&
arg_
;
private
:
wchar_t
type_
;
internal
::
Arg
&
arg_
;
wchar_t
type_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgConverter
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
ArgConverter
);
public
:
ArgConverter
(
internal
::
Arg
&
arg
,
wchar_t
type
)
public
:
:
arg_
(
arg
),
type_
(
type
)
{}
ArgConverter
(
internal
::
Arg
&
arg
,
wchar_t
type
)
:
arg_
(
arg
),
type_
(
type
)
{}
void
visit_bool
(
bool
value
)
{
if
(
type_
!=
's'
)
void
visit_bool
(
bool
value
)
visit_any_int
(
value
);
{
}
if
(
type_
!=
's'
)
visit_any_int
(
value
);
void
visit_char
(
char
value
)
{
}
if
(
type_
!=
's'
)
visit_any_int
(
value
);
void
visit_char
(
char
value
)
}
{
if
(
type_
!=
's'
)
template
<
typename
U
>
visit_any_int
(
value
);
void
visit_any_int
(
U
value
)
{
bool
is_signed
=
type_
==
'd'
||
type_
==
'i'
;
if
(
type_
==
's'
)
{
is_signed
=
std
::
numeric_limits
<
U
>::
is_signed
;
}
}
using
internal
::
Arg
;
template
<
typename
U
>
typedef
typename
internal
::
Conditional
<
void
visit_any_int
(
U
value
)
{
bool
is_signed
=
type_
==
'd'
||
type_
==
'i'
;
if
(
type_
==
's'
)
{
is_signed
=
std
::
numeric_limits
<
U
>::
is_signed
;
}
using
internal
::
Arg
;
typedef
typename
internal
::
Conditional
<
is_same
<
T
,
void
>::
value
,
U
,
T
>::
type
TargetType
;
is_same
<
T
,
void
>::
value
,
U
,
T
>::
type
TargetType
;
if
(
sizeof
(
TargetType
)
<=
sizeof
(
int
))
{
if
(
sizeof
(
TargetType
)
<=
sizeof
(
int
))
// Extra casts are used to silence warnings.
{
if
(
is_signed
)
{
// Extra casts are used to silence warnings.
arg_
.
type
=
Arg
::
INT
;
if
(
is_signed
)
arg_
.
int_value
=
static_cast
<
int
>
(
static_cast
<
TargetType
>
(
value
));
{
}
else
{
arg_
.
type
=
Arg
::
INT
;
arg_
.
type
=
Arg
::
UINT
;
arg_
.
int_value
=
static_cast
<
int
>
(
static_cast
<
TargetType
>
(
value
));
typedef
typename
internal
::
MakeUnsigned
<
TargetType
>::
Type
Unsigned
;
}
arg_
.
uint_value
=
static_cast
<
unsigned
>
(
static_cast
<
Unsigned
>
(
value
));
else
}
{
}
else
{
arg_
.
type
=
Arg
::
UINT
;
if
(
is_signed
)
{
typedef
typename
internal
::
MakeUnsigned
<
TargetType
>::
Type
Unsigned
;
arg_
.
type
=
Arg
::
LONG_LONG
;
arg_
.
uint_value
=
static_cast
<
unsigned
>
(
static_cast
<
Unsigned
>
(
value
));
// glibc's printf doesn't sign extend arguments of smaller types:
}
// std::printf("%lld", -42); // prints "4294967254"
}
// but we don't have to do the same because it's a UB.
else
arg_
.
long_long_value
=
static_cast
<
LongLong
>
(
value
);
{
}
else
{
if
(
is_signed
)
arg_
.
type
=
Arg
::
ULONG_LONG
;
{
arg_
.
ulong_long_value
=
arg_
.
type
=
Arg
::
LONG_LONG
;
static_cast
<
typename
internal
::
MakeUnsigned
<
U
>::
Type
>
(
value
);
// glibc's printf doesn't sign extend arguments of smaller types:
}
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB.
arg_
.
long_long_value
=
static_cast
<
LongLong
>
(
value
);
}
else
{
arg_
.
type
=
Arg
::
ULONG_LONG
;
arg_
.
ulong_long_value
=
static_cast
<
typename
internal
::
MakeUnsigned
<
U
>::
Type
>
(
value
);
}
}
}
}
}
};
};
// Converts an integer argument to char for printf.
// Converts an integer argument to char for printf.
class
CharConverter
:
public
ArgVisitor
<
CharConverter
,
void
>
{
class
CharConverter
:
public
ArgVisitor
<
CharConverter
,
void
>
private
:
{
internal
::
Arg
&
arg_
;
private
:
internal
::
Arg
&
arg_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
CharConverter
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
CharConverter
);
public
:
public
:
explicit
CharConverter
(
internal
::
Arg
&
arg
)
:
arg_
(
arg
)
{}
explicit
CharConverter
(
internal
::
Arg
&
arg
)
:
arg_
(
arg
)
{}
template
<
typename
T
>
template
<
typename
T
>
void
visit_any_int
(
T
value
)
{
void
visit_any_int
(
T
value
)
arg_
.
type
=
internal
::
Arg
::
CHAR
;
{
arg_
.
int_value
=
static_cast
<
char
>
(
value
);
arg_
.
type
=
internal
::
Arg
::
CHAR
;
}
arg_
.
int_value
=
static_cast
<
char
>
(
value
);
}
};
};
// Checks if an argument is a valid printf width specifier and sets
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
// left alignment if it is negative.
class
WidthHandler
:
public
ArgVisitor
<
WidthHandler
,
unsigned
>
{
class
WidthHandler
:
public
ArgVisitor
<
WidthHandler
,
unsigned
>
private
:
{
FormatSpec
&
spec_
;
private
:
FormatSpec
&
spec_
;
FMT_DISALLOW_COPY_AND_ASSIGN
(
WidthHandler
);
FMT_DISALLOW_COPY_AND_ASSIGN
(
WidthHandler
);
public
:
explicit
WidthHandler
(
FormatSpec
&
spec
)
:
spec_
(
spec
)
{}
public
:
explicit
WidthHandler
(
FormatSpec
&
spec
)
:
spec_
(
spec
)
{}
void
report_unhandled_arg
()
{
FMT_THROW
(
FormatError
(
"width is not integer"
));
void
report_unhandled_arg
()
}
{
FMT_THROW
(
FormatError
(
"width is not integer"
));
template
<
typename
T
>
}
unsigned
visit_any_int
(
T
value
)
{
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
template
<
typename
T
>
UnsignedType
width
=
static_cast
<
UnsignedType
>
(
value
);
unsigned
visit_any_int
(
T
value
)
if
(
internal
::
is_negative
(
value
))
{
{
spec_
.
align_
=
ALIGN_LEFT
;
typedef
typename
internal
::
IntTraits
<
T
>::
MainType
UnsignedType
;
width
=
0
-
width
;
UnsignedType
width
=
static_cast
<
UnsignedType
>
(
value
);
if
(
internal
::
is_negative
(
value
))
{
spec_
.
align_
=
ALIGN_LEFT
;
width
=
0
-
width
;
}
unsigned
int_max
=
std
::
numeric_limits
<
int
>::
max
();
if
(
width
>
int_max
)
FMT_THROW
(
FormatError
(
"number is too big"
));
return
static_cast
<
unsigned
>
(
width
);
}
}
unsigned
int_max
=
std
::
numeric_limits
<
int
>::
max
();
if
(
width
>
int_max
)
FMT_THROW
(
FormatError
(
"number is too big"
));
return
static_cast
<
unsigned
>
(
width
);
}
};
};
}
// namespace internal
}
// namespace internal
...
@@ -218,314 +278,359 @@ class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
...
@@ -218,314 +278,359 @@ class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
*/
*/
template
<
typename
Impl
,
typename
Char
,
typename
Spec
>
template
<
typename
Impl
,
typename
Char
,
typename
Spec
>
class
BasicPrintfArgFormatter
:
class
BasicPrintfArgFormatter
:
public
internal
::
ArgFormatterBase
<
Impl
,
Char
,
Spec
>
{
public
internal
::
ArgFormatterBase
<
Impl
,
Char
,
Spec
>
private
:
{
void
write_null_pointer
()
{
private
:
this
->
spec
().
type_
=
0
;
void
write_null_pointer
()
this
->
write
(
"(nil)"
);
{
}
this
->
spec
().
type_
=
0
;
this
->
write
(
"(nil)"
);
typedef
internal
::
ArgFormatterBase
<
Impl
,
Char
,
Spec
>
Base
;
}
public
:
typedef
internal
::
ArgFormatterBase
<
Impl
,
Char
,
Spec
>
Base
;
/**
\rst
public
:
Constructs an argument formatter object.
/**
*writer* is a reference to the output writer and *spec* contains format
\rst
specifier information for standard argument types.
Constructs an argument formatter object.
\endrst
*writer* is a reference to the output writer and *spec* contains format
*/
specifier information for standard argument types.
BasicPrintfArgFormatter
(
BasicWriter
<
Char
>
&
w
,
Spec
&
s
)
\endrst
:
internal
::
ArgFormatterBase
<
Impl
,
Char
,
Spec
>
(
w
,
s
)
{}
*/
BasicPrintfArgFormatter
(
BasicWriter
<
Char
>
&
w
,
Spec
&
s
)
/** Formats an argument of type ``bool``. */
:
internal
::
ArgFormatterBase
<
Impl
,
Char
,
Spec
>
(
w
,
s
)
{}
void
visit_bool
(
bool
value
)
{
Spec
&
fmt_spec
=
this
->
spec
();
/** Formats an argument of type ``bool``. */
if
(
fmt_spec
.
type_
!=
's'
)
void
visit_bool
(
bool
value
)
return
this
->
visit_any_int
(
value
);
{
fmt_spec
.
type_
=
0
;
Spec
&
fmt_spec
=
this
->
spec
();
this
->
write
(
value
);
if
(
fmt_spec
.
type_
!=
's'
)
}
return
this
->
visit_any_int
(
value
);
fmt_spec
.
type_
=
0
;
/** Formats a character. */
this
->
write
(
value
);
void
visit_char
(
int
value
)
{
}
const
Spec
&
fmt_spec
=
this
->
spec
();
BasicWriter
<
Char
>
&
w
=
this
->
writer
();
/** Formats a character. */
if
(
fmt_spec
.
type_
&&
fmt_spec
.
type_
!=
'c'
)
void
visit_char
(
int
value
)
w
.
write_int
(
value
,
fmt_spec
);
{
typedef
typename
BasicWriter
<
Char
>::
CharPtr
CharPtr
;
const
Spec
&
fmt_spec
=
this
->
spec
();
CharPtr
out
=
CharPtr
();
BasicWriter
<
Char
>
&
w
=
this
->
writer
();
if
(
fmt_spec
.
width_
>
1
)
{
if
(
fmt_spec
.
type_
&&
fmt_spec
.
type_
!=
'c'
)
Char
fill
=
' '
;
w
.
write_int
(
value
,
fmt_spec
);
out
=
w
.
grow_buffer
(
fmt_spec
.
width_
);
typedef
typename
BasicWriter
<
Char
>::
CharPtr
CharPtr
;
if
(
fmt_spec
.
align_
!=
ALIGN_LEFT
)
{
CharPtr
out
=
CharPtr
();
std
::
fill_n
(
out
,
fmt_spec
.
width_
-
1
,
fill
);
if
(
fmt_spec
.
width_
>
1
)
out
+=
fmt_spec
.
width_
-
1
;
{
}
else
{
Char
fill
=
' '
;
std
::
fill_n
(
out
+
1
,
fmt_spec
.
width_
-
1
,
fill
);
out
=
w
.
grow_buffer
(
fmt_spec
.
width_
);
}
if
(
fmt_spec
.
align_
!=
ALIGN_LEFT
)
}
else
{
{
out
=
w
.
grow_buffer
(
1
);
std
::
fill_n
(
out
,
fmt_spec
.
width_
-
1
,
fill
);
out
+=
fmt_spec
.
width_
-
1
;
}
else
{
std
::
fill_n
(
out
+
1
,
fmt_spec
.
width_
-
1
,
fill
);
}
}
else
{
out
=
w
.
grow_buffer
(
1
);
}
*
out
=
static_cast
<
Char
>
(
value
);
}
/** Formats a null-terminated C string. */
void
visit_cstring
(
const
char
*
value
)
{
if
(
value
)
Base
::
visit_cstring
(
value
);
else
if
(
this
->
spec
().
type_
==
'p'
)
write_null_pointer
();
else
this
->
write
(
"(null)"
);
}
/** Formats a pointer. */
void
visit_pointer
(
const
void
*
value
)
{
if
(
value
)
return
Base
::
visit_pointer
(
value
);
this
->
spec
().
type_
=
0
;
write_null_pointer
();
}
/** Formats an argument of a custom (user-defined) type. */
void
visit_custom
(
internal
::
Arg
::
CustomValue
c
)
{
BasicFormatter
<
Char
>
formatter
(
ArgList
(),
this
->
writer
());
const
Char
format_str
[]
=
{
'}'
,
0
};
const
Char
*
format
=
format_str
;
c
.
format
(
&
formatter
,
c
.
value
,
&
format
);
}
}
*
out
=
static_cast
<
Char
>
(
value
);
}
/** Formats a null-terminated C string. */
void
visit_cstring
(
const
char
*
value
)
{
if
(
value
)
Base
::
visit_cstring
(
value
);
else
if
(
this
->
spec
().
type_
==
'p'
)
write_null_pointer
();
else
this
->
write
(
"(null)"
);
}
/** Formats a pointer. */
void
visit_pointer
(
const
void
*
value
)
{
if
(
value
)
return
Base
::
visit_pointer
(
value
);
this
->
spec
().
type_
=
0
;
write_null_pointer
();
}
/** Formats an argument of a custom (user-defined) type. */
void
visit_custom
(
internal
::
Arg
::
CustomValue
c
)
{
BasicFormatter
<
Char
>
formatter
(
ArgList
(),
this
->
writer
());
const
Char
format_str
[]
=
{
'}'
,
0
};
const
Char
*
format
=
format_str
;
c
.
format
(
&
formatter
,
c
.
value
,
&
format
);
}
};
};
/** The default printf argument formatter. */
/** The default printf argument formatter. */
template
<
typename
Char
>
template
<
typename
Char
>
class
PrintfArgFormatter
:
class
PrintfArgFormatter
:
public
BasicPrintfArgFormatter
<
PrintfArgFormatter
<
Char
>
,
Char
,
FormatSpec
>
{
public
BasicPrintfArgFormatter
<
PrintfArgFormatter
<
Char
>
,
Char
,
FormatSpec
>
public
:
{
/** Constructs an argument formatter object. */
public
:
PrintfArgFormatter
(
BasicWriter
<
Char
>
&
w
,
FormatSpec
&
s
)
/** Constructs an argument formatter object. */
:
BasicPrintfArgFormatter
<
PrintfArgFormatter
<
Char
>
,
Char
,
FormatSpec
>
(
w
,
s
)
{}
PrintfArgFormatter
(
BasicWriter
<
Char
>
&
w
,
FormatSpec
&
s
)
:
BasicPrintfArgFormatter
<
PrintfArgFormatter
<
Char
>
,
Char
,
FormatSpec
>
(
w
,
s
)
{}
};
};
/** This template formats data and writes the output to a writer. */
/** This template formats data and writes the output to a writer. */
template
<
typename
Char
,
typename
ArgFormatter
=
PrintfArgFormatter
<
Char
>
>
template
<
typename
Char
,
typename
ArgFormatter
=
PrintfArgFormatter
<
Char
>
>
class
PrintfFormatter
:
private
internal
::
FormatterBase
{
class
PrintfFormatter
:
private
internal
::
FormatterBase
private
:
{
BasicWriter
<
Char
>
&
writer_
;
private
:
BasicWriter
<
Char
>
&
writer_
;
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
void
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
// Returns the argument with specified index or, if arg_index is equal
internal
::
Arg
get_arg
(
// to the maximum unsigned value, the next argument.
const
Char
*
s
,
internal
::
Arg
get_arg
(
unsigned
arg_index
=
(
std
::
numeric_limits
<
unsigned
>::
max
)());
const
Char
*
s
,
unsigned
arg_index
=
(
std
::
numeric_limits
<
unsigned
>::
max
)());
// Parses argument index, flags and width and returns the argument index.
unsigned
parse_header
(
const
Char
*&
s
,
FormatSpec
&
spec
);
// Parses argument index, flags and width and returns the argument index.
unsigned
parse_header
(
const
Char
*&
s
,
FormatSpec
&
spec
);
public
:
/**
public
:
\rst
/**
Constructs a ``PrintfFormatter`` object. References to the arguments and
\rst
the writer are stored in the formatter object so make sure they have
Constructs a ``PrintfFormatter`` object. References to the arguments and
appropriate lifetimes.
the writer are stored in the formatter object so make sure they have
\endrst
appropriate lifetimes.
*/
\endrst
explicit
PrintfFormatter
(
const
ArgList
&
al
,
BasicWriter
<
Char
>
&
w
)
*/
:
FormatterBase
(
al
),
writer_
(
w
)
{}
explicit
PrintfFormatter
(
const
ArgList
&
al
,
BasicWriter
<
Char
>
&
w
)
:
FormatterBase
(
al
),
writer_
(
w
)
{}
/** Formats stored arguments and writes the output to the writer. */
void
format
(
BasicCStringRef
<
Char
>
format_str
);
/** Formats stored arguments and writes the output to the writer. */
void
format
(
BasicCStringRef
<
Char
>
format_str
);
};
};
template
<
typename
Char
,
typename
AF
>
template
<
typename
Char
,
typename
AF
>
void
PrintfFormatter
<
Char
,
AF
>::
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
)
{
void
PrintfFormatter
<
Char
,
AF
>::
parse_flags
(
FormatSpec
&
spec
,
const
Char
*&
s
)
for
(;;)
{
{
switch
(
*
s
++
)
{
for
(;;)
case
'-'
:
{
spec
.
align_
=
ALIGN_LEFT
;
switch
(
*
s
++
)
break
;
{
case
'+'
:
case
'-'
:
spec
.
flags_
|=
SIGN_FLAG
|
PLUS_FLAG
;
spec
.
align_
=
ALIGN_LEFT
;
break
;
break
;
case
'0'
:
case
'+'
:
spec
.
fill_
=
'0'
;
spec
.
flags_
|=
SIGN_FLAG
|
PLUS_FLAG
;
break
;
break
;
case
' '
:
case
'0'
:
spec
.
flags_
|=
SIGN_FLAG
;
spec
.
fill_
=
'0'
;
break
;
break
;
case
'#'
:
case
' '
:
spec
.
flags_
|=
HASH_FLAG
;
spec
.
flags_
|=
SIGN_FLAG
;
break
;
break
;
default
:
case
'#'
:
--
s
;
spec
.
flags_
|=
HASH_FLAG
;
return
;
break
;
default
:
--
s
;
return
;
}
}
}
}
}
}
template
<
typename
Char
,
typename
AF
>
template
<
typename
Char
,
typename
AF
>
internal
::
Arg
PrintfFormatter
<
Char
,
AF
>::
get_arg
(
const
Char
*
s
,
internal
::
Arg
PrintfFormatter
<
Char
,
AF
>::
get_arg
(
const
Char
*
s
,
unsigned
arg_index
)
{
unsigned
arg_index
)
(
void
)
s
;
{
const
char
*
error
=
FMT_NULL
;
(
void
)
s
;
internal
::
Arg
arg
=
arg_index
==
std
::
numeric_limits
<
unsigned
>::
max
()
?
const
char
*
error
=
FMT_NULL
;
next_arg
(
error
)
:
FormatterBase
::
get_arg
(
arg_index
-
1
,
error
);
internal
::
Arg
arg
=
arg_index
==
std
::
numeric_limits
<
unsigned
>::
max
()
?
if
(
error
)
next_arg
(
error
)
:
FormatterBase
::
get_arg
(
arg_index
-
1
,
error
);
FMT_THROW
(
FormatError
(
!*
s
?
"invalid format string"
:
error
));
if
(
error
)
return
arg
;
FMT_THROW
(
FormatError
(
!*
s
?
"invalid format string"
:
error
));
return
arg
;
}
}
template
<
typename
Char
,
typename
AF
>
template
<
typename
Char
,
typename
AF
>
unsigned
PrintfFormatter
<
Char
,
AF
>::
parse_header
(
unsigned
PrintfFormatter
<
Char
,
AF
>::
parse_header
(
const
Char
*&
s
,
FormatSpec
&
spec
)
{
const
Char
*&
s
,
FormatSpec
&
spec
)
unsigned
arg_index
=
std
::
numeric_limits
<
unsigned
>::
max
();
{
Char
c
=
*
s
;
unsigned
arg_index
=
std
::
numeric_limits
<
unsigned
>::
max
();
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
Char
c
=
*
s
;
// Parse an argument index (if followed by '$') or a width possibly
if
(
c
>=
'0'
&&
c
<=
'9'
)
// preceded with '0' flag(s).
{
unsigned
value
=
internal
::
parse_nonnegative_int
(
s
);
// Parse an argument index (if followed by '$') or a width possibly
if
(
*
s
==
'$'
)
{
// value is an argument index
// preceded with '0' flag(s).
++
s
;
unsigned
value
=
internal
::
parse_nonnegative_int
(
s
);
arg_index
=
value
;
if
(
*
s
==
'$'
)
// value is an argument index
}
else
{
{
if
(
c
==
'0'
)
++
s
;
spec
.
fill_
=
'0'
;
arg_index
=
value
;
if
(
value
!=
0
)
{
}
// Nonzero value means that we parsed width and don't need to
else
// parse it or flags again, so return now.
{
spec
.
width_
=
value
;
if
(
c
==
'0'
)
return
arg_index
;
spec
.
fill_
=
'0'
;
}
if
(
value
!=
0
)
{
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec
.
width_
=
value
;
return
arg_index
;
}
}
}
}
}
parse_flags
(
spec
,
s
);
parse_flags
(
spec
,
s
);
// Parse width.
// Parse width.
if
(
*
s
>=
'0'
&&
*
s
<=
'9'
)
if
(
*
s
>=
'0'
&&
*
s
<=
'9'
)
{
{
spec
.
width_
=
internal
::
parse_nonnegative_int
(
s
);
spec
.
width_
=
internal
::
parse_nonnegative_int
(
s
);
}
else
if
(
*
s
==
'*'
)
{
++
s
;
spec
.
width_
=
internal
::
WidthHandler
(
spec
).
visit
(
get_arg
(
s
));
}
return
arg_index
;
}
template
<
typename
Char
,
typename
AF
>
void
PrintfFormatter
<
Char
,
AF
>::
format
(
BasicCStringRef
<
Char
>
format_str
)
{
const
Char
*
start
=
format_str
.
c_str
();
const
Char
*
s
=
start
;
while
(
*
s
)
{
Char
c
=
*
s
++
;
if
(
c
!=
'%'
)
continue
;
if
(
*
s
==
c
)
{
write
(
writer_
,
start
,
s
);
start
=
++
s
;
continue
;
}
}
write
(
writer_
,
start
,
s
-
1
);
else
if
(
*
s
==
'*'
)
{
FormatSpec
spec
;
spec
.
align_
=
ALIGN_RIGHT
;
// Parse argument index, flags and width.
unsigned
arg_index
=
parse_header
(
s
,
spec
);
// Parse precision.
if
(
*
s
==
'.'
)
{
++
s
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
precision_
=
static_cast
<
int
>
(
internal
::
parse_nonnegative_int
(
s
));
}
else
if
(
*
s
==
'*'
)
{
++
s
;
++
s
;
spec
.
precision_
=
internal
::
PrecisionHandler
().
visit
(
get_arg
(
s
));
spec
.
width_
=
internal
::
WidthHandler
(
spec
).
visit
(
get_arg
(
s
));
}
else
{
spec
.
precision_
=
0
;
}
}
using
internal
::
Arg
;
Arg
arg
=
get_arg
(
s
,
arg_index
);
if
(
spec
.
flag
(
HASH_FLAG
)
&&
internal
::
IsZeroInt
().
visit
(
arg
))
spec
.
flags_
&=
~
internal
::
to_unsigned
<
int
>
(
HASH_FLAG
);
if
(
spec
.
fill_
==
'0'
)
{
if
(
arg
.
type
<=
Arg
::
LAST_NUMERIC_TYPE
)
spec
.
align_
=
ALIGN_NUMERIC
;
else
spec
.
fill_
=
' '
;
// Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
using
internal
::
ArgConverter
;
switch
(
*
s
++
)
{
case
'h'
:
if
(
*
s
==
'h'
)
ArgConverter
<
signed
char
>
(
arg
,
*++
s
).
visit
(
arg
);
else
ArgConverter
<
short
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'l'
:
if
(
*
s
==
'l'
)
ArgConverter
<
fmt
::
LongLong
>
(
arg
,
*++
s
).
visit
(
arg
);
else
ArgConverter
<
long
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'j'
:
ArgConverter
<
intmax_t
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'z'
:
ArgConverter
<
std
::
size_t
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
't'
:
ArgConverter
<
std
::
ptrdiff_t
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'L'
:
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break
;
default
:
--
s
;
ArgConverter
<
void
>
(
arg
,
*
s
).
visit
(
arg
);
}
// Parse type.
if
(
!*
s
)
FMT_THROW
(
FormatError
(
"invalid format string"
));
spec
.
type_
=
static_cast
<
char
>
(
*
s
++
);
if
(
spec
.
type_
==
's'
)
{
// set the format type to the default if 's' is specified
spec
.
type_
=
internal
::
DefaultType
().
visit
(
arg
);
}
}
return
arg_index
;
}
if
(
arg
.
type
<=
Arg
::
LAST_INTEGER_TYPE
)
{
template
<
typename
Char
,
typename
AF
>
// Normalize type.
void
PrintfFormatter
<
Char
,
AF
>::
format
(
BasicCStringRef
<
Char
>
format_str
)
switch
(
spec
.
type_
)
{
{
case
'i'
:
case
'u'
:
const
Char
*
start
=
format_str
.
c_str
();
spec
.
type_
=
'd'
;
const
Char
*
s
=
start
;
break
;
while
(
*
s
)
case
'c'
:
{
// TODO: handle wchar_t
Char
c
=
*
s
++
;
internal
::
CharConverter
(
arg
).
visit
(
arg
);
if
(
c
!=
'%'
)
continue
;
break
;
if
(
*
s
==
c
)
}
{
write
(
writer_
,
start
,
s
);
start
=
++
s
;
continue
;
}
write
(
writer_
,
start
,
s
-
1
);
FormatSpec
spec
;
spec
.
align_
=
ALIGN_RIGHT
;
// Parse argument index, flags and width.
unsigned
arg_index
=
parse_header
(
s
,
spec
);
// Parse precision.
if
(
*
s
==
'.'
)
{
++
s
;
if
(
'0'
<=
*
s
&&
*
s
<=
'9'
)
{
spec
.
precision_
=
static_cast
<
int
>
(
internal
::
parse_nonnegative_int
(
s
));
}
else
if
(
*
s
==
'*'
)
{
++
s
;
spec
.
precision_
=
internal
::
PrecisionHandler
().
visit
(
get_arg
(
s
));
}
else
{
spec
.
precision_
=
0
;
}
}
using
internal
::
Arg
;
Arg
arg
=
get_arg
(
s
,
arg_index
);
if
(
spec
.
flag
(
HASH_FLAG
)
&&
internal
::
IsZeroInt
().
visit
(
arg
))
spec
.
flags_
&=
~
internal
::
to_unsigned
<
int
>
(
HASH_FLAG
);
if
(
spec
.
fill_
==
'0'
)
{
if
(
arg
.
type
<=
Arg
::
LAST_NUMERIC_TYPE
)
spec
.
align_
=
ALIGN_NUMERIC
;
else
spec
.
fill_
=
' '
;
// Ignore '0' flag for non-numeric types.
}
// Parse length and convert the argument to the required type.
using
internal
::
ArgConverter
;
switch
(
*
s
++
)
{
case
'h'
:
if
(
*
s
==
'h'
)
ArgConverter
<
signed
char
>
(
arg
,
*++
s
).
visit
(
arg
);
else
ArgConverter
<
short
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'l'
:
if
(
*
s
==
'l'
)
ArgConverter
<
fmt
::
LongLong
>
(
arg
,
*++
s
).
visit
(
arg
);
else
ArgConverter
<
long
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'j'
:
ArgConverter
<
intmax_t
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'z'
:
ArgConverter
<
std
::
size_t
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
't'
:
ArgConverter
<
std
::
ptrdiff_t
>
(
arg
,
*
s
).
visit
(
arg
);
break
;
case
'L'
:
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break
;
default
:
--
s
;
ArgConverter
<
void
>
(
arg
,
*
s
).
visit
(
arg
);
}
// Parse type.
if
(
!*
s
)
FMT_THROW
(
FormatError
(
"invalid format string"
));
spec
.
type_
=
static_cast
<
char
>
(
*
s
++
);
if
(
spec
.
type_
==
's'
)
{
// set the format type to the default if 's' is specified
spec
.
type_
=
internal
::
DefaultType
().
visit
(
arg
);
}
if
(
arg
.
type
<=
Arg
::
LAST_INTEGER_TYPE
)
{
// Normalize type.
switch
(
spec
.
type_
)
{
case
'i'
:
case
'u'
:
spec
.
type_
=
'd'
;
break
;
case
'c'
:
// TODO: handle wchar_t
internal
::
CharConverter
(
arg
).
visit
(
arg
);
break
;
}
}
start
=
s
;
// Format argument.
AF
(
writer_
,
spec
).
visit
(
arg
);
}
}
write
(
writer_
,
start
,
s
);
start
=
s
;
// Format argument.
AF
(
writer_
,
spec
).
visit
(
arg
);
}
write
(
writer_
,
start
,
s
);
}
}
inline
void
printf
(
Writer
&
w
,
CStringRef
format
,
ArgList
args
)
{
inline
void
printf
(
Writer
&
w
,
CStringRef
format
,
ArgList
args
)
PrintfFormatter
<
char
>
(
args
,
w
).
format
(
format
);
{
PrintfFormatter
<
char
>
(
args
,
w
).
format
(
format
);
}
}
FMT_VARIADIC
(
void
,
printf
,
Writer
&
,
CStringRef
)
FMT_VARIADIC
(
void
,
printf
,
Writer
&
,
CStringRef
)
inline
void
printf
(
WWriter
&
w
,
WCStringRef
format
,
ArgList
args
)
{
inline
void
printf
(
WWriter
&
w
,
WCStringRef
format
,
ArgList
args
)
PrintfFormatter
<
wchar_t
>
(
args
,
w
).
format
(
format
);
{
PrintfFormatter
<
wchar_t
>
(
args
,
w
).
format
(
format
);
}
}
FMT_VARIADIC
(
void
,
printf
,
WWriter
&
,
WCStringRef
)
FMT_VARIADIC
(
void
,
printf
,
WWriter
&
,
WCStringRef
)
...
@@ -538,17 +643,19 @@ FMT_VARIADIC(void, printf, WWriter &, WCStringRef)
...
@@ -538,17 +643,19 @@ FMT_VARIADIC(void, printf, WWriter &, WCStringRef)
std::string message = fmt::sprintf("The answer is %d", 42);
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
\endrst
*/
*/
inline
std
::
string
sprintf
(
CStringRef
format
,
ArgList
args
)
{
inline
std
::
string
sprintf
(
CStringRef
format
,
ArgList
args
)
MemoryWriter
w
;
{
printf
(
w
,
format
,
args
);
MemoryWriter
w
;
return
w
.
str
();
printf
(
w
,
format
,
args
);
return
w
.
str
();
}
}
FMT_VARIADIC
(
std
::
string
,
sprintf
,
CStringRef
)
FMT_VARIADIC
(
std
::
string
,
sprintf
,
CStringRef
)
inline
std
::
wstring
sprintf
(
WCStringRef
format
,
ArgList
args
)
{
inline
std
::
wstring
sprintf
(
WCStringRef
format
,
ArgList
args
)
WMemoryWriter
w
;
{
printf
(
w
,
format
,
args
);
WMemoryWriter
w
;
return
w
.
str
();
printf
(
w
,
format
,
args
);
return
w
.
str
();
}
}
FMT_VARIADIC_W
(
std
::
wstring
,
sprintf
,
WCStringRef
)
FMT_VARIADIC_W
(
std
::
wstring
,
sprintf
,
WCStringRef
)
...
@@ -573,8 +680,9 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
...
@@ -573,8 +680,9 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
fmt::printf("Elapsed time: %.2f seconds", 1.23);
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
\endrst
*/
*/
inline
int
printf
(
CStringRef
format
,
ArgList
args
)
{
inline
int
printf
(
CStringRef
format
,
ArgList
args
)
return
fprintf
(
stdout
,
format
,
args
);
{
return
fprintf
(
stdout
,
format
,
args
);
}
}
FMT_VARIADIC
(
int
,
printf
,
CStringRef
)
FMT_VARIADIC
(
int
,
printf
,
CStringRef
)
...
@@ -587,11 +695,12 @@ FMT_VARIADIC(int, printf, CStringRef)
...
@@ -587,11 +695,12 @@ FMT_VARIADIC(int, printf, CStringRef)
fprintf(cerr, "Don't %s!", "panic");
fprintf(cerr, "Don't %s!", "panic");
\endrst
\endrst
*/
*/
inline
int
fprintf
(
std
::
ostream
&
os
,
CStringRef
format_str
,
ArgList
args
)
{
inline
int
fprintf
(
std
::
ostream
&
os
,
CStringRef
format_str
,
ArgList
args
)
MemoryWriter
w
;
{
printf
(
w
,
format_str
,
args
);
MemoryWriter
w
;
internal
::
write
(
os
,
w
);
printf
(
w
,
format_str
,
args
);
return
static_cast
<
int
>
(
w
.
size
());
internal
::
write
(
os
,
w
);
return
static_cast
<
int
>
(
w
.
size
());
}
}
FMT_VARIADIC
(
int
,
fprintf
,
std
::
ostream
&
,
CStringRef
)
FMT_VARIADIC
(
int
,
fprintf
,
std
::
ostream
&
,
CStringRef
)
}
// namespace fmt
}
// namespace fmt
...
...
include/spdlog/fmt/bundled/time.h
View file @
93be7713
...
@@ -19,120 +19,160 @@
...
@@ -19,120 +19,160 @@
# pragma warning(disable: 4996) // "deprecated" functions
# pragma warning(disable: 4996) // "deprecated" functions
#endif
#endif
namespace
fmt
{
namespace
fmt
{
template
<
typename
ArgFormatter
>
template
<
typename
ArgFormatter
>
void
format_arg
(
BasicFormatter
<
char
,
ArgFormatter
>
&
f
,
void
format_arg
(
BasicFormatter
<
char
,
ArgFormatter
>
&
f
,
const
char
*&
format_str
,
const
std
::
tm
&
tm
)
{
const
char
*&
format_str
,
const
std
::
tm
&
tm
)
if
(
*
format_str
==
':'
)
{
++
format_str
;
if
(
*
format_str
==
':'
)
const
char
*
end
=
format_str
;
++
format_str
;
while
(
*
end
&&
*
end
!=
'}'
)
const
char
*
end
=
format_str
;
++
end
;
while
(
*
end
&&
*
end
!=
'}'
)
if
(
*
end
!=
'}'
)
++
end
;
FMT_THROW
(
FormatError
(
"missing '}' in format string"
));
if
(
*
end
!=
'}'
)
internal
::
MemoryBuffer
<
char
,
internal
::
INLINE_BUFFER_SIZE
>
format
;
FMT_THROW
(
FormatError
(
"missing '}' in format string"
));
format
.
append
(
format_str
,
end
+
1
);
internal
::
MemoryBuffer
<
char
,
internal
::
INLINE_BUFFER_SIZE
>
format
;
format
[
format
.
size
()
-
1
]
=
'\0'
;
format
.
append
(
format_str
,
end
+
1
);
Buffer
<
char
>
&
buffer
=
f
.
writer
().
buffer
();
format
[
format
.
size
()
-
1
]
=
'\0'
;
std
::
size_t
start
=
buffer
.
size
();
Buffer
<
char
>
&
buffer
=
f
.
writer
().
buffer
();
for
(;;)
{
std
::
size_t
start
=
buffer
.
size
();
std
::
size_t
size
=
buffer
.
capacity
()
-
start
;
for
(;;)
std
::
size_t
count
=
std
::
strftime
(
&
buffer
[
start
],
size
,
&
format
[
0
],
&
tm
);
{
if
(
count
!=
0
)
{
std
::
size_t
size
=
buffer
.
capacity
()
-
start
;
buffer
.
resize
(
start
+
count
);
std
::
size_t
count
=
std
::
strftime
(
&
buffer
[
start
],
size
,
&
format
[
0
],
&
tm
);
break
;
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
)
{
format_str
=
end
+
1
;
// 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
;
}
}
namespace
internal
{
namespace
internal
inline
Null
<>
localtime_r
(...)
{
return
Null
<>
();
}
{
inline
Null
<>
localtime_s
(...)
{
return
Null
<>
();
}
inline
Null
<>
localtime_r
(...)
inline
Null
<>
gmtime_r
(...)
{
return
Null
<>
();
}
{
inline
Null
<>
gmtime_s
(...)
{
return
Null
<>
();
}
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
// Thread-safe replacement for std::localtime
inline
std
::
tm
localtime
(
std
::
time_t
time
)
{
inline
std
::
tm
localtime
(
std
::
time_t
time
)
struct
LocalTime
{
{
std
::
time_t
time_
;
struct
LocalTime
std
::
tm
tm_
;
{
std
::
time_t
time_
;
LocalTime
(
std
::
time_t
t
)
:
time_
(
t
)
{}
std
::
tm
tm_
;
bool
run
()
{
LocalTime
(
std
::
time_t
t
)
:
time_
(
t
)
{}
using
namespace
fmt
::
internal
;
return
handle
(
localtime_r
(
&
time_
,
&
tm_
));
bool
run
()
}
{
using
namespace
fmt
::
internal
;
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
FMT_NULL
;
}
return
handle
(
localtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
internal
::
Null
<>
)
{
using
namespace
fmt
::
internal
;
bool
handle
(
std
::
tm
*
tm
)
return
fallback
(
localtime_s
(
&
tm_
,
&
time_
));
{
}
return
tm
!=
FMT_NULL
;
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
bool
handle
(
internal
::
Null
<>
)
bool
fallback
(
internal
::
Null
<>
)
{
{
using
namespace
fmt
::
internal
;
using
namespace
fmt
::
internal
;
std
::
tm
*
tm
=
std
::
localtime
(
&
time_
);
return
fallback
(
localtime_s
(
&
tm_
,
&
time_
));
if
(
tm
)
tm_
=
*
tm
;
}
return
tm
!=
FMT_NULL
;
}
bool
fallback
(
int
res
)
};
{
LocalTime
lt
(
time
);
return
res
==
0
;
if
(
lt
.
run
())
}
return
lt
.
tm_
;
// Too big time values may be unsupported.
bool
fallback
(
internal
::
Null
<>
)
FMT_THROW
(
fmt
::
FormatError
(
"time_t value out of range"
));
{
return
std
::
tm
();
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
// Thread-safe replacement for std::gmtime
inline
std
::
tm
gmtime
(
std
::
time_t
time
)
{
inline
std
::
tm
gmtime
(
std
::
time_t
time
)
struct
GMTime
{
{
std
::
time_t
time_
;
struct
GMTime
std
::
tm
tm_
;
{
std
::
time_t
time_
;
GMTime
(
std
::
time_t
t
)
:
time_
(
t
)
{}
std
::
tm
tm_
;
bool
run
()
{
GMTime
(
std
::
time_t
t
)
:
time_
(
t
)
{}
using
namespace
fmt
::
internal
;
return
handle
(
gmtime_r
(
&
time_
,
&
tm_
));
bool
run
()
}
{
using
namespace
fmt
::
internal
;
bool
handle
(
std
::
tm
*
tm
)
{
return
tm
!=
FMT_NULL
;
}
return
handle
(
gmtime_r
(
&
time_
,
&
tm_
));
}
bool
handle
(
internal
::
Null
<>
)
{
using
namespace
fmt
::
internal
;
bool
handle
(
std
::
tm
*
tm
)
return
fallback
(
gmtime_s
(
&
tm_
,
&
time_
));
{
}
return
tm
!=
FMT_NULL
;
}
bool
fallback
(
int
res
)
{
return
res
==
0
;
}
bool
handle
(
internal
::
Null
<>
)
bool
fallback
(
internal
::
Null
<>
)
{
{
std
::
tm
*
tm
=
std
::
gmtime
(
&
time_
);
using
namespace
fmt
::
internal
;
if
(
tm
!=
FMT_NULL
)
tm_
=
*
tm
;
return
fallback
(
gmtime_s
(
&
tm_
,
&
time_
));
return
tm
!=
FMT_NULL
;
}
}
};
bool
fallback
(
int
res
)
GMTime
gt
(
time
);
{
if
(
gt
.
run
())
return
res
==
0
;
return
gt
.
tm_
;
}
// Too big time values may be unsupported.
FMT_THROW
(
fmt
::
FormatError
(
"time_t value out of range"
));
bool
fallback
(
internal
::
Null
<>
)
return
std
::
tm
();
{
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
}
//namespace fmt
...
...
include/spdlog/spdlog.h
View file @
93be7713
...
@@ -169,11 +169,11 @@ void drop_all();
...
@@ -169,11 +169,11 @@ void drop_all();
#define SPDLOG_STR_H(x) #x
#define SPDLOG_STR_H(x) #x
#define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)
#define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)
#ifdef _MSC_VER
#ifdef _MSC_VER
#define SPDLOG_TRACE(logger, ...) logger->trace("[ " __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__)
#define SPDLOG_TRACE_IF(logger, flag, ...) logger->trace_if(flag, "[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__)
#else
#else
#define SPDLOG_TRACE(logger, ...) logger->trace("[ " __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__)
#define SPDLOG_TRACE_IF(logger, flag, ...) logger->trace_if(flag, "[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__)
#endif
#endif
#else
#else
#define SPDLOG_TRACE(logger, ...)
#define SPDLOG_TRACE(logger, ...)
...
...
tests/includes.h
View file @
93be7713
...
@@ -10,8 +10,8 @@
...
@@ -10,8 +10,8 @@
#include "catch.hpp"
#include "catch.hpp"
#include "utils.h"
#include "utils.h"
#define SPDLOG_TRACE_ON
#define SPDLOG_TRACE_ON
#define SPDLOG_DEBUG_ON
#define SPDLOG_DEBUG_ON
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/null_sink.h"
...
...
tests/test_macros.cpp
View file @
93be7713
...
@@ -6,45 +6,45 @@
...
@@ -6,45 +6,45 @@
TEST_CASE
(
"debug and trace w/o format string"
,
"[macros]]"
)
TEST_CASE
(
"debug and trace w/o format string"
,
"[macros]]"
)
{
{
prepare_logdir
();
prepare_logdir
();
std
::
string
filename
=
"logs/simple_log"
;
std
::
string
filename
=
"logs/simple_log"
;
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
simple_file_sink_mt
>
(
"logger"
,
filename
);
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
simple_file_sink_mt
>
(
"logger"
,
filename
);
logger
->
set_pattern
(
"%v"
);
logger
->
set_pattern
(
"%v"
);
logger
->
set_level
(
spdlog
::
level
::
trace
);
logger
->
set_level
(
spdlog
::
level
::
trace
);
SPDLOG_TRACE
(
logger
,
"Test message 1"
);
SPDLOG_TRACE
(
logger
,
"Test message 1"
);
//SPDLOG_DEBUG(logger, "Test message 2");
//SPDLOG_DEBUG(logger, "Test message 2");
SPDLOG_DEBUG
(
logger
,
"Test message 2"
);
SPDLOG_DEBUG
(
logger
,
"Test message 2"
);
logger
->
flush
();
logger
->
flush
();
REQUIRE
(
ends_with
(
file_contents
(
filename
),
"Test message 2
\n
"
));
REQUIRE
(
ends_with
(
file_contents
(
filename
),
"Test message 2
\n
"
));
REQUIRE
(
count_lines
(
filename
)
==
2
);
REQUIRE
(
count_lines
(
filename
)
==
2
);
}
}
TEST_CASE
(
"debug and trace with format strings"
,
"[macros]]"
)
TEST_CASE
(
"debug and trace with format strings"
,
"[macros]]"
)
{
{
prepare_logdir
();
prepare_logdir
();
std
::
string
filename
=
"logs/simple_log"
;
std
::
string
filename
=
"logs/simple_log"
;
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
simple_file_sink_mt
>
(
"logger"
,
filename
);
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
simple_file_sink_mt
>
(
"logger"
,
filename
);
logger
->
set_pattern
(
"%v"
);
logger
->
set_pattern
(
"%v"
);
logger
->
set_level
(
spdlog
::
level
::
trace
);
logger
->
set_level
(
spdlog
::
level
::
trace
);
#if !defined(SPDLOG_FMT_PRINTF)
#if !defined(SPDLOG_FMT_PRINTF)
SPDLOG_TRACE
(
logger
,
"Test message {}"
,
1
);
SPDLOG_TRACE
(
logger
,
"Test message {}"
,
1
);
//SPDLOG_DEBUG(logger, "Test message 2");
//SPDLOG_DEBUG(logger, "Test message 2");
SPDLOG_DEBUG
(
logger
,
"Test message {}"
,
222
);
SPDLOG_DEBUG
(
logger
,
"Test message {}"
,
222
);
#else
#else
SPDLOG_TRACE
(
logger
,
"Test message %d"
,
1
);
SPDLOG_TRACE
(
logger
,
"Test message %d"
,
1
);
//SPDLOG_DEBUG(logger, "Test message 2");
//SPDLOG_DEBUG(logger, "Test message 2");
SPDLOG_DEBUG
(
logger
,
"Test message %d"
,
222
);
SPDLOG_DEBUG
(
logger
,
"Test message %d"
,
222
);
#endif
#endif
logger
->
flush
();
logger
->
flush
();
REQUIRE
(
ends_with
(
file_contents
(
filename
),
"Test message 222
\n
"
));
REQUIRE
(
ends_with
(
file_contents
(
filename
),
"Test message 222
\n
"
));
REQUIRE
(
count_lines
(
filename
)
==
2
);
REQUIRE
(
count_lines
(
filename
)
==
2
);
}
}
tests/utils.cpp
View file @
93be7713
...
@@ -49,8 +49,8 @@ std::size_t get_filesize(const std::string& filename)
...
@@ -49,8 +49,8 @@ std::size_t get_filesize(const std::string& filename)
// source: https://stackoverflow.com/a/2072890/192001
// source: https://stackoverflow.com/a/2072890/192001
bool
ends_with
(
std
::
string
const
&
value
,
std
::
string
const
&
ending
)
bool
ends_with
(
std
::
string
const
&
value
,
std
::
string
const
&
ending
)
{
{
if
(
ending
.
size
()
>
value
.
size
())
return
false
;
if
(
ending
.
size
()
>
value
.
size
())
return
false
;
return
std
::
equal
(
ending
.
rbegin
(),
ending
.
rend
(),
value
.
rbegin
());
return
std
::
equal
(
ending
.
rbegin
(),
ending
.
rend
(),
value
.
rbegin
());
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment