All files under the same project; Renamed TR5Main to TombEngine; Cleaned repository;

This commit is contained in:
MontyTRC89 2022-05-08 06:52:04 +02:00
parent 3e02f1828b
commit f1e7c6fbfc
907 changed files with 141 additions and 1778 deletions

1144
Libs/bass/bass.h Normal file

File diff suppressed because it is too large Load diff

BIN
Libs/bass/bass.lib Normal file

Binary file not shown.

443
Libs/bass/bass_fx.h Normal file
View file

@ -0,0 +1,443 @@
/*===========================================================================
BASS_FX 2.4 - Copyright (c) 2002-2018 (: JOBnik! :) [Arthur Aminov, ISRAEL]
[http://www.jobnik.org]
bugs/suggestions/questions:
forum : http://www.un4seen.com/forum/?board=1
http://www.jobnik.org/forums
e-mail : bass_fx@jobnik.org
--------------------------------------------------
NOTE: This header will work only with BASS_FX version 2.4.12
Check www.un4seen.com or www.jobnik.org for any later versions.
* Requires BASS 2.4 (available at http://www.un4seen.com)
===========================================================================*/
#ifndef BASS_FX_H
#define BASS_FX_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BASS_FXDEF
#define BASS_FXDEF(f) WINAPI f
#endif
// BASS_CHANNELINFO types
#define BASS_CTYPE_STREAM_TEMPO 0x1f200
#define BASS_CTYPE_STREAM_REVERSE 0x1f201
// Tempo / Reverse / BPM / Beat flag
#define BASS_FX_FREESOURCE 0x10000 // Free the source handle as well?
// BASS_FX Version
DWORD BASS_FXDEF(BASS_FX_GetVersion)();
/*===========================================================================
DSP (Digital Signal Processing)
===========================================================================*/
/*
Multi-channel order of each channel is as follows:
3 channels left-front, right-front, center.
4 channels left-front, right-front, left-rear/side, right-rear/side.
5 channels left-front, right-front, center, left-rear/side, right-rear/side.
6 channels (5.1) left-front, right-front, center, LFE, left-rear/side, right-rear/side.
8 channels (7.1) left-front, right-front, center, LFE, left-rear/side, right-rear/side, left-rear center, right-rear center.
*/
// DSP channels flags
#define BASS_BFX_CHANALL -1 // all channels at once (as by default)
#define BASS_BFX_CHANNONE 0 // disable an effect for all channels
#define BASS_BFX_CHAN1 1 // left-front channel
#define BASS_BFX_CHAN2 2 // right-front channel
#define BASS_BFX_CHAN3 4 // see above info
#define BASS_BFX_CHAN4 8 // see above info
#define BASS_BFX_CHAN5 16 // see above info
#define BASS_BFX_CHAN6 32 // see above info
#define BASS_BFX_CHAN7 64 // see above info
#define BASS_BFX_CHAN8 128 // see above info
// if you have more than 8 channels (7.1), use this macro
#define BASS_BFX_CHANNEL_N(n) (1<<((n)-1))
// DSP effects
enum {
BASS_FX_BFX_ROTATE = 0x10000, // A channels volume ping-pong / multi channel
BASS_FX_BFX_ECHO, // Echo / 2 channels max (deprecated)
BASS_FX_BFX_FLANGER, // Flanger / multi channel (deprecated)
BASS_FX_BFX_VOLUME, // Volume / multi channel
BASS_FX_BFX_PEAKEQ, // Peaking Equalizer / multi channel
BASS_FX_BFX_REVERB, // Reverb / 2 channels max (deprecated)
BASS_FX_BFX_LPF, // Low Pass Filter 24dB / multi channel (deprecated)
BASS_FX_BFX_MIX, // Swap, remap and mix channels / multi channel
BASS_FX_BFX_DAMP, // Dynamic Amplification / multi channel
BASS_FX_BFX_AUTOWAH, // Auto Wah / multi channel
BASS_FX_BFX_ECHO2, // Echo 2 / multi channel (deprecated)
BASS_FX_BFX_PHASER, // Phaser / multi channel
BASS_FX_BFX_ECHO3, // Echo 3 / multi channel (deprecated)
BASS_FX_BFX_CHORUS, // Chorus/Flanger / multi channel
BASS_FX_BFX_APF, // All Pass Filter / multi channel (deprecated)
BASS_FX_BFX_COMPRESSOR, // Compressor / multi channel (deprecated)
BASS_FX_BFX_DISTORTION, // Distortion / multi channel
BASS_FX_BFX_COMPRESSOR2, // Compressor 2 / multi channel
BASS_FX_BFX_VOLUME_ENV, // Volume envelope / multi channel
BASS_FX_BFX_BQF, // BiQuad filters / multi channel
BASS_FX_BFX_ECHO4, // Echo 4 / multi channel
BASS_FX_BFX_PITCHSHIFT, // Pitch shift using FFT / multi channel (not available on mobile)
BASS_FX_BFX_FREEVERB // Reverb using "Freeverb" algo / multi channel
};
/*
Deprecated effects in 2.4.10 version:
------------------------------------
BASS_FX_BFX_ECHO -> use BASS_FX_BFX_ECHO4
BASS_FX_BFX_ECHO2 -> use BASS_FX_BFX_ECHO4
BASS_FX_BFX_ECHO3 -> use BASS_FX_BFX_ECHO4
BASS_FX_BFX_REVERB -> use BASS_FX_BFX_FREEVERB
BASS_FX_BFX_FLANGER -> use BASS_FX_BFX_CHORUS
BASS_FX_BFX_COMPRESSOR -> use BASS_FX_BFX_COMPRESSOR2
BASS_FX_BFX_APF -> use BASS_FX_BFX_BQF with BASS_BFX_BQF_ALLPASS filter
BASS_FX_BFX_LPF -> use 2x BASS_FX_BFX_BQF with BASS_BFX_BQF_LOWPASS filter and appropriate fQ values
*/
// Rotate
typedef struct {
float fRate; // rotation rate/speed in Hz (A negative rate can be used for reverse direction)
int lChannel; // BASS_BFX_CHANxxx flag/s (supported only even number of channels)
} BASS_BFX_ROTATE;
// Echo (deprecated)
typedef struct {
float fLevel; // [0....1....n] linear
int lDelay; // [1200..30000]
} BASS_BFX_ECHO;
// Flanger (deprecated)
typedef struct {
float fWetDry; // [0....1....n] linear
float fSpeed; // [0......0.09]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_FLANGER;
// Volume
typedef struct {
int lChannel; // BASS_BFX_CHANxxx flag/s or 0 for global volume control
float fVolume; // [0....1....n] linear
} BASS_BFX_VOLUME;
// Peaking Equalizer
typedef struct {
int lBand; // [0...............n] more bands means more memory & cpu usage
float fBandwidth; // [0.1...........<10] in octaves - fQ is not in use (Bandwidth has a priority over fQ)
float fQ; // [0...............1] the EE kinda definition (linear) (if Bandwidth is not in use)
float fCenter; // [1Hz..<info.freq/2] in Hz
float fGain; // [-15dB...0...+15dB] in dB (can be above/below these limits)
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_PEAKEQ;
// Reverb (deprecated)
typedef struct {
float fLevel; // [0....1....n] linear
int lDelay; // [1200..10000]
} BASS_BFX_REVERB;
// Low Pass Filter (deprecated)
typedef struct {
float fResonance; // [0.01...........10]
float fCutOffFreq; // [1Hz...info.freq/2] cutoff frequency
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_LPF;
// Swap, remap and mix
typedef struct {
const int *lChannel; // an array of channels to mix using BASS_BFX_CHANxxx flag/s (lChannel[0] is left channel...)
} BASS_BFX_MIX;
// Dynamic Amplification
typedef struct {
float fTarget; // target volume level [0<......1] linear
float fQuiet; // quiet volume level [0.......1] linear
float fRate; // amp adjustment rate [0.......1] linear
float fGain; // amplification level [0...1...n] linear
float fDelay; // delay in seconds before increasing level [0.......n] linear
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_DAMP;
// Auto Wah
typedef struct {
float fDryMix; // dry (unaffected) signal mix [-2......2]
float fWetMix; // wet (affected) signal mix [-2......2]
float fFeedback; // output signal to feed back into input [-1......1]
float fRate; // rate of sweep in cycles per second [0<....<10]
float fRange; // sweep range in octaves [0<....<10]
float fFreq; // base frequency of sweep Hz [0<...1000]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_AUTOWAH;
// Echo 2 (deprecated)
typedef struct {
float fDryMix; // dry (unaffected) signal mix [-2......2]
float fWetMix; // wet (affected) signal mix [-2......2]
float fFeedback; // output signal to feed back into input [-1......1]
float fDelay; // delay sec [0<......n]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_ECHO2;
// Phaser
typedef struct {
float fDryMix; // dry (unaffected) signal mix [-2......2]
float fWetMix; // wet (affected) signal mix [-2......2]
float fFeedback; // output signal to feed back into input [-1......1]
float fRate; // rate of sweep in cycles per second [0<....<10]
float fRange; // sweep range in octaves [0<....<10]
float fFreq; // base frequency of sweep [0<...1000]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_PHASER;
// Echo 3 (deprecated)
typedef struct {
float fDryMix; // dry (unaffected) signal mix [-2......2]
float fWetMix; // wet (affected) signal mix [-2......2]
float fDelay; // delay sec [0<......n]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_ECHO3;
// Chorus/Flanger
typedef struct {
float fDryMix; // dry (unaffected) signal mix [-2......2]
float fWetMix; // wet (affected) signal mix [-2......2]
float fFeedback; // output signal to feed back into input [-1......1]
float fMinSweep; // minimal delay ms [0<...6000]
float fMaxSweep; // maximum delay ms [0<...6000]
float fRate; // rate ms/s [0<...1000]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_CHORUS;
// All Pass Filter (deprecated)
typedef struct {
float fGain; // reverberation time [-1=<..<=1]
float fDelay; // delay sec [0<....<=n]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_APF;
// Compressor (deprecated)
typedef struct {
float fThreshold; // compressor threshold [0<=...<=1]
float fAttacktime; // attack time ms [0<.<=1000]
float fReleasetime; // release time ms [0<.<=5000]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_COMPRESSOR;
// Distortion
typedef struct {
float fDrive; // distortion drive [0<=...<=5]
float fDryMix; // dry (unaffected) signal mix [-5<=..<=5]
float fWetMix; // wet (affected) signal mix [-5<=..<=5]
float fFeedback; // output signal to feed back into input [-1<=..<=1]
float fVolume; // distortion volume [0=<...<=2]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_DISTORTION;
// Compressor 2
typedef struct {
float fGain; // output gain of signal after compression [-60....60] in dB
float fThreshold; // point at which compression begins [-60.....0] in dB
float fRatio; // compression ratio [1.......n]
float fAttack; // attack time in ms [0.01.1000]
float fRelease; // release time in ms [0.01.5000]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_COMPRESSOR2;
// Volume envelope
typedef struct {
int lChannel; // BASS_BFX_CHANxxx flag/s
int lNodeCount; // number of nodes
const struct BASS_BFX_ENV_NODE *pNodes; // the nodes
BOOL bFollow; // follow source position
} BASS_BFX_VOLUME_ENV;
#pragma pack(push,4)
typedef struct BASS_BFX_ENV_NODE {
double pos; // node position in seconds (1st envelope node must be at position 0)
float val; // node value
} BASS_BFX_ENV_NODE;
#pragma pack(pop)
// BiQuad Filters
enum {
BASS_BFX_BQF_LOWPASS,
BASS_BFX_BQF_HIGHPASS,
BASS_BFX_BQF_BANDPASS, // constant 0 dB peak gain
BASS_BFX_BQF_BANDPASS_Q, // constant skirt gain, peak gain = Q
BASS_BFX_BQF_NOTCH,
BASS_BFX_BQF_ALLPASS,
BASS_BFX_BQF_PEAKINGEQ,
BASS_BFX_BQF_LOWSHELF,
BASS_BFX_BQF_HIGHSHELF
};
typedef struct {
int lFilter; // BASS_BFX_BQF_xxx filter types
float fCenter; // [1Hz..<info.freq/2] Cutoff (central) frequency in Hz
float fGain; // [-15dB...0...+15dB] Used only for PEAKINGEQ and Shelving filters in dB (can be above/below these limits)
float fBandwidth; // [0.1...........<10] Bandwidth in octaves (fQ is not in use (fBandwidth has a priority over fQ))
// (between -3 dB frequencies for BANDPASS and NOTCH or between midpoint
// (fGgain/2) gain frequencies for PEAKINGEQ)
float fQ; // [0.1.............1] The EE kinda definition (linear) (if fBandwidth is not in use)
float fS; // [0.1.............1] A "shelf slope" parameter (linear) (used only with Shelving filters)
// when fS = 1, the shelf slope is as steep as you can get it and remain monotonically
// increasing or decreasing gain with frequency.
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_BQF;
// Echo 4
typedef struct {
float fDryMix; // dry (unaffected) signal mix [-2.......2]
float fWetMix; // wet (affected) signal mix [-2.......2]
float fFeedback; // output signal to feed back into input [-1.......1]
float fDelay; // delay sec [0<.......n]
BOOL bStereo; // echo adjoining channels to each other [TRUE/FALSE]
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_ECHO4;
// Pitch shift (not available on mobile)
typedef struct {
float fPitchShift; // A factor value which is between 0.5 (one octave down) and 2 (one octave up) (1 won't change the pitch) [1 default]
// (fSemitones is not in use, fPitchShift has a priority over fSemitones)
float fSemitones; // Semitones (0 won't change the pitch) [0 default]
long lFFTsize; // Defines the FFT frame size used for the processing. Typical values are 1024, 2048 and 4096 [2048 default]
// It may be any value <= 8192 but it MUST be a power of 2
long lOsamp; // Is the STFT oversampling factor which also determines the overlap between adjacent STFT frames [8 default]
// It should at least be 4 for moderate scaling ratios. A value of 32 is recommended for best quality (better quality = higher CPU usage)
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_PITCHSHIFT;
// Freeverb
#define BASS_BFX_FREEVERB_MODE_FREEZE 1
typedef struct {
float fDryMix; // dry (unaffected) signal mix [0........1], def. 0
float fWetMix; // wet (affected) signal mix [0........3], def. 1.0f
float fRoomSize; // room size [0........1], def. 0.5f
float fDamp; // damping [0........1], def. 0.5f
float fWidth; // stereo width [0........1], def. 1
DWORD lMode; // 0 or BASS_BFX_FREEVERB_MODE_FREEZE, def. 0 (no freeze)
int lChannel; // BASS_BFX_CHANxxx flag/s
} BASS_BFX_FREEVERB;
/*===========================================================================
set dsp fx - BASS_ChannelSetFX
remove dsp fx - BASS_ChannelRemoveFX
set parameters - BASS_FXSetParameters
retrieve parameters - BASS_FXGetParameters
reset the state - BASS_FXReset
===========================================================================*/
/*===========================================================================
Tempo, Pitch scaling and Sample rate changers
===========================================================================*/
// NOTE: Enable Tempo supported flags in BASS_FX_TempoCreate and the others to source handle.
// tempo attributes (BASS_ChannelSet/GetAttribute)
enum {
BASS_ATTRIB_TEMPO = 0x10000,
BASS_ATTRIB_TEMPO_PITCH,
BASS_ATTRIB_TEMPO_FREQ
};
// tempo attributes options
enum {
BASS_ATTRIB_TEMPO_OPTION_USE_AA_FILTER = 0x10010, // TRUE (default) / FALSE (default for multi-channel on mobile devices for lower CPU usage)
BASS_ATTRIB_TEMPO_OPTION_AA_FILTER_LENGTH, // 32 default (8 .. 128 taps)
BASS_ATTRIB_TEMPO_OPTION_USE_QUICKALGO, // TRUE (default on mobile devices for lower CPU usage) / FALSE (default)
BASS_ATTRIB_TEMPO_OPTION_SEQUENCE_MS, // 82 default, 0 = automatic
BASS_ATTRIB_TEMPO_OPTION_SEEKWINDOW_MS, // 28 default, 0 = automatic
BASS_ATTRIB_TEMPO_OPTION_OVERLAP_MS, // 8 default
BASS_ATTRIB_TEMPO_OPTION_PREVENT_CLICK // TRUE / FALSE (default)
};
// tempo algorithm flags
#define BASS_FX_TEMPO_ALGO_LINEAR 0x200
#define BASS_FX_TEMPO_ALGO_CUBIC 0x400 // default
#define BASS_FX_TEMPO_ALGO_SHANNON 0x800
HSTREAM BASS_FXDEF(BASS_FX_TempoCreate)(DWORD chan, DWORD flags);
DWORD BASS_FXDEF(BASS_FX_TempoGetSource)(HSTREAM chan);
float BASS_FXDEF(BASS_FX_TempoGetRateRatio)(HSTREAM chan);
/*===========================================================================
Reverse playback
===========================================================================*/
// NOTES: 1. MODs won't load without BASS_MUSIC_PRESCAN flag.
// 2. Enable Reverse supported flags in BASS_FX_ReverseCreate and the others to source handle.
// reverse attribute (BASS_ChannelSet/GetAttribute)
#define BASS_ATTRIB_REVERSE_DIR 0x11000
// playback directions
#define BASS_FX_RVS_REVERSE -1
#define BASS_FX_RVS_FORWARD 1
HSTREAM BASS_FXDEF(BASS_FX_ReverseCreate)(DWORD chan, float dec_block, DWORD flags);
DWORD BASS_FXDEF(BASS_FX_ReverseGetSource)(HSTREAM chan);
/*===========================================================================
BPM (Beats Per Minute)
===========================================================================*/
// bpm flags
#define BASS_FX_BPM_BKGRND 1 // if in use, then you can do other processing while detection's in progress. Available only in Windows platforms (BPM/Beat)
#define BASS_FX_BPM_MULT2 2 // if in use, then will auto multiply bpm by 2 (if BPM < minBPM*2)
// translation options (deprecated)
enum {
BASS_FX_BPM_TRAN_X2, // multiply the original BPM value by 2 (may be called only once & will change the original BPM as well!)
BASS_FX_BPM_TRAN_2FREQ, // BPM value to Frequency
BASS_FX_BPM_TRAN_FREQ2, // Frequency to BPM value
BASS_FX_BPM_TRAN_2PERCENT, // BPM value to Percents
BASS_FX_BPM_TRAN_PERCENT2 // Percents to BPM value
};
typedef void (CALLBACK BPMPROC)(DWORD chan, float bpm, void *user);
typedef void (CALLBACK BPMPROGRESSPROC)(DWORD chan, float percent, void *user);
typedef BPMPROGRESSPROC BPMPROCESSPROC; // back-compatibility
float BASS_FXDEF(BASS_FX_BPM_DecodeGet)(DWORD chan, double startSec, double endSec, DWORD minMaxBPM, DWORD flags, BPMPROGRESSPROC *proc, void *user);
BOOL BASS_FXDEF(BASS_FX_BPM_CallbackSet)(DWORD handle, BPMPROC *proc, double period, DWORD minMaxBPM, DWORD flags, void *user);
BOOL BASS_FXDEF(BASS_FX_BPM_CallbackReset)(DWORD handle);
float BASS_FXDEF(BASS_FX_BPM_Translate)(DWORD handle, float val2tran, DWORD trans); // deprecated
BOOL BASS_FXDEF(BASS_FX_BPM_Free)(DWORD handle);
/*===========================================================================
Beat position trigger
===========================================================================*/
typedef void (CALLBACK BPMBEATPROC)(DWORD chan, double beatpos, void *user);
BOOL BASS_FXDEF(BASS_FX_BPM_BeatCallbackSet)(DWORD handle, BPMBEATPROC *proc, void *user);
BOOL BASS_FXDEF(BASS_FX_BPM_BeatCallbackReset)(DWORD handle);
BOOL BASS_FXDEF(BASS_FX_BPM_BeatDecodeGet)(DWORD chan, double startSec, double endSec, DWORD flags, BPMBEATPROC *proc, void *user);
BOOL BASS_FXDEF(BASS_FX_BPM_BeatSetParameters)(DWORD handle, float bandwidth, float centerfreq, float beat_rtime);
BOOL BASS_FXDEF(BASS_FX_BPM_BeatGetParameters)(DWORD handle, float *bandwidth, float *centerfreq, float *beat_rtime);
BOOL BASS_FXDEF(BASS_FX_BPM_BeatFree)(DWORD handle);
/*===========================================================================
Macros
===========================================================================*/
// translate linear level to logarithmic dB
#define BASS_BFX_Linear2dB(level) (20*log10(level))
// translate logarithmic dB level to linear
#define BASS_BFX_dB2Linear(dB) pow(10,(dB)/20)
#ifdef __cplusplus
}
#endif
#endif

BIN
Libs/bass/bass_fx.lib Normal file

Binary file not shown.

114
Libs/bass/bassmix.h Normal file
View file

@ -0,0 +1,114 @@
/*
BASSmix 2.4 C/C++ header file
Copyright (c) 2005-2017 Un4seen Developments Ltd.
See the BASSMIX.CHM file for more detailed documentation
*/
#ifndef BASSMIX_H
#define BASSMIX_H
#include "bass.h"
#if BASSVERSION!=0x204
#error conflicting BASS and BASSmix versions
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef BASSMIXDEF
#define BASSMIXDEF(f) WINAPI f
#endif
// additional BASS_SetConfig option
#define BASS_CONFIG_MIXER_BUFFER 0x10601
#define BASS_CONFIG_MIXER_POSEX 0x10602
#define BASS_CONFIG_SPLIT_BUFFER 0x10610
// BASS_Mixer_StreamCreate flags
#define BASS_MIXER_END 0x10000 // end the stream when there are no sources
#define BASS_MIXER_NONSTOP 0x20000 // don't stall when there are no sources
#define BASS_MIXER_RESUME 0x1000 // resume stalled immediately upon new/unpaused source
#define BASS_MIXER_POSEX 0x2000 // enable BASS_Mixer_ChannelGetPositionEx support
// source flags
#define BASS_MIXER_BUFFER 0x2000 // buffer data for BASS_Mixer_ChannelGetData/Level
#define BASS_MIXER_LIMIT 0x4000 // limit mixer processing to the amount available from this source
#define BASS_MIXER_MATRIX 0x10000 // matrix mixing
#define BASS_MIXER_PAUSE 0x20000 // don't process the source
#define BASS_MIXER_DOWNMIX 0x400000 // downmix to stereo/mono
#define BASS_MIXER_NORAMPIN 0x800000 // don't ramp-in the start
// mixer attributes
#define BASS_ATTRIB_MIXER_LATENCY 0x15000
// splitter flags
#define BASS_SPLIT_SLAVE 0x1000 // only read buffered data
#define BASS_SPLIT_POS 0x2000
// splitter attributes
#define BASS_ATTRIB_SPLIT_ASYNCBUFFER 0x15010
#define BASS_ATTRIB_SPLIT_ASYNCPERIOD 0x15011
// envelope node
typedef struct {
QWORD pos;
float value;
} BASS_MIXER_NODE;
// envelope types
#define BASS_MIXER_ENV_FREQ 1
#define BASS_MIXER_ENV_VOL 2
#define BASS_MIXER_ENV_PAN 3
#define BASS_MIXER_ENV_LOOP 0x10000 // flag: loop
// additional sync type
#define BASS_SYNC_MIXER_ENVELOPE 0x10200
#define BASS_SYNC_MIXER_ENVELOPE_NODE 0x10201
// additional BASS_Mixer_ChannelSetPosition flag
#define BASS_POS_MIXER_RESET 0x10000 // flag: clear mixer's playback buffer
// BASS_CHANNELINFO type
#define BASS_CTYPE_STREAM_MIXER 0x10800
#define BASS_CTYPE_STREAM_SPLIT 0x10801
DWORD BASSMIXDEF(BASS_Mixer_GetVersion)();
HSTREAM BASSMIXDEF(BASS_Mixer_StreamCreate)(DWORD freq, DWORD chans, DWORD flags);
BOOL BASSMIXDEF(BASS_Mixer_StreamAddChannel)(HSTREAM handle, DWORD channel, DWORD flags);
BOOL BASSMIXDEF(BASS_Mixer_StreamAddChannelEx)(HSTREAM handle, DWORD channel, DWORD flags, QWORD start, QWORD length);
DWORD BASSMIXDEF(BASS_Mixer_StreamGetChannels)(HSTREAM handle, DWORD *channels, DWORD count);
HSTREAM BASSMIXDEF(BASS_Mixer_ChannelGetMixer)(DWORD handle);
DWORD BASSMIXDEF(BASS_Mixer_ChannelFlags)(DWORD handle, DWORD flags, DWORD mask);
BOOL BASSMIXDEF(BASS_Mixer_ChannelRemove)(DWORD handle);
BOOL BASSMIXDEF(BASS_Mixer_ChannelSetPosition)(DWORD handle, QWORD pos, DWORD mode);
QWORD BASSMIXDEF(BASS_Mixer_ChannelGetPosition)(DWORD handle, DWORD mode);
QWORD BASSMIXDEF(BASS_Mixer_ChannelGetPositionEx)(DWORD channel, DWORD mode, DWORD delay);
DWORD BASSMIXDEF(BASS_Mixer_ChannelGetLevel)(DWORD handle);
BOOL BASSMIXDEF(BASS_Mixer_ChannelGetLevelEx)(DWORD handle, float *levels, float length, DWORD flags);
DWORD BASSMIXDEF(BASS_Mixer_ChannelGetData)(DWORD handle, void *buffer, DWORD length);
HSYNC BASSMIXDEF(BASS_Mixer_ChannelSetSync)(DWORD handle, DWORD type, QWORD param, SYNCPROC *proc, void *user);
BOOL BASSMIXDEF(BASS_Mixer_ChannelRemoveSync)(DWORD channel, HSYNC sync);
BOOL BASSMIXDEF(BASS_Mixer_ChannelSetMatrix)(DWORD handle, const void *matrix);
BOOL BASSMIXDEF(BASS_Mixer_ChannelSetMatrixEx)(DWORD handle, const void *matrix, float time);
BOOL BASSMIXDEF(BASS_Mixer_ChannelGetMatrix)(DWORD handle, void *matrix);
BOOL BASSMIXDEF(BASS_Mixer_ChannelSetEnvelope)(DWORD handle, DWORD type, const BASS_MIXER_NODE *nodes, DWORD count);
BOOL BASSMIXDEF(BASS_Mixer_ChannelSetEnvelopePos)(DWORD handle, DWORD type, QWORD pos);
QWORD BASSMIXDEF(BASS_Mixer_ChannelGetEnvelopePos)(DWORD handle, DWORD type, float *value);
HSTREAM BASSMIXDEF(BASS_Split_StreamCreate)(DWORD channel, DWORD flags, const int *chanmap);
DWORD BASSMIXDEF(BASS_Split_StreamGetSource)(HSTREAM handle);
DWORD BASSMIXDEF(BASS_Split_StreamGetSplits)(DWORD handle, HSTREAM *splits, DWORD count);
BOOL BASSMIXDEF(BASS_Split_StreamReset)(DWORD handle);
BOOL BASSMIXDEF(BASS_Split_StreamResetEx)(DWORD handle, DWORD offset);
DWORD BASSMIXDEF(BASS_Split_StreamGetAvailable)(DWORD handle);
#ifdef __cplusplus
}
#endif
#endif

BIN
Libs/bass/bassmix.lib Normal file

Binary file not shown.

View file

@ -0,0 +1,574 @@
// From: https://github.com/eteran/cpp-utilities/blob/master/fixed/include/eteran/cpp-utilities/Fixed.h
// See also: http://stackoverflow.com/questions/79677/whats-the-best-way-to-do-fixed-point-math
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Evan Teran
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef FIXED_H_
#define FIXED_H_
#if __cplusplus >= 201402L
#define CONSTEXPR14 constexpr
#else
#define CONSTEXPR14
#endif
#include <ostream>
#include <exception>
#include <cstddef> // for size_t
#include <cstdint>
#include <type_traits>
namespace numeric {
template <size_t I, size_t F>
class Fixed;
namespace detail {
// helper templates to make magic with types :)
// these allow us to determine resonable types from
// a desired size, they also let us infer the next largest type
// from a type which is nice for the division op
template <size_t T>
struct type_from_size {
static constexpr bool is_specialized = false;
};
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__STRICT_ANSI__)
template <>
struct type_from_size<128> {
static constexpr bool is_specialized = true;
static constexpr size_t size = 128;
using value_type = __int128;
using unsigned_type = unsigned __int128;
using signed_type = __int128;
using next_size = type_from_size<256>;
};
#endif
template <>
struct type_from_size<64> {
static constexpr bool is_specialized = true;
static constexpr size_t size = 64;
using value_type = int64_t;
using unsigned_type = std::make_unsigned<value_type>::type;
using signed_type = std::make_signed<value_type>::type;
using next_size = type_from_size<128>;
};
template <>
struct type_from_size<32> {
static constexpr bool is_specialized = true;
static constexpr size_t size = 32;
using value_type = int32_t;
using unsigned_type = std::make_unsigned<value_type>::type;
using signed_type = std::make_signed<value_type>::type;
using next_size = type_from_size<64>;
};
template <>
struct type_from_size<16> {
static constexpr bool is_specialized = true;
static constexpr size_t size = 16;
using value_type = int16_t;
using unsigned_type = std::make_unsigned<value_type>::type;
using signed_type = std::make_signed<value_type>::type;
using next_size = type_from_size<32>;
};
template <>
struct type_from_size<8> {
static constexpr bool is_specialized = true;
static constexpr size_t size = 8;
using value_type = int8_t;
using unsigned_type = std::make_unsigned<value_type>::type;
using signed_type = std::make_signed<value_type>::type;
using next_size = type_from_size<16>;
};
// this is to assist in adding support for non-native base
// types (for adding big-int support), this should be fine
// unless your bit-int class doesn't nicely support casting
template <class B, class N>
constexpr B next_to_base(N rhs) {
return static_cast<B>(rhs);
}
struct divide_by_zero : std::exception {
};
template <size_t I, size_t F>
CONSTEXPR14 Fixed<I, F> divide(Fixed<I, F> numerator, Fixed<I, F> denominator, Fixed<I, F>& remainder, typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type * = nullptr) {
using next_type = typename Fixed<I, F>::next_type;
using base_type = typename Fixed<I, F>::base_type;
constexpr size_t fractional_bits = Fixed<I, F>::fractional_bits;
next_type t(numerator.to_raw());
t <<= fractional_bits;
Fixed<I, F> quotient;
quotient = Fixed<I, F>::from_base(next_to_base<base_type>(t / denominator.to_raw()));
remainder = Fixed<I, F>::from_base(next_to_base<base_type>(t % denominator.to_raw()));
return quotient;
}
template <size_t I, size_t F>
CONSTEXPR14 Fixed<I, F> divide(Fixed<I, F> numerator, Fixed<I, F> denominator, Fixed<I, F> & remainder, typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type * = nullptr) {
// NOTE(eteran): division is broken for large types :-(
// especially when dealing with negative quantities
using base_type = typename Fixed<I, F>::base_type;
using unsigned_type = typename Fixed<I, F>::unsigned_type;
constexpr int bits = Fixed<I, F>::total_bits;
if (denominator == 0) {
throw divide_by_zero();
}
else {
int sign = 0;
Fixed<I, F> quotient;
if (numerator < 0) {
sign ^= 1;
numerator = -numerator;
}
if (denominator < 0) {
sign ^= 1;
denominator = -denominator;
}
base_type n = numerator.to_raw();
base_type d = denominator.to_raw();
base_type x = 1;
base_type answer = 0;
// egyptian division algorithm
while ((n >= d) && (((d >> (bits - 1)) & 1) == 0)) {
x <<= 1;
d <<= 1;
}
while (x != 0) {
if (n >= d) {
n -= d;
answer += x;
}
x >>= 1;
d >>= 1;
}
unsigned_type l1 = n;
unsigned_type l2 = denominator.to_raw();
// calculate the lower bits (needs to be unsigned)
// unfortunately for many fractions this overflows the type still :-/
const unsigned_type lo = (static_cast<unsigned_type>(n) << F) / denominator.to_raw();
quotient = Fixed<I, F>::from_base((answer << F) | lo);
remainder = n;
if (sign) {
quotient = -quotient;
}
return quotient;
}
}
// this is the usual implementation of multiplication
template <size_t I, size_t F>
CONSTEXPR14 Fixed<I, F> multiply(Fixed<I, F> lhs, Fixed<I, F> rhs, typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type * = nullptr) {
using next_type = typename Fixed<I, F>::next_type;
using base_type = typename Fixed<I, F>::base_type;
constexpr size_t fractional_bits = Fixed<I, F>::fractional_bits;
next_type t(static_cast<next_type>(lhs.to_raw()) * static_cast<next_type>(rhs.to_raw()));
t >>= fractional_bits;
return Fixed<I, F>::from_base(next_to_base<base_type>(t));
}
// this is the fall back version we use when we don't have a next size
// it is slightly slower, but is more robust since it doesn't
// require and upgraded type
template <size_t I, size_t F>
CONSTEXPR14 Fixed<I, F> multiply(Fixed<I, F> lhs, Fixed<I, F> rhs, typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type * = nullptr) {
using base_type = typename Fixed<I, F>::base_type;
constexpr size_t fractional_bits = Fixed<I, F>::fractional_bits;
constexpr base_type integer_mask = Fixed<I, F>::integer_mask;
constexpr base_type fractional_mask = Fixed<I, F>::fractional_mask;
// more costly but doesn't need a larger type
constexpr base_type a_hi = (lhs.to_raw() & integer_mask) >> fractional_bits;
constexpr base_type b_hi = (rhs.to_raw() & integer_mask) >> fractional_bits;
constexpr base_type a_lo = (lhs.to_raw() & fractional_mask);
constexpr base_type b_lo = (rhs.to_raw() & fractional_mask);
constexpr base_type x1 = a_hi * b_hi;
constexpr base_type x2 = a_hi * b_lo;
constexpr base_type x3 = a_lo * b_hi;
constexpr base_type x4 = a_lo * b_lo;
return Fixed<I, F>::from_base((x1 << fractional_bits) + (x3 + x2) + (x4 >> fractional_bits));
}
}
template <size_t I, size_t F>
class Fixed {
static_assert(detail::type_from_size<I + F>::is_specialized, "invalid combination of sizes");
public:
static constexpr size_t fractional_bits = F;
static constexpr size_t integer_bits = I;
static constexpr size_t total_bits = I + F;
using base_type_info = detail::type_from_size<total_bits>;
using base_type = typename base_type_info::value_type;
using next_type = typename base_type_info::next_size::value_type;
using unsigned_type = typename base_type_info::unsigned_type;
public:
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverflow"
#endif
static constexpr base_type fractional_mask = ~(static_cast<unsigned_type>(~base_type(0)) << fractional_bits);
static constexpr base_type integer_mask = ~fractional_mask;
#ifdef __GNUC__
#pragma GCC diagnostic push
#endif
public:
static constexpr base_type one = base_type(1) << fractional_bits;
public: // constructors
Fixed() = default;
Fixed(const Fixed&) = default;
Fixed & operator=(const Fixed&) = default;
template <class Number>
constexpr Fixed(Number n, typename std::enable_if<std::is_arithmetic<Number>::value>::type * = nullptr) : data_(static_cast<base_type>(n * one)) {
}
public: // conversion
template <size_t I2, size_t F2>
CONSTEXPR14 explicit Fixed(Fixed<I2, F2> other) {
static_assert(I2 <= I && F2 <= F, "Scaling conversion can only upgrade types");
using T = Fixed<I2, F2>;
const base_type fractional = (other.data_ & T::fractional_mask);
const base_type integer = (other.data_ & T::integer_mask) >> T::fractional_bits;
data_ = (integer << fractional_bits) | (fractional << (fractional_bits - T::fractional_bits));
}
private:
// this makes it simpler to create a fixed point object from
// a native type without scaling
// use "Fixed::from_base" in order to perform this.
struct NoScale {};
constexpr Fixed(base_type n, const NoScale&) : data_(n) {
}
public:
constexpr static Fixed from_base(base_type n) {
return Fixed(n, NoScale());
}
public: // comparison operators
constexpr bool operator==(Fixed rhs) const {
return data_ == rhs.data_;
}
constexpr bool operator!=(Fixed rhs) const {
return data_ != rhs.data_;
}
constexpr bool operator<(Fixed rhs) const {
return data_ < rhs.data_;
}
constexpr bool operator>(Fixed rhs) const {
return data_ > rhs.data_;
}
constexpr bool operator<=(Fixed rhs) const {
return data_ <= rhs.data_;
}
constexpr bool operator>=(Fixed rhs) const {
return data_ >= rhs.data_;
}
public: // unary operators
constexpr bool operator!() const {
return !data_;
}
constexpr Fixed operator~() const {
// NOTE(eteran): this will often appear to "just negate" the value
// that is not an error, it is because -x == (~x+1)
// and that "+1" is adding an infinitesimally small fraction to the
// complimented value
return Fixed::from_base(~data_);
}
constexpr Fixed operator-() const {
return Fixed::from_base(-data_);
}
constexpr Fixed operator+() const {
return Fixed::from_base(+data_);
}
CONSTEXPR14 Fixed& operator++() {
data_ += one;
return *this;
}
CONSTEXPR14 Fixed& operator--() {
data_ -= one;
return *this;
}
CONSTEXPR14 Fixed operator++(int) {
Fixed tmp(*this);
data_ += one;
return tmp;
}
CONSTEXPR14 Fixed operator--(int) {
Fixed tmp(*this);
data_ -= one;
return tmp;
}
public: // basic math operators
CONSTEXPR14 Fixed& operator+=(Fixed n) {
data_ += n.data_;
return *this;
}
CONSTEXPR14 Fixed& operator-=(Fixed n) {
data_ -= n.data_;
return *this;
}
CONSTEXPR14 Fixed& operator*=(Fixed n) {
return assign(detail::multiply(*this, n));
}
CONSTEXPR14 Fixed& operator/=(Fixed n) {
Fixed temp;
return assign(detail::divide(*this, n, temp));
}
private:
CONSTEXPR14 Fixed& assign(Fixed rhs) {
data_ = rhs.data_;
return *this;
}
public: // binary math operators, effects underlying bit pattern since these
// don't really typically make sense for non-integer values
CONSTEXPR14 Fixed& operator&=(Fixed n) {
data_ &= n.data_;
return *this;
}
CONSTEXPR14 Fixed& operator|=(Fixed n) {
data_ |= n.data_;
return *this;
}
CONSTEXPR14 Fixed& operator^=(Fixed n) {
data_ ^= n.data_;
return *this;
}
template <class Integer, class = typename std::enable_if<std::is_integral<Integer>::value>::type>
CONSTEXPR14 Fixed & operator>>=(Integer n) {
data_ >>= n;
return *this;
}
template <class Integer, class = typename std::enable_if<std::is_integral<Integer>::value>::type>
CONSTEXPR14 Fixed & operator<<=(Integer n) {
data_ <<= n;
return *this;
}
public: // conversion to basic types
constexpr int to_int() const {
return (data_ & integer_mask) >> fractional_bits;
}
constexpr unsigned int to_uint() const {
return (data_ & integer_mask) >> fractional_bits;
}
constexpr float to_float() const {
return static_cast<float>(data_) / Fixed::one;
}
constexpr double to_double() const {
return static_cast<double>(data_) / Fixed::one;
}
constexpr base_type to_raw() const {
return data_;
}
public:
CONSTEXPR14 void swap(Fixed & rhs) {
using std::swap;
swap(data_, rhs.data_);
}
public:
base_type data_ = 0;
};
// if we have the same fractional portion, but differing integer portions, we trivially upgrade the smaller type
template <size_t I1, size_t I2, size_t F>
CONSTEXPR14 typename std::conditional<I1 >= I2, Fixed<I1, F>, Fixed<I2, F>>::type operator+(Fixed<I1, F> lhs, Fixed<I2, F> rhs) {
using T = typename std::conditional<
I1 >= I2,
Fixed<I1, F>,
Fixed<I2, F>
>::type;
const T l = T::from_base(lhs.to_raw());
const T r = T::from_base(rhs.to_raw());
return l + r;
}
template <size_t I1, size_t I2, size_t F>
CONSTEXPR14 typename std::conditional<I1 >= I2, Fixed<I1, F>, Fixed<I2, F>>::type operator-(Fixed<I1, F> lhs, Fixed<I2, F> rhs) {
using T = typename std::conditional<
I1 >= I2,
Fixed<I1, F>,
Fixed<I2, F>
>::type;
const T l = T::from_base(lhs.to_raw());
const T r = T::from_base(rhs.to_raw());
return l - r;
}
template <size_t I1, size_t I2, size_t F>
CONSTEXPR14 typename std::conditional<I1 >= I2, Fixed<I1, F>, Fixed<I2, F>>::type operator*(Fixed<I1, F> lhs, Fixed<I2, F> rhs) {
using T = typename std::conditional<
I1 >= I2,
Fixed<I1, F>,
Fixed<I2, F>
>::type;
const T l = T::from_base(lhs.to_raw());
const T r = T::from_base(rhs.to_raw());
return l * r;
}
template <size_t I1, size_t I2, size_t F>
CONSTEXPR14 typename std::conditional<I1 >= I2, Fixed<I1, F>, Fixed<I2, F>>::type operator/(Fixed<I1, F> lhs, Fixed<I2, F> rhs) {
using T = typename std::conditional<
I1 >= I2,
Fixed<I1, F>,
Fixed<I2, F>
>::type;
const T l = T::from_base(lhs.to_raw());
const T r = T::from_base(rhs.to_raw());
return l / r;
}
template <size_t I, size_t F>
std::ostream& operator<<(std::ostream & os, Fixed<I, F> f) {
os << f.to_double();
return os;
}
// basic math operators
template <size_t I, size_t F> CONSTEXPR14 Fixed<I, F> operator+(Fixed<I, F> lhs, Fixed<I, F> rhs) { lhs += rhs; return lhs; }
template <size_t I, size_t F> CONSTEXPR14 Fixed<I, F> operator-(Fixed<I, F> lhs, Fixed<I, F> rhs) { lhs -= rhs; return lhs; }
template <size_t I, size_t F> CONSTEXPR14 Fixed<I, F> operator*(Fixed<I, F> lhs, Fixed<I, F> rhs) { lhs *= rhs; return lhs; }
template <size_t I, size_t F> CONSTEXPR14 Fixed<I, F> operator/(Fixed<I, F> lhs, Fixed<I, F> rhs) { lhs /= rhs; return lhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator+(Fixed<I, F> lhs, Number rhs) { lhs += Fixed<I, F>(rhs); return lhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator-(Fixed<I, F> lhs, Number rhs) { lhs -= Fixed<I, F>(rhs); return lhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator*(Fixed<I, F> lhs, Number rhs) { lhs *= Fixed<I, F>(rhs); return lhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator/(Fixed<I, F> lhs, Number rhs) { lhs /= Fixed<I, F>(rhs); return lhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator+(Number lhs, Fixed<I, F> rhs) { Fixed<I, F> tmp(lhs); tmp += rhs; return tmp; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator-(Number lhs, Fixed<I, F> rhs) { Fixed<I, F> tmp(lhs); tmp -= rhs; return tmp; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator*(Number lhs, Fixed<I, F> rhs) { Fixed<I, F> tmp(lhs); tmp *= rhs; return tmp; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> CONSTEXPR14 Fixed<I, F> operator/(Number lhs, Fixed<I, F> rhs) { Fixed<I, F> tmp(lhs); tmp /= rhs; return tmp; }
// shift operators
template <size_t I, size_t F, class Integer, class = typename std::enable_if<std::is_integral<Integer>::value>::type> CONSTEXPR14 Fixed<I, F> operator<<(Fixed<I, F> lhs, Integer rhs) { lhs <<= rhs; return lhs; }
template <size_t I, size_t F, class Integer, class = typename std::enable_if<std::is_integral<Integer>::value>::type> CONSTEXPR14 Fixed<I, F> operator>>(Fixed<I, F> lhs, Integer rhs) { lhs >>= rhs; return lhs; }
// comparison operators
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator>(Fixed<I, F> lhs, Number rhs) { return lhs > Fixed<I, F>(rhs); }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator<(Fixed<I, F> lhs, Number rhs) { return lhs < Fixed<I, F>(rhs); }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator>=(Fixed<I, F> lhs, Number rhs) { return lhs >= Fixed<I, F>(rhs); }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator<=(Fixed<I, F> lhs, Number rhs) { return lhs <= Fixed<I, F>(rhs); }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator==(Fixed<I, F> lhs, Number rhs) { return lhs == Fixed<I, F>(rhs); }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator!=(Fixed<I, F> lhs, Number rhs) { return lhs != Fixed<I, F>(rhs); }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator>(Number lhs, Fixed<I, F> rhs) { return Fixed<I, F>(lhs) > rhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator<(Number lhs, Fixed<I, F> rhs) { return Fixed<I, F>(lhs) < rhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator>=(Number lhs, Fixed<I, F> rhs) { return Fixed<I, F>(lhs) >= rhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator<=(Number lhs, Fixed<I, F> rhs) { return Fixed<I, F>(lhs) <= rhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator==(Number lhs, Fixed<I, F> rhs) { return Fixed<I, F>(lhs) == rhs; }
template <size_t I, size_t F, class Number, class = typename std::enable_if<std::is_arithmetic<Number>::value>::type> constexpr bool operator!=(Number lhs, Fixed<I, F> rhs) { return Fixed<I, F>(lhs) != rhs; }
}
#undef CONSTEXPR14
#endif

442
Libs/flatbuffers/base.h Normal file
View file

@ -0,0 +1,442 @@
#ifndef FLATBUFFERS_BASE_H_
# define FLATBUFFERS_BASE_H_
// clang-format off
// If activate should be declared and included first.
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
defined(_MSC_VER) && defined(_DEBUG)
// The _CRTDBG_MAP_ALLOC inside <crtdbg.h> will replace
// calloc/free (etc) to its debug version using #define directives.
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
// Replace operator new by trace-enabled version.
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
#if !defined(FLATBUFFERS_ASSERT)
#include <assert.h>
#define FLATBUFFERS_ASSERT assert
#elif defined(FLATBUFFERS_ASSERT_INCLUDE)
// Include file with forward declaration
#include FLATBUFFERS_ASSERT_INCLUDE
#endif
#ifndef ARDUINO
#include <cstdint>
#endif
#include <cstddef>
#include <cstdlib>
#include <cstring>
#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
#include <utility.h>
#else
#include <utility>
#endif
#include <string>
#include <type_traits>
#include <vector>
#include <set>
#include <algorithm>
#include <iterator>
#include <memory>
#if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT)
#include <unistd.h>
#endif
#ifdef _STLPORT_VERSION
#define FLATBUFFERS_CPP98_STL
#endif
#ifdef __ANDROID__
#include <android/api-level.h>
#endif
#if defined(__ICCARM__)
#include <intrinsics.h>
#endif
// Note the __clang__ check is needed, because clang presents itself
// as an older GNUC compiler (4.2).
// Clang 3.3 and later implement all of the ISO C++ 2011 standard.
// Clang 3.4 and later implement all of the ISO C++ 2014 standard.
// http://clang.llvm.org/cxx_status.html
// Note the MSVC value '__cplusplus' may be incorrect:
// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L,
// indicating (erroneously!) that the compiler conformed to the C++98 Standard.
// This value should be correct starting from MSVC2017-15.7-Preview-3.
// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set.
// Workaround (for details see MSDN):
// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility.
// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch.
#if defined(__GNUC__) && !defined(__clang__)
#define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#else
#define FLATBUFFERS_GCC 0
#endif
#if defined(__clang__)
#define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#else
#define FLATBUFFERS_CLANG 0
#endif
/// @cond FLATBUFFERS_INTERNAL
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
(!defined(__GNUC__) || \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
#error A C++11 compatible compiler with support for the auto typing is \
required for FlatBuffers.
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
#endif
#if !defined(__clang__) && \
defined(__GNUC__) && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
// Backwards compatibility for g++ 4.4, and 4.5 which don't have the nullptr
// and constexpr keywords. Note the __clang__ check is needed, because clang
// presents itself as an older GNUC compiler.
#ifndef nullptr_t
const class nullptr_t {
public:
template<class T> inline operator T*() const { return 0; }
private:
void operator&() const;
} nullptr = {};
#endif
#ifndef constexpr
#define constexpr const
#endif
#endif
// The wire format uses a little endian encoding (since that's efficient for
// the common platforms).
#if defined(__s390x__)
#define FLATBUFFERS_LITTLEENDIAN 0
#endif // __s390x__
#if !defined(FLATBUFFERS_LITTLEENDIAN)
#if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
#if (defined(__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
#define FLATBUFFERS_LITTLEENDIAN 0
#else
#define FLATBUFFERS_LITTLEENDIAN 1
#endif // __BIG_ENDIAN__
#elif defined(_MSC_VER)
#if defined(_M_PPC)
#define FLATBUFFERS_LITTLEENDIAN 0
#else
#define FLATBUFFERS_LITTLEENDIAN 1
#endif
#else
#error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
#endif
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
#define FLATBUFFERS_VERSION_MAJOR 2
#define FLATBUFFERS_VERSION_MINOR 0
#define FLATBUFFERS_VERSION_REVISION 0
#define FLATBUFFERS_STRING_EXPAND(X) #X
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
namespace flatbuffers {
// Returns version as string "MAJOR.MINOR.REVISION".
const char* FLATBUFFERS_VERSION();
}
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \
defined(__clang__)
#define FLATBUFFERS_FINAL_CLASS final
#define FLATBUFFERS_OVERRIDE override
#define FLATBUFFERS_EXPLICIT_CPP11 explicit
#define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t
#else
#define FLATBUFFERS_FINAL_CLASS
#define FLATBUFFERS_OVERRIDE
#define FLATBUFFERS_EXPLICIT_CPP11
#define FLATBUFFERS_VTABLE_UNDERLYING_TYPE
#endif
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
(defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
#define FLATBUFFERS_CONSTEXPR constexpr
#define FLATBUFFERS_CONSTEXPR_CPP11 constexpr
#define FLATBUFFERS_CONSTEXPR_DEFINED
#else
#define FLATBUFFERS_CONSTEXPR const
#define FLATBUFFERS_CONSTEXPR_CPP11
#endif
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11
#else
#define FLATBUFFERS_CONSTEXPR_CPP14
#endif
#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
(defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \
defined(__clang__)
#define FLATBUFFERS_NOEXCEPT noexcept
#else
#define FLATBUFFERS_NOEXCEPT
#endif
// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
// private, so be sure to put it at the end or reset access mode explicitly.
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
defined(__clang__)
#define FLATBUFFERS_DELETE_FUNC(func) func = delete
#else
#define FLATBUFFERS_DELETE_FUNC(func) private: func
#endif
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
defined(__clang__)
#define FLATBUFFERS_DEFAULT_DECLARATION
#endif
// Check if we can use template aliases
// Not possible if Microsoft Compiler before 2012
// Possible is the language feature __cpp_alias_templates is defined well
// Or possible if the C++ std is C+11 or newer
#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \
|| (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \
|| (defined(__cplusplus) && __cplusplus >= 201103L)
#define FLATBUFFERS_TEMPLATES_ALIASES
#endif
#ifndef FLATBUFFERS_HAS_STRING_VIEW
// Only provide flatbuffers::string_view if __has_include can be used
// to detect a header that provides an implementation
#if defined(__has_include)
// Check for std::string_view (in c++17)
#if __has_include(<string_view>) && (__cplusplus >= 201606 || (defined(_HAS_CXX17) && _HAS_CXX17))
#include <string_view>
namespace flatbuffers {
typedef std::string_view string_view;
}
#define FLATBUFFERS_HAS_STRING_VIEW 1
// Check for std::experimental::string_view (in c++14, compiler-dependent)
#elif __has_include(<experimental/string_view>) && (__cplusplus >= 201411)
#include <experimental/string_view>
namespace flatbuffers {
typedef std::experimental::string_view string_view;
}
#define FLATBUFFERS_HAS_STRING_VIEW 1
// Check for absl::string_view
#elif __has_include("absl/strings/string_view.h")
#include "absl/strings/string_view.h"
namespace flatbuffers {
typedef absl::string_view string_view;
}
#define FLATBUFFERS_HAS_STRING_VIEW 1
#endif
#endif // __has_include
#endif // !FLATBUFFERS_HAS_STRING_VIEW
#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
// Allow heap allocations to be used
#define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1
#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK
#ifndef FLATBUFFERS_HAS_NEW_STRTOD
// Modern (C++11) strtod and strtof functions are available for use.
// 1) nan/inf strings as argument of strtod;
// 2) hex-float as argument of strtod/strtof.
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
(defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
(defined(__clang__))
#define FLATBUFFERS_HAS_NEW_STRTOD 1
#endif
#endif // !FLATBUFFERS_HAS_NEW_STRTOD
#ifndef FLATBUFFERS_LOCALE_INDEPENDENT
// Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}.
#if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION>=700)) && (!defined(__ANDROID_API__) || (defined(__ANDROID_API__) && (__ANDROID_API__>=21))))
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
#else
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
#endif
#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
// Suppress Undefined Behavior Sanitizer (recoverable only). Usage:
// - __supress_ubsan__("undefined")
// - __supress_ubsan__("signed-integer-overflow")
#if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7))
#define __supress_ubsan__(type) __attribute__((no_sanitize(type)))
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
#define __supress_ubsan__(type) __attribute__((no_sanitize_undefined))
#else
#define __supress_ubsan__(type)
#endif
// This is constexpr function used for checking compile-time constants.
// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`.
template<typename T> FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) {
return !!t;
}
// Enable C++ attribute [[]] if std:c++17 or higher.
#if ((__cplusplus >= 201703L) \
|| (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
// All attributes unknown to an implementation are ignored without causing an error.
#define FLATBUFFERS_ATTRIBUTE(attr) [[attr]]
#define FLATBUFFERS_FALLTHROUGH() [[fallthrough]]
#else
#define FLATBUFFERS_ATTRIBUTE(attr)
#if FLATBUFFERS_CLANG >= 30800
#define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]]
#elif FLATBUFFERS_GCC >= 70300
#define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]]
#else
#define FLATBUFFERS_FALLTHROUGH()
#endif
#endif
/// @endcond
/// @file
namespace flatbuffers {
/// @cond FLATBUFFERS_INTERNAL
// Our default offset / size type, 32bit on purpose on 64bit systems.
// Also, using a consistent offset type maintains compatibility of serialized
// offset values between 32bit and 64bit systems.
typedef uint32_t uoffset_t;
// Signed offsets for references that can go in both directions.
typedef int32_t soffset_t;
// Offset/index used in v-tables, can be changed to uint8_t in
// format forks to save a bit of space if desired.
typedef uint16_t voffset_t;
typedef uintmax_t largest_scalar_t;
// In 32bits, this evaluates to 2GB - 1
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1)
// We support aligning the contents of buffers up to this size.
#define FLATBUFFERS_MAX_ALIGNMENT 16
inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) {
return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) &&
(align & (align - 1)) == 0; // must be power of 2
}
#if defined(_MSC_VER)
#pragma warning(disable: 4351) // C4351: new behavior: elements of array ... will be default initialized
#pragma warning(push)
#pragma warning(disable: 4127) // C4127: conditional expression is constant
#endif
template<typename T> T EndianSwap(T t) {
#if defined(_MSC_VER)
#define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
#define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
#define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
#elif defined(__ICCARM__)
#define FLATBUFFERS_BYTESWAP16 __REV16
#define FLATBUFFERS_BYTESWAP32 __REV
#define FLATBUFFERS_BYTESWAP64(x) \
((__REV(static_cast<uint32_t>(x >> 32U))) | (static_cast<uint64_t>(__REV(static_cast<uint32_t>(x)))) << 32U)
#else
#if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
// __builtin_bswap16 was missing prior to GCC 4.8.
#define FLATBUFFERS_BYTESWAP16(x) \
static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
#else
#define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
#endif
#define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
#define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
#endif
if (sizeof(T) == 1) { // Compile-time if-then's.
return t;
} else if (sizeof(T) == 2) {
union { T t; uint16_t i; } u = { t };
u.i = FLATBUFFERS_BYTESWAP16(u.i);
return u.t;
} else if (sizeof(T) == 4) {
union { T t; uint32_t i; } u = { t };
u.i = FLATBUFFERS_BYTESWAP32(u.i);
return u.t;
} else if (sizeof(T) == 8) {
union { T t; uint64_t i; } u = { t };
u.i = FLATBUFFERS_BYTESWAP64(u.i);
return u.t;
} else {
FLATBUFFERS_ASSERT(0);
return t;
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
template<typename T> T EndianScalar(T t) {
#if FLATBUFFERS_LITTLEENDIAN
return t;
#else
return EndianSwap(t);
#endif
}
template<typename T>
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
__supress_ubsan__("alignment")
T ReadScalar(const void *p) {
return EndianScalar(*reinterpret_cast<const T *>(p));
}
// See https://github.com/google/flatbuffers/issues/5950
#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
template<typename T>
// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
__supress_ubsan__("alignment")
void WriteScalar(void *p, T t) {
*reinterpret_cast<T *>(p) = EndianScalar(t);
}
template<typename T> struct Offset;
template<typename T> __supress_ubsan__("alignment") void WriteScalar(void *p, Offset<T> t) {
*reinterpret_cast<uoffset_t *>(p) = EndianScalar(t.o);
}
#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000)
#pragma GCC diagnostic pop
#endif
// Computes how many bytes you'd have to pad to be able to write an
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
// memory).
__supress_ubsan__("unsigned-integer-overflow")
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
return ((~buf_size) + 1) & (scalar_size - 1);
}
} // namespace flatbuffers
#endif // FLATBUFFERS_BASE_H_

View file

@ -0,0 +1,235 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_CODE_GENERATORS_H_
#define FLATBUFFERS_CODE_GENERATORS_H_
#include <map>
#include <sstream>
#include "flatbuffers/idl.h"
namespace flatbuffers {
// Utility class to assist in generating code through use of text templates.
//
// Example code:
// CodeWriter code("\t");
// code.SetValue("NAME", "Foo");
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
// code.SetValue("NAME", "Bar");
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
// std::cout << code.ToString() << std::endl;
//
// Output:
// void Foo() { printf("%s", "Foo"); }
// void Bar() { printf("%s", "Bar"); }
class CodeWriter {
public:
CodeWriter(std::string pad = std::string())
: pad_(pad), cur_ident_lvl_(0), ignore_ident_(false) {}
// Clears the current "written" code.
void Clear() {
stream_.str("");
stream_.clear();
}
// Associates a key with a value. All subsequent calls to operator+=, where
// the specified key is contained in {{ and }} delimiters will be replaced by
// the given value.
void SetValue(const std::string &key, const std::string &value) {
value_map_[key] = value;
}
std::string GetValue(const std::string &key) const {
const auto it = value_map_.find(key);
return it == value_map_.end() ? "" : it->second;
}
// Appends the given text to the generated code as well as a newline
// character. Any text within {{ and }} delimiters is replaced by values
// previously stored in the CodeWriter by calling SetValue above. The newline
// will be suppressed if the text ends with the \\ character.
void operator+=(std::string text);
// Returns the current contents of the CodeWriter as a std::string.
std::string ToString() const { return stream_.str(); }
// Increase ident level for writing code
void IncrementIdentLevel() { cur_ident_lvl_++; }
// Decrease ident level for writing code
void DecrementIdentLevel() {
if (cur_ident_lvl_) cur_ident_lvl_--;
}
void SetPadding(const std::string &padding) { pad_ = padding; }
private:
std::map<std::string, std::string> value_map_;
std::stringstream stream_;
std::string pad_;
int cur_ident_lvl_;
bool ignore_ident_;
// Add ident padding (tab or space) based on ident level
void AppendIdent(std::stringstream &stream);
};
class BaseGenerator {
public:
virtual bool generate() = 0;
static std::string NamespaceDir(const Parser &parser, const std::string &path,
const Namespace &ns,
const bool dasherize = false);
static std::string ToDasherizedCase(const std::string pascal_case);
std::string GeneratedFileName(const std::string &path,
const std::string &file_name,
const IDLOptions &options) const;
protected:
BaseGenerator(const Parser &parser, const std::string &path,
const std::string &file_name, std::string qualifying_start,
std::string qualifying_separator, std::string default_extension)
: parser_(parser),
path_(path),
file_name_(file_name),
qualifying_start_(qualifying_start),
qualifying_separator_(qualifying_separator),
default_extension_(default_extension) {}
virtual ~BaseGenerator() {}
// No copy/assign.
BaseGenerator &operator=(const BaseGenerator &);
BaseGenerator(const BaseGenerator &);
std::string NamespaceDir(const Namespace &ns,
const bool dasherize = false) const;
static const char *FlatBuffersGeneratedWarning();
static std::string FullNamespace(const char *separator, const Namespace &ns);
static std::string LastNamespacePart(const Namespace &ns);
// tracks the current namespace for early exit in WrapInNameSpace
// c++, java and csharp returns a different namespace from
// the following default (no early exit, always fully qualify),
// which works for js and php
virtual const Namespace *CurrentNameSpace() const { return nullptr; }
// Ensure that a type is prefixed with its namespace even within
// its own namespace to avoid conflict between generated method
// names and similarly named classes or structs
std::string WrapInNameSpace(const Namespace *ns,
const std::string &name) const;
std::string WrapInNameSpace(const Definition &def) const;
std::string GetNameSpace(const Definition &def) const;
const Parser &parser_;
const std::string &path_;
const std::string &file_name_;
const std::string qualifying_start_;
const std::string qualifying_separator_;
const std::string default_extension_;
};
struct CommentConfig {
const char *first_line;
const char *content_line_prefix;
const char *last_line;
};
extern void GenComment(const std::vector<std::string> &dc,
std::string *code_ptr, const CommentConfig *config,
const char *prefix = "");
class FloatConstantGenerator {
public:
virtual ~FloatConstantGenerator() {}
std::string GenFloatConstant(const FieldDef &field) const;
private:
virtual std::string Value(double v, const std::string &src) const = 0;
virtual std::string Inf(double v) const = 0;
virtual std::string NaN(double v) const = 0;
virtual std::string Value(float v, const std::string &src) const = 0;
virtual std::string Inf(float v) const = 0;
virtual std::string NaN(float v) const = 0;
template<typename T>
std::string GenFloatConstantImpl(const FieldDef &field) const;
};
class SimpleFloatConstantGenerator : public FloatConstantGenerator {
public:
SimpleFloatConstantGenerator(const char *nan_number,
const char *pos_inf_number,
const char *neg_inf_number);
private:
std::string Value(double v,
const std::string &src) const FLATBUFFERS_OVERRIDE;
std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
const std::string nan_number_;
const std::string pos_inf_number_;
const std::string neg_inf_number_;
};
// C++, C#, Java like generator.
class TypedFloatConstantGenerator : public FloatConstantGenerator {
public:
TypedFloatConstantGenerator(const char *double_prefix,
const char *single_prefix, const char *nan_number,
const char *pos_inf_number,
const char *neg_inf_number = "");
private:
std::string Value(double v,
const std::string &src) const FLATBUFFERS_OVERRIDE;
std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
std::string MakeNaN(const std::string &prefix) const;
std::string MakeInf(bool neg, const std::string &prefix) const;
const std::string double_prefix_;
const std::string single_prefix_;
const std::string nan_number_;
const std::string pos_inf_number_;
const std::string neg_inf_number_;
};
} // namespace flatbuffers
#endif // FLATBUFFERS_CODE_GENERATORS_H_

File diff suppressed because it is too large Load diff

100
Libs/flatbuffers/flatc.h Normal file
View file

@ -0,0 +1,100 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_FLATC_H_
#define FLATBUFFERS_FLATC_H_
#include <functional>
#include <limits>
#include <string>
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
extern void LogCompilerWarn(const std::string &warn);
extern void LogCompilerError(const std::string &err);
class FlatCompiler {
public:
// Output generator for the various programming languages and formats we
// support.
struct Generator {
typedef bool (*GenerateFn)(const flatbuffers::Parser &parser,
const std::string &path,
const std::string &file_name);
typedef std::string (*MakeRuleFn)(const flatbuffers::Parser &parser,
const std::string &path,
const std::string &file_name);
GenerateFn generate;
const char *generator_opt_short;
const char *generator_opt_long;
const char *lang_name;
bool schema_only;
GenerateFn generateGRPC;
flatbuffers::IDLOptions::Language lang;
const char *generator_help;
MakeRuleFn make_rule;
};
typedef void (*WarnFn)(const FlatCompiler *flatc, const std::string &warn,
bool show_exe_name);
typedef void (*ErrorFn)(const FlatCompiler *flatc, const std::string &err,
bool usage, bool show_exe_name);
// Parameters required to initialize the FlatCompiler.
struct InitParams {
InitParams()
: generators(nullptr),
num_generators(0),
warn_fn(nullptr),
error_fn(nullptr) {}
const Generator *generators;
size_t num_generators;
WarnFn warn_fn;
ErrorFn error_fn;
};
explicit FlatCompiler(const InitParams &params) : params_(params) {}
int Compile(int argc, const char **argv);
std::string GetUsageString(const char *program_name) const;
private:
void ParseFile(flatbuffers::Parser &parser, const std::string &filename,
const std::string &contents,
std::vector<const char *> &include_directories) const;
void LoadBinarySchema(Parser &parser, const std::string &filename,
const std::string &contents);
void Warn(const std::string &warn, bool show_exe_name = true) const;
void Error(const std::string &err, bool usage = true,
bool show_exe_name = true) const;
InitParams params_;
};
} // namespace flatbuffers
#endif // FLATBUFFERS_FLATC_H_

File diff suppressed because it is too large Load diff

298
Libs/flatbuffers/grpc.h Normal file
View file

@ -0,0 +1,298 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_GRPC_H_
#define FLATBUFFERS_GRPC_H_
// Helper functionality to glue FlatBuffers and GRPC.
#include "flatbuffers/flatbuffers.h"
#include "grpc/byte_buffer_reader.h"
#include "grpcpp/support/byte_buffer.h"
#include "grpcpp/support/slice.h"
namespace flatbuffers {
namespace grpc {
// Message is a typed wrapper around a buffer that manages the underlying
// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
// is refcounted and ownership is be managed automatically.
template<class T> class Message {
public:
Message() {}
Message(::grpc::Slice slice) : slice_(slice) {}
Message &operator=(const Message &other) = delete;
Message(Message &&other) = default;
Message(const Message &other) = delete;
Message &operator=(Message &&other) = default;
const uint8_t *mutable_data() const { return slice_.begin(); }
const uint8_t *data() const { return slice_.begin(); }
size_t size() const { return slice_.size(); }
bool Verify() const {
Verifier verifier(data(), size());
return verifier.VerifyBuffer<T>(nullptr);
}
T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
// This is only intended for serializer use, or if you know what you're doing
const ::grpc::Slice &BorrowSlice() const { return slice_; }
private:
::grpc::Slice slice_;
};
class MessageBuilder;
// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
// refcounted slices to manage memory ownership. This makes it easy and
// efficient to transfer buffers to gRPC.
class SliceAllocator : public Allocator {
public:
SliceAllocator() {}
SliceAllocator(const SliceAllocator &other) = delete;
SliceAllocator &operator=(const SliceAllocator &other) = delete;
SliceAllocator(SliceAllocator &&other) {
// default-construct and swap idiom
swap(other);
}
SliceAllocator &operator=(SliceAllocator &&other) {
// move-construct and swap idiom
SliceAllocator temp(std::move(other));
swap(temp);
return *this;
}
void swap(SliceAllocator &other) {
using std::swap;
swap(slice_, other.slice_);
}
virtual ~SliceAllocator() {}
virtual uint8_t *allocate(size_t size) override {
FLATBUFFERS_ASSERT(slice_.size() == 0);
slice_ = ::grpc::Slice(size);
return const_cast<uint8_t *>(slice_.begin());
}
virtual void deallocate(uint8_t *p, size_t size) override {
FLATBUFFERS_ASSERT(p == slice_.begin());
FLATBUFFERS_ASSERT(size == slice_.size());
slice_ = ::grpc::Slice();
}
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size, size_t in_use_back,
size_t in_use_front) override {
FLATBUFFERS_ASSERT(old_p == slice_.begin());
FLATBUFFERS_ASSERT(old_size == slice_.size());
FLATBUFFERS_ASSERT(new_size > old_size);
::grpc::Slice old_slice = slice_;
::grpc::Slice new_slice = ::grpc::Slice(new_size);
uint8_t *new_p = const_cast<uint8_t *>(new_slice.begin());
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
in_use_front);
slice_ = new_slice;
return new_p;
}
private:
::grpc::Slice &get_slice(uint8_t *p, size_t size) {
FLATBUFFERS_ASSERT(p == slice_.begin());
FLATBUFFERS_ASSERT(size == slice_.size());
return slice_;
}
::grpc::Slice slice_;
friend class MessageBuilder;
};
// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
// slice_allocator_ member is constructed before the FlatBufferBuilder, since
// the allocator is used in the FlatBufferBuilder ctor.
namespace detail {
struct SliceAllocatorMember {
SliceAllocator slice_allocator_;
};
} // namespace detail
// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
// to allocate gRPC buffers.
class MessageBuilder : private detail::SliceAllocatorMember,
public FlatBufferBuilder {
public:
explicit MessageBuilder(uoffset_t initial_size = 1024)
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
MessageBuilder(const MessageBuilder &other) = delete;
MessageBuilder &operator=(const MessageBuilder &other) = delete;
MessageBuilder(MessageBuilder &&other)
: FlatBufferBuilder(1024, &slice_allocator_, false) {
// Default construct and swap idiom.
Swap(other);
}
/// Create a MessageBuilder from a FlatBufferBuilder.
explicit MessageBuilder(FlatBufferBuilder &&src,
void (*dealloc)(void *,
size_t) = &DefaultAllocator::dealloc)
: FlatBufferBuilder(1024, &slice_allocator_, false) {
src.Swap(*this);
src.SwapBufAllocator(*this);
if (buf_.capacity()) {
uint8_t *buf = buf_.scratch_data(); // pointer to memory
size_t capacity = buf_.capacity(); // size of memory
slice_allocator_.slice_ = ::grpc::Slice(buf, capacity, dealloc);
} else {
slice_allocator_.slice_ = ::grpc::Slice();
}
}
/// Move-assign a FlatBufferBuilder to a MessageBuilder.
/// Only FlatBufferBuilder with default allocator (basically, nullptr) is
/// supported.
MessageBuilder &operator=(FlatBufferBuilder &&src) {
// Move construct a temporary and swap
MessageBuilder temp(std::move(src));
Swap(temp);
return *this;
}
MessageBuilder &operator=(MessageBuilder &&other) {
// Move construct a temporary and swap
MessageBuilder temp(std::move(other));
Swap(temp);
return *this;
}
void Swap(MessageBuilder &other) {
slice_allocator_.swap(other.slice_allocator_);
FlatBufferBuilder::Swap(other);
// After swapping the FlatBufferBuilder, we swap back the allocator, which
// restores the original allocator back in place. This is necessary because
// MessageBuilder's allocator is its own member (SliceAllocatorMember). The
// allocator passed to FlatBufferBuilder::vector_downward must point to this
// member.
buf_.swap_allocator(other.buf_);
}
// Releases the ownership of the buffer pointer.
// Returns the size, offset, and the original grpc_slice that
// allocated the buffer. Also see grpc_slice_unref().
uint8_t *ReleaseRaw(size_t &size, size_t &offset, ::grpc::Slice &slice) {
uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset);
slice = slice_allocator_.slice_;
slice_allocator_.slice_ = ::grpc::Slice();
return buf;
}
~MessageBuilder() {}
// GetMessage extracts the subslice of the buffer corresponding to the
// flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
// ownership.
template<class T> Message<T> GetMessage() {
auto buf_data = buf_.scratch_data(); // pointer to memory
auto buf_size = buf_.capacity(); // size of memory
auto msg_data = buf_.data(); // pointer to msg
auto msg_size = buf_.size(); // size of msg
// Do some sanity checks on data/size
FLATBUFFERS_ASSERT(msg_data);
FLATBUFFERS_ASSERT(msg_size);
FLATBUFFERS_ASSERT(msg_data >= buf_data);
FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size);
// Calculate offsets from the buffer start
auto begin = msg_data - buf_data;
auto end = begin + msg_size;
// Get the slice we are working with (no refcount change)
::grpc::Slice slice = slice_allocator_.get_slice(buf_data, buf_size);
// Extract a subslice of the existing slice (increment refcount)
::grpc::Slice subslice = slice.sub(begin, end);
// Wrap the subslice in a `Message<T>`, but don't increment refcount
Message<T> msg(subslice);
return msg;
}
template<class T> Message<T> ReleaseMessage() {
Message<T> msg = GetMessage<T>();
Reset();
return msg;
}
private:
// SliceAllocator slice_allocator_; // part of SliceAllocatorMember
};
} // namespace grpc
} // namespace flatbuffers
namespace grpc {
template<class T> class SerializationTraits<flatbuffers::grpc::Message<T>> {
public:
static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg,
ByteBuffer *buffer, bool *own_buffer) {
// Package the single slice into a `ByteBuffer`,
// incrementing the refcount in the process.
*buffer = ByteBuffer(&msg.BorrowSlice(), 1);
*own_buffer = true;
return grpc::Status::OK;
}
// Deserialize by pulling the
static grpc::Status Deserialize(ByteBuffer *buf,
flatbuffers::grpc::Message<T> *msg) {
Slice slice;
if (!buf->TrySingleSlice(&slice).ok()) {
if (!buf->DumpToSingleSlice(&slice).ok()) {
return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
}
}
*msg = flatbuffers::grpc::Message<T>(slice);
#if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
return ::grpc::Status::OK;
#else
if (msg->Verify()) {
return ::grpc::Status::OK;
} else {
return ::grpc::Status(::grpc::StatusCode::INTERNAL,
"Message verification failed");
}
#endif
}
};
} // namespace grpc
#endif // FLATBUFFERS_GRPC_H_

127
Libs/flatbuffers/hash.h Normal file
View file

@ -0,0 +1,127 @@
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_HASH_H_
#define FLATBUFFERS_HASH_H_
#include <cstdint>
#include <cstring>
#include "flatbuffers/flatbuffers.h"
namespace flatbuffers {
template<typename T> struct FnvTraits {
static const T kFnvPrime;
static const T kOffsetBasis;
};
template<> struct FnvTraits<uint32_t> {
static const uint32_t kFnvPrime = 0x01000193;
static const uint32_t kOffsetBasis = 0x811C9DC5;
};
template<> struct FnvTraits<uint64_t> {
static const uint64_t kFnvPrime = 0x00000100000001b3ULL;
static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL;
};
template<typename T> T HashFnv1(const char *input) {
T hash = FnvTraits<T>::kOffsetBasis;
for (const char *c = input; *c; ++c) {
hash *= FnvTraits<T>::kFnvPrime;
hash ^= static_cast<unsigned char>(*c);
}
return hash;
}
template<typename T> T HashFnv1a(const char *input) {
T hash = FnvTraits<T>::kOffsetBasis;
for (const char *c = input; *c; ++c) {
hash ^= static_cast<unsigned char>(*c);
hash *= FnvTraits<T>::kFnvPrime;
}
return hash;
}
template<> inline uint16_t HashFnv1<uint16_t>(const char *input) {
uint32_t hash = HashFnv1<uint32_t>(input);
return (hash >> 16) ^ (hash & 0xffff);
}
template<> inline uint16_t HashFnv1a<uint16_t>(const char *input) {
uint32_t hash = HashFnv1a<uint32_t>(input);
return (hash >> 16) ^ (hash & 0xffff);
}
template<typename T> struct NamedHashFunction {
const char *name;
typedef T (*HashFunction)(const char *);
HashFunction function;
};
const NamedHashFunction<uint16_t> kHashFunctions16[] = {
{ "fnv1_16", HashFnv1<uint16_t> },
{ "fnv1a_16", HashFnv1a<uint16_t> },
};
const NamedHashFunction<uint32_t> kHashFunctions32[] = {
{ "fnv1_32", HashFnv1<uint32_t> },
{ "fnv1a_32", HashFnv1a<uint32_t> },
};
const NamedHashFunction<uint64_t> kHashFunctions64[] = {
{ "fnv1_64", HashFnv1<uint64_t> },
{ "fnv1a_64", HashFnv1a<uint64_t> },
};
inline NamedHashFunction<uint16_t>::HashFunction FindHashFunction16(
const char *name) {
std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]);
for (std::size_t i = 0; i < size; ++i) {
if (std::strcmp(name, kHashFunctions16[i].name) == 0) {
return kHashFunctions16[i].function;
}
}
return nullptr;
}
inline NamedHashFunction<uint32_t>::HashFunction FindHashFunction32(
const char *name) {
std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]);
for (std::size_t i = 0; i < size; ++i) {
if (std::strcmp(name, kHashFunctions32[i].name) == 0) {
return kHashFunctions32[i].function;
}
}
return nullptr;
}
inline NamedHashFunction<uint64_t>::HashFunction FindHashFunction64(
const char *name) {
std::size_t size = sizeof(kHashFunctions64) / sizeof(kHashFunctions64[0]);
for (std::size_t i = 0; i < size; ++i) {
if (std::strcmp(name, kHashFunctions64[i].name) == 0) {
return kHashFunctions64[i].function;
}
}
return nullptr;
}
} // namespace flatbuffers
#endif // FLATBUFFERS_HASH_H_

1211
Libs/flatbuffers/idl.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,419 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_MINIREFLECT_H_
#define FLATBUFFERS_MINIREFLECT_H_
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
// Utilities that can be used with the "mini reflection" tables present
// in generated code with --reflect-types (only types) or --reflect-names
// (also names).
// This allows basic reflection functionality such as pretty-printing
// that does not require the use of the schema parser or loading of binary
// schema files at runtime (reflection.h).
// For any of the functions below that take `const TypeTable *`, you pass
// `FooTypeTable()` if the type of the root is `Foo`.
// First, a generic iterator that can be used by multiple algorithms.
struct IterationVisitor {
// These mark the scope of a table or struct.
virtual void StartSequence() {}
virtual void EndSequence() {}
// Called for each field regardless of whether it is present or not.
// If not present, val == nullptr. set_idx is the index of all set fields.
virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
ElementaryType /*type*/, bool /*is_vector*/,
const TypeTable * /*type_table*/, const char * /*name*/,
const uint8_t * /*val*/) {}
// Called for a value that is actually present, after a field, or as part
// of a vector.
virtual void UType(uint8_t, const char *) {}
virtual void Bool(bool) {}
virtual void Char(int8_t, const char *) {}
virtual void UChar(uint8_t, const char *) {}
virtual void Short(int16_t, const char *) {}
virtual void UShort(uint16_t, const char *) {}
virtual void Int(int32_t, const char *) {}
virtual void UInt(uint32_t, const char *) {}
virtual void Long(int64_t) {}
virtual void ULong(uint64_t) {}
virtual void Float(float) {}
virtual void Double(double) {}
virtual void String(const String *) {}
virtual void Unknown(const uint8_t *) {} // From a future version.
// These mark the scope of a vector.
virtual void StartVector() {}
virtual void EndVector() {}
virtual void Element(size_t /*i*/, ElementaryType /*type*/,
const TypeTable * /*type_table*/,
const uint8_t * /*val*/) {}
virtual ~IterationVisitor() {}
};
inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
switch (type) {
case ET_UTYPE:
case ET_BOOL:
case ET_CHAR:
case ET_UCHAR: return 1;
case ET_SHORT:
case ET_USHORT: return 2;
case ET_INT:
case ET_UINT:
case ET_FLOAT:
case ET_STRING: return 4;
case ET_LONG:
case ET_ULONG:
case ET_DOUBLE: return 8;
case ET_SEQUENCE:
switch (type_table->st) {
case ST_TABLE:
case ST_UNION: return 4;
case ST_STRUCT:
return static_cast<size_t>(type_table->values[type_table->num_elems]);
default: FLATBUFFERS_ASSERT(false); return 1;
}
default: FLATBUFFERS_ASSERT(false); return 1;
}
}
inline int64_t LookupEnum(int64_t enum_val, const int64_t *values,
size_t num_values) {
if (!values) return enum_val;
for (size_t i = 0; i < num_values; i++) {
if (enum_val == values[i]) return static_cast<int64_t>(i);
}
return -1; // Unknown enum value.
}
template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
if (!type_table || !type_table->names) return nullptr;
auto i = LookupEnum(static_cast<int64_t>(tval), type_table->values,
type_table->num_elems);
if (i >= 0 && i < static_cast<int64_t>(type_table->num_elems)) {
return type_table->names[i];
}
return nullptr;
}
void IterateObject(const uint8_t *obj, const TypeTable *type_table,
IterationVisitor *visitor);
inline void IterateValue(ElementaryType type, const uint8_t *val,
const TypeTable *type_table, const uint8_t *prev_val,
soffset_t vector_index, IterationVisitor *visitor) {
switch (type) {
case ET_UTYPE: {
auto tval = ReadScalar<uint8_t>(val);
visitor->UType(tval, EnumName(tval, type_table));
break;
}
case ET_BOOL: {
visitor->Bool(ReadScalar<uint8_t>(val) != 0);
break;
}
case ET_CHAR: {
auto tval = ReadScalar<int8_t>(val);
visitor->Char(tval, EnumName(tval, type_table));
break;
}
case ET_UCHAR: {
auto tval = ReadScalar<uint8_t>(val);
visitor->UChar(tval, EnumName(tval, type_table));
break;
}
case ET_SHORT: {
auto tval = ReadScalar<int16_t>(val);
visitor->Short(tval, EnumName(tval, type_table));
break;
}
case ET_USHORT: {
auto tval = ReadScalar<uint16_t>(val);
visitor->UShort(tval, EnumName(tval, type_table));
break;
}
case ET_INT: {
auto tval = ReadScalar<int32_t>(val);
visitor->Int(tval, EnumName(tval, type_table));
break;
}
case ET_UINT: {
auto tval = ReadScalar<uint32_t>(val);
visitor->UInt(tval, EnumName(tval, type_table));
break;
}
case ET_LONG: {
visitor->Long(ReadScalar<int64_t>(val));
break;
}
case ET_ULONG: {
visitor->ULong(ReadScalar<uint64_t>(val));
break;
}
case ET_FLOAT: {
visitor->Float(ReadScalar<float>(val));
break;
}
case ET_DOUBLE: {
visitor->Double(ReadScalar<double>(val));
break;
}
case ET_STRING: {
val += ReadScalar<uoffset_t>(val);
visitor->String(reinterpret_cast<const String *>(val));
break;
}
case ET_SEQUENCE: {
switch (type_table->st) {
case ST_TABLE:
val += ReadScalar<uoffset_t>(val);
IterateObject(val, type_table, visitor);
break;
case ST_STRUCT: IterateObject(val, type_table, visitor); break;
case ST_UNION: {
val += ReadScalar<uoffset_t>(val);
FLATBUFFERS_ASSERT(prev_val);
auto union_type = *prev_val; // Always a uint8_t.
if (vector_index >= 0) {
auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
}
auto type_code_idx =
LookupEnum(union_type, type_table->values, type_table->num_elems);
if (type_code_idx >= 0 &&
type_code_idx < static_cast<int32_t>(type_table->num_elems)) {
auto type_code = type_table->type_codes[type_code_idx];
switch (type_code.base_type) {
case ET_SEQUENCE: {
auto ref = type_table->type_refs[type_code.sequence_ref]();
IterateObject(val, ref, visitor);
break;
}
case ET_STRING:
visitor->String(reinterpret_cast<const String *>(val));
break;
default: visitor->Unknown(val);
}
} else {
visitor->Unknown(val);
}
break;
}
case ST_ENUM: FLATBUFFERS_ASSERT(false); break;
}
break;
}
default: {
visitor->Unknown(val);
break;
}
}
}
inline void IterateObject(const uint8_t *obj, const TypeTable *type_table,
IterationVisitor *visitor) {
visitor->StartSequence();
const uint8_t *prev_val = nullptr;
size_t set_idx = 0;
size_t array_idx = 0;
for (size_t i = 0; i < type_table->num_elems; i++) {
auto type_code = type_table->type_codes[i];
auto type = static_cast<ElementaryType>(type_code.base_type);
auto is_repeating = type_code.is_repeating != 0;
auto ref_idx = type_code.sequence_ref;
const TypeTable *ref = nullptr;
if (ref_idx >= 0) { ref = type_table->type_refs[ref_idx](); }
auto name = type_table->names ? type_table->names[i] : nullptr;
const uint8_t *val = nullptr;
if (type_table->st == ST_TABLE) {
val = reinterpret_cast<const Table *>(obj)->GetAddressOf(
FieldIndexToOffset(static_cast<voffset_t>(i)));
} else {
val = obj + type_table->values[i];
}
visitor->Field(i, set_idx, type, is_repeating, ref, name, val);
if (val) {
set_idx++;
if (is_repeating) {
auto elem_ptr = val;
size_t size = 0;
if (type_table->st == ST_TABLE) {
// variable length vector
val += ReadScalar<uoffset_t>(val);
auto vec = reinterpret_cast<const Vector<uint8_t> *>(val);
elem_ptr = vec->Data();
size = vec->size();
} else {
// otherwise fixed size array
size = type_table->array_sizes[array_idx];
++array_idx;
}
visitor->StartVector();
for (size_t j = 0; j < size; j++) {
visitor->Element(j, type, ref, elem_ptr);
IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
visitor);
elem_ptr += InlineSize(type, ref);
}
visitor->EndVector();
} else {
IterateValue(type, val, ref, prev_val, -1, visitor);
}
}
prev_val = val;
}
visitor->EndSequence();
}
inline void IterateFlatBuffer(const uint8_t *buffer,
const TypeTable *type_table,
IterationVisitor *callback) {
IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
}
// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
// the output generated by idl_gen_text.cpp.
struct ToStringVisitor : public IterationVisitor {
std::string s;
std::string d;
bool q;
std::string in;
size_t indent_level;
bool vector_delimited;
ToStringVisitor(std::string delimiter, bool quotes, std::string indent,
bool vdelimited = true)
: d(delimiter),
q(quotes),
in(indent),
indent_level(0),
vector_delimited(vdelimited) {}
ToStringVisitor(std::string delimiter)
: d(delimiter),
q(false),
in(""),
indent_level(0),
vector_delimited(true) {}
void append_indent() {
for (size_t i = 0; i < indent_level; i++) { s += in; }
}
void StartSequence() {
s += "{";
s += d;
indent_level++;
}
void EndSequence() {
s += d;
indent_level--;
append_indent();
s += "}";
}
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
bool /*is_vector*/, const TypeTable * /*type_table*/,
const char *name, const uint8_t *val) {
if (!val) return;
if (set_idx) {
s += ",";
s += d;
}
append_indent();
if (name) {
if (q) s += "\"";
s += name;
if (q) s += "\"";
s += ": ";
}
}
template<typename T> void Named(T x, const char *name) {
if (name) {
if (q) s += "\"";
s += name;
if (q) s += "\"";
} else {
s += NumToString(x);
}
}
void UType(uint8_t x, const char *name) { Named(x, name); }
void Bool(bool x) { s += x ? "true" : "false"; }
void Char(int8_t x, const char *name) { Named(x, name); }
void UChar(uint8_t x, const char *name) { Named(x, name); }
void Short(int16_t x, const char *name) { Named(x, name); }
void UShort(uint16_t x, const char *name) { Named(x, name); }
void Int(int32_t x, const char *name) { Named(x, name); }
void UInt(uint32_t x, const char *name) { Named(x, name); }
void Long(int64_t x) { s += NumToString(x); }
void ULong(uint64_t x) { s += NumToString(x); }
void Float(float x) { s += NumToString(x); }
void Double(double x) { s += NumToString(x); }
void String(const struct String *str) {
EscapeString(str->c_str(), str->size(), &s, true, false);
}
void Unknown(const uint8_t *) { s += "(?)"; }
void StartVector() {
s += "[";
if (vector_delimited) {
s += d;
indent_level++;
append_indent();
} else {
s += " ";
}
}
void EndVector() {
if (vector_delimited) {
s += d;
indent_level--;
append_indent();
} else {
s += " ";
}
s += "]";
}
void Element(size_t i, ElementaryType /*type*/,
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
if (i) {
s += ",";
if (vector_delimited) {
s += d;
append_indent();
} else {
s += " ";
}
}
}
};
inline std::string FlatBufferToString(const uint8_t *buffer,
const TypeTable *type_table,
bool multi_line = false,
bool vector_delimited = true) {
ToStringVisitor tostring_visitor(multi_line ? "\n" : " ", false, "",
vector_delimited);
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
return tostring_visitor.s;
}
} // namespace flatbuffers
#endif // FLATBUFFERS_MINIREFLECT_H_

View file

@ -0,0 +1,39 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_FLATC_PCH_H_
#define FLATBUFFERS_FLATC_PCH_H_
// stl
#include <cmath>
#include <sstream>
#include <cassert>
#include <unordered_set>
#include <unordered_map>
#include <iostream>
#include <functional>
#include <set>
#include <iterator>
#include <tuple>
// flatbuffers
#include "flatbuffers/pch/pch.h"
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/flexbuffers.h"
#include "flatbuffers/idl.h"
#endif // FLATBUFFERS_FLATC_PCH_H_

View file

@ -0,0 +1,38 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_PCH_H_
#define FLATBUFFERS_PCH_H_
// stl
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <list>
#include <string>
#include <utility>
#include <iomanip>
#include <map>
#include <memory>
#include <limits>
#include <stack>
#include <vector>
#include <type_traits>
// flatbuffers
#include "flatbuffers/util.h"
#endif // FLATBUFFERS_PCH_H_

View file

@ -0,0 +1,502 @@
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_REFLECTION_H_
#define FLATBUFFERS_REFLECTION_H_
// This is somewhat of a circular dependency because flatc (and thus this
// file) is needed to generate this header in the first place.
// Should normally not be a problem since it can be generated by the
// previous version of flatc whenever this code needs to change.
// See reflection/generate_code.sh
#include "flatbuffers/reflection_generated.h"
// Helper functionality for reflection.
namespace flatbuffers {
// ------------------------- GETTERS -------------------------
inline bool IsScalar(reflection::BaseType t) {
return t >= reflection::UType && t <= reflection::Double;
}
inline bool IsInteger(reflection::BaseType t) {
return t >= reflection::UType && t <= reflection::ULong;
}
inline bool IsFloat(reflection::BaseType t) {
return t == reflection::Float || t == reflection::Double;
}
inline bool IsLong(reflection::BaseType t) {
return t == reflection::Long || t == reflection::ULong;
}
// Size of a basic type, don't use with structs.
inline size_t GetTypeSize(reflection::BaseType base_type) {
// This needs to correspond to the BaseType enum.
static size_t sizes[] = {
0, // None
1, // UType
1, // Bool
1, // Byte
1, // UByte
2, // Short
2, // UShort
4, // Int
4, // UInt
8, // Long
8, // ULong
4, // Float
8, // Double
4, // String
4, // Vector
4, // Obj
4, // Union
0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds
// errors.
0 // MaxBaseType. This must be kept the last entry in this array.
};
static_assert(sizeof(sizes) / sizeof(size_t) == reflection::MaxBaseType + 1,
"Size of sizes[] array does not match the count of BaseType "
"enum values.");
return sizes[base_type];
}
// Same as above, but now correctly returns the size of a struct if
// the field (or vector element) is a struct.
inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index,
const reflection::Schema &schema) {
if (base_type == reflection::Obj &&
schema.objects()->Get(type_index)->is_struct()) {
return schema.objects()->Get(type_index)->bytesize();
} else {
return GetTypeSize(base_type);
}
}
// Get the root, regardless of what type it is.
inline Table *GetAnyRoot(uint8_t *flatbuf) {
return GetMutableRoot<Table>(flatbuf);
}
inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
return GetRoot<Table>(flatbuf);
}
// Get a field's default, if you know it's an integer, and its exact type.
template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return static_cast<T>(field.default_integer());
}
// Get a field's default, if you know it's floating point and its exact type.
template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return static_cast<T>(field.default_real());
}
// Get a field, if you know it's an integer, and its exact type.
template<typename T>
T GetFieldI(const Table &table, const reflection::Field &field) {
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table.GetField<T>(field.offset(),
static_cast<T>(field.default_integer()));
}
// Get a field, if you know it's floating point and its exact type.
template<typename T>
T GetFieldF(const Table &table, const reflection::Field &field) {
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table.GetField<T>(field.offset(),
static_cast<T>(field.default_real()));
}
// Get a field, if you know it's a string.
inline const String *GetFieldS(const Table &table,
const reflection::Field &field) {
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String);
return table.GetPointer<const String *>(field.offset());
}
// Get a field, if you know it's a vector.
template<typename T>
Vector<T> *GetFieldV(const Table &table, const reflection::Field &field) {
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector &&
sizeof(T) == GetTypeSize(field.type()->element()));
return table.GetPointer<Vector<T> *>(field.offset());
}
// Get a field, if you know it's a vector, generically.
// To actually access elements, use the return value together with
// field.type()->element() in any of GetAnyVectorElemI below etc.
inline VectorOfAny *GetFieldAnyV(const Table &table,
const reflection::Field &field) {
return table.GetPointer<VectorOfAny *>(field.offset());
}
// Get a field, if you know it's a table.
inline Table *GetFieldT(const Table &table, const reflection::Field &field) {
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj ||
field.type()->base_type() == reflection::Union);
return table.GetPointer<Table *>(field.offset());
}
// Get a field, if you know it's a struct.
inline const Struct *GetFieldStruct(const Table &table,
const reflection::Field &field) {
// TODO: This does NOT check if the field is a table or struct, but we'd need
// access to the schema to check the is_struct flag.
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
return table.GetStruct<const Struct *>(field.offset());
}
// Get a structure's field, if you know it's a struct.
inline const Struct *GetFieldStruct(const Struct &structure,
const reflection::Field &field) {
FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
return structure.GetStruct<const Struct *>(field.offset());
}
// Raw helper functions used below: get any value in memory as a 64bit int, a
// double or a string.
// All scalars get static_cast to an int64_t, strings use strtoull, every other
// data type returns 0.
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
// All scalars static cast to double, strings use strtod, every other data
// type is 0.0.
double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
// All scalars converted using stringstream, strings as-is, and all other
// data types provide some level of debug-pretty-printing.
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
const reflection::Schema *schema, int type_index);
// Get any table field as a 64bit int, regardless of what type it is.
inline int64_t GetAnyFieldI(const Table &table,
const reflection::Field &field) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
: field.default_integer();
}
// Get any table field as a double, regardless of what type it is.
inline double GetAnyFieldF(const Table &table, const reflection::Field &field) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
: field.default_real();
}
// Get any table field as a string, regardless of what type it is.
// You may pass nullptr for the schema if you don't care to have fields that
// are of table type pretty-printed.
inline std::string GetAnyFieldS(const Table &table,
const reflection::Field &field,
const reflection::Schema *schema) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
field.type()->index())
: "";
}
// Get any struct field as a 64bit int, regardless of what type it is.
inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) {
return GetAnyValueI(field.type()->base_type(),
st.GetAddressOf(field.offset()));
}
// Get any struct field as a double, regardless of what type it is.
inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) {
return GetAnyValueF(field.type()->base_type(),
st.GetAddressOf(field.offset()));
}
// Get any struct field as a string, regardless of what type it is.
inline std::string GetAnyFieldS(const Struct &st,
const reflection::Field &field) {
return GetAnyValueS(field.type()->base_type(),
st.GetAddressOf(field.offset()), nullptr, -1);
}
// Get any vector element as a 64bit int, regardless of what type it is.
inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
}
// Get any vector element as a double, regardless of what type it is.
inline double GetAnyVectorElemF(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
}
// Get any vector element as a string, regardless of what type it is.
inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
nullptr, -1);
}
// Get a vector element that's a table/string/vector from a generic vector.
// Pass Table/String/VectorOfAny as template parameter.
// Warning: does no typechecking.
template<typename T>
T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) {
auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
return reinterpret_cast<T *>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
}
// Get the inline-address of a vector element. Useful for Structs (pass Struct
// as template arg), or being able to address a range of scalars in-line.
// Get elem_size from GetTypeSizeInline().
// Note: little-endian data on all platforms, use EndianScalar() instead of
// raw pointer access with scalars).
template<typename T>
T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i,
size_t elem_size) {
return reinterpret_cast<T *>(vec->Data() + elem_size * i);
}
// Similarly, for elements of tables.
template<typename T>
T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) {
return reinterpret_cast<T *>(table.GetAddressOf(field.offset()));
}
// Similarly, for elements of structs.
template<typename T>
T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) {
return reinterpret_cast<T *>(st.GetAddressOf(field.offset()));
}
// ------------------------- SETTERS -------------------------
// Set any scalar field, if you know its exact type.
template<typename T>
bool SetField(Table *table, const reflection::Field &field, T val) {
reflection::BaseType type = field.type()->base_type();
if (!IsScalar(type)) { return false; }
FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type));
T def;
if (IsInteger(type)) {
def = GetFieldDefaultI<T>(field);
} else {
FLATBUFFERS_ASSERT(IsFloat(type));
def = GetFieldDefaultF<T>(field);
}
return table->SetField(field.offset(), val, def);
}
// Raw helper functions used below: set any value in memory as a 64bit int, a
// double or a string.
// These work for all scalar values, but do nothing for other data types.
// To set a string, see SetString below.
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
// Set any table field as a 64bit int, regardless of type what it is.
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
int64_t val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
SetAnyValueI(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any table field as a double, regardless of what type it is.
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
double val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return val == GetFieldDefaultF<double>(field);
SetAnyValueF(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any table field as a string, regardless of what type it is.
inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
const char *val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueS(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any struct field as a 64bit int, regardless of type what it is.
inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
int64_t val) {
SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any struct field as a double, regardless of type what it is.
inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
double val) {
SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any struct field as a string, regardless of type what it is.
inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
const char *val) {
SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any vector element as a 64bit int, regardless of type what it is.
inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, int64_t val) {
SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// Set any vector element as a double, regardless of type what it is.
inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, double val) {
SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// Set any vector element as a string, regardless of type what it is.
inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, const char *val) {
SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// ------------------------- RESIZING SETTERS -------------------------
// "smart" pointer for use with resizing vectors: turns a pointer inside
// a vector into a relative offset, such that it is not affected by resizes.
template<typename T, typename U> class pointer_inside_vector {
public:
pointer_inside_vector(T *ptr, std::vector<U> &vec)
: offset_(reinterpret_cast<uint8_t *>(ptr) -
reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec))),
vec_(vec) {}
T *operator*() const {
return reinterpret_cast<T *>(
reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec_)) + offset_);
}
T *operator->() const { return operator*(); }
private:
size_t offset_;
std::vector<U> &vec_;
};
// Helper to create the above easily without specifying template args.
template<typename T, typename U>
pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) {
return pointer_inside_vector<T, U>(ptr, vec);
}
inline const char *UnionTypeFieldSuffix() { return "_type"; }
// Helper to figure out the actual table type a union refers to.
inline const reflection::Object &GetUnionType(
const reflection::Schema &schema, const reflection::Object &parent,
const reflection::Field &unionfield, const Table &table) {
auto enumdef = schema.enums()->Get(unionfield.type()->index());
// TODO: this is clumsy and slow, but no other way to find it?
auto type_field = parent.fields()->LookupByKey(
(unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
FLATBUFFERS_ASSERT(type_field);
auto union_type = GetFieldI<uint8_t>(table, *type_field);
auto enumval = enumdef->values()->LookupByKey(union_type);
return *schema.objects()->Get(enumval->union_type()->index());
}
// Changes the contents of a string inside a FlatBuffer. FlatBuffer must
// live inside a std::vector so we can resize the buffer if needed.
// "str" must live inside "flatbuf" and may be invalidated after this call.
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
void SetString(const reflection::Schema &schema, const std::string &val,
const String *str, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
// live inside a std::vector so we can resize the buffer if needed.
// "vec" must live inside "flatbuf" and may be invalidated after this call.
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
const VectorOfAny *vec, uoffset_t num_elems,
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
template<typename T>
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr) {
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
auto newelems = ResizeAnyVector(
schema, newsize, reinterpret_cast<const VectorOfAny *>(vec), vec->size(),
static_cast<uoffset_t>(sizeof(T)), flatbuf, root_table);
// Set new elements to "val".
for (int i = 0; i < delta_elem; i++) {
auto loc = newelems + i * sizeof(T);
auto is_scalar = flatbuffers::is_scalar<T>::value;
if (is_scalar) {
WriteScalar(loc, val);
} else { // struct
*reinterpret_cast<T *>(loc) = val;
}
}
}
// Adds any new data (in the form of a new FlatBuffer) to an existing
// FlatBuffer. This can be used when any of the above methods are not
// sufficient, in particular for adding new tables and new fields.
// This is potentially slightly less efficient than a FlatBuffer constructed
// in one piece, since the new FlatBuffer doesn't share any vtables with the
// existing one.
// The return value can now be set using Vector::MutateOffset or SetFieldT
// below.
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
const uint8_t *newbuf, size_t newlen);
inline bool SetFieldT(Table *table, const reflection::Field &field,
const uint8_t *val) {
FLATBUFFERS_ASSERT(sizeof(uoffset_t) ==
GetTypeSize(field.type()->base_type()));
return table->SetPointer(field.offset(), val);
}
// ------------------------- COPYING -------------------------
// Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
// Can be used to do any kind of merging/selecting you may want to do out
// of existing buffers. Also useful to reconstruct a whole buffer if the
// above resizing functionality has introduced garbage in a buffer you want
// to remove.
// Note: this does not deal with DAGs correctly. If the table passed forms a
// DAG, the copy will be a tree instead (with duplicates). Strings can be
// shared however, by passing true for use_string_pooling.
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
const reflection::Schema &schema,
const reflection::Object &objectdef,
const Table &table,
bool use_string_pooling = false);
// Verifies the provided flatbuffer using reflection.
// root should point to the root type for this flatbuffer.
// buf should point to the start of flatbuffer data.
// length specifies the size of the flatbuffer data.
bool Verify(const reflection::Schema &schema, const reflection::Object &root,
const uint8_t *buf, size_t length, uoffset_t max_depth = 64,
uoffset_t max_tables = 1000000);
} // namespace flatbuffers
#endif // FLATBUFFERS_REFLECTION_H_

File diff suppressed because it is too large Load diff

127
Libs/flatbuffers/registry.h Normal file
View file

@ -0,0 +1,127 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_REGISTRY_H_
#define FLATBUFFERS_REGISTRY_H_
#include "flatbuffers/idl.h"
namespace flatbuffers {
// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
// Simply pre-populate it with all schema filenames that may be in use, and
// This class will look them up using the file_identifier declared in the
// schema.
class Registry {
public:
// Call this for all schemas that may be in use. The identifier has
// a function in the generated code, e.g. MonsterIdentifier().
void Register(const char *file_identifier, const char *schema_path) {
Schema schema;
schema.path_ = schema_path;
schemas_[file_identifier] = schema;
}
// Generate text from an arbitrary FlatBuffer by looking up its
// file_identifier in the registry.
bool FlatBufferToText(const uint8_t *flatbuf, size_t len, std::string *dest) {
// Get the identifier out of the buffer.
// If the buffer is truncated, exit.
if (len < sizeof(uoffset_t) + FlatBufferBuilder::kFileIdentifierLength) {
lasterror_ = "buffer truncated";
return false;
}
std::string ident(
reinterpret_cast<const char *>(flatbuf) + sizeof(uoffset_t),
FlatBufferBuilder::kFileIdentifierLength);
// Load and parse the schema.
Parser parser;
if (!LoadSchema(ident, &parser)) return false;
// Now we're ready to generate text.
if (!GenerateText(parser, flatbuf, dest)) {
lasterror_ = "unable to generate text for FlatBuffer binary";
return false;
}
return true;
}
// Converts a binary buffer to text using one of the schemas in the registry,
// use the file_identifier to indicate which.
// If DetachedBuffer::data() is null then parsing failed.
DetachedBuffer TextToFlatBuffer(const char *text,
const char *file_identifier) {
// Load and parse the schema.
Parser parser;
if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
// Parse the text.
if (!parser.Parse(text)) {
lasterror_ = parser.error_;
return DetachedBuffer();
}
// We have a valid FlatBuffer. Detach it from the builder and return.
return parser.builder_.Release();
}
// Modify any parsing / output options used by the other functions.
void SetOptions(const IDLOptions &opts) { opts_ = opts; }
// If schemas used contain include statements, call this function for every
// directory the parser should search them for.
void AddIncludeDirectory(const char *path) { include_paths_.push_back(path); }
// Returns a human readable error if any of the above functions fail.
const std::string &GetLastError() { return lasterror_; }
private:
bool LoadSchema(const std::string &ident, Parser *parser) {
// Find the schema, if not, exit.
auto it = schemas_.find(ident);
if (it == schemas_.end()) {
// Don't attach the identifier, since it may not be human readable.
lasterror_ = "identifier for this buffer not in the registry";
return false;
}
auto &schema = it->second;
// Load the schema from disk. If not, exit.
std::string schematext;
if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
lasterror_ = "could not load schema: " + schema.path_;
return false;
}
// Parse schema.
parser->opts = opts_;
if (!parser->Parse(schematext.c_str(), vector_data(include_paths_),
schema.path_.c_str())) {
lasterror_ = parser->error_;
return false;
}
return true;
}
struct Schema {
std::string path_;
// TODO(wvo) optionally cache schema file or parsed schema here.
};
std::string lasterror_;
IDLOptions opts_;
std::vector<const char *> include_paths_;
std::map<std::string, Schema> schemas_;
};
} // namespace flatbuffers
#endif // FLATBUFFERS_REGISTRY_H_

View file

@ -0,0 +1,715 @@
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_STL_EMULATION_H_
#define FLATBUFFERS_STL_EMULATION_H_
// clang-format off
#include "flatbuffers/base.h"
#include <string>
#include <type_traits>
#include <vector>
#include <memory>
#include <limits>
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
#define FLATBUFFERS_CPP98_STL
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
#if defined(FLATBUFFERS_CPP98_STL)
#include <cctype>
#endif // defined(FLATBUFFERS_CPP98_STL)
// Detect C++17 compatible compiler.
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \
|| (defined(__cplusplus) && __cplusplus >= 201703L) \
|| (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
#include <optional>
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
#define FLATBUFFERS_USE_STD_OPTIONAL
#endif
#endif // defined(FLATBUFFERS_USE_STD_OPTIONAL) ...
// The __cpp_lib_span is the predefined feature macro.
#if defined(FLATBUFFERS_USE_STD_SPAN)
#include <span>
#elif defined(__cpp_lib_span) && defined(__has_include)
#if __has_include(<span>)
#include <span>
#define FLATBUFFERS_USE_STD_SPAN
#endif
#else
// Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined.
#if !defined(FLATBUFFERS_TEMPLATES_ALIASES) || defined(FLATBUFFERS_CPP98_STL)
#define FLATBUFFERS_SPAN_MINIMAL
#else
// Enable implicit construction of a span<T,N> from a std::array<T,N>.
#include <array>
#endif
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
// This header provides backwards compatibility for C++98 STLs like stlport.
namespace flatbuffers {
// Retrieve ::back() from a string in a way that is compatible with pre C++11
// STLs (e.g stlport).
inline char& string_back(std::string &value) {
return value[value.length() - 1];
}
inline char string_back(const std::string &value) {
return value[value.length() - 1];
}
// Helper method that retrieves ::data() from a vector in a way that is
// compatible with pre C++11 STLs (e.g stlport).
template <typename T> inline T *vector_data(std::vector<T> &vector) {
// In some debug environments, operator[] does bounds checking, so &vector[0]
// can't be used.
return vector.empty() ? nullptr : &vector[0];
}
template <typename T> inline const T *vector_data(
const std::vector<T> &vector) {
return vector.empty() ? nullptr : &vector[0];
}
template <typename T, typename V>
inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
#if defined(FLATBUFFERS_CPP98_STL)
vector->push_back(data);
#else
vector->emplace_back(std::forward<V>(data));
#endif // defined(FLATBUFFERS_CPP98_STL)
}
#ifndef FLATBUFFERS_CPP98_STL
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <typename T>
using numeric_limits = std::numeric_limits<T>;
#else
template <typename T> class numeric_limits :
public std::numeric_limits<T> {};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#else
template <typename T> class numeric_limits :
public std::numeric_limits<T> {
public:
// Android NDK fix.
static T lowest() {
return std::numeric_limits<T>::min();
}
};
template <> class numeric_limits<float> :
public std::numeric_limits<float> {
public:
static float lowest() { return -FLT_MAX; }
};
template <> class numeric_limits<double> :
public std::numeric_limits<double> {
public:
static double lowest() { return -DBL_MAX; }
};
template <> class numeric_limits<unsigned long long> {
public:
static unsigned long long min() { return 0ULL; }
static unsigned long long max() { return ~0ULL; }
static unsigned long long lowest() {
return numeric_limits<unsigned long long>::min();
}
};
template <> class numeric_limits<long long> {
public:
static long long min() {
return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
}
static long long max() {
return static_cast<long long>(
(1ULL << ((sizeof(long long) << 3) - 1)) - 1);
}
static long long lowest() {
return numeric_limits<long long>::min();
}
};
#endif // FLATBUFFERS_CPP98_STL
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL
template <typename T> using is_scalar = std::is_scalar<T>;
template <typename T, typename U> using is_same = std::is_same<T,U>;
template <typename T> using is_floating_point = std::is_floating_point<T>;
template <typename T> using is_unsigned = std::is_unsigned<T>;
template <typename T> using is_enum = std::is_enum<T>;
template <typename T> using make_unsigned = std::make_unsigned<T>;
template<bool B, class T, class F>
using conditional = std::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
using true_type = std::true_type;
using false_type = std::false_type;
#else
// Map C++ TR1 templates defined by stlport.
template <typename T> using is_scalar = std::tr1::is_scalar<T>;
template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
template <typename T> using is_floating_point =
std::tr1::is_floating_point<T>;
template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
template <typename T> using is_enum = std::tr1::is_enum<T>;
// Android NDK doesn't have std::make_unsigned or std::tr1::make_unsigned.
template<typename T> struct make_unsigned {
static_assert(is_unsigned<T>::value, "Specialization not implemented!");
using type = T;
};
template<> struct make_unsigned<char> { using type = unsigned char; };
template<> struct make_unsigned<short> { using type = unsigned short; };
template<> struct make_unsigned<int> { using type = unsigned int; };
template<> struct make_unsigned<long> { using type = unsigned long; };
template<>
struct make_unsigned<long long> { using type = unsigned long long; };
template<bool B, class T, class F>
using conditional = std::tr1::conditional<B, T, F>;
template<class T, T v>
using integral_constant = std::tr1::integral_constant<T, v>;
template <bool B>
using bool_constant = integral_constant<bool, B>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
#endif // !FLATBUFFERS_CPP98_STL
#else
// MSVC 2010 doesn't support C++11 aliases.
template <typename T> struct is_scalar : public std::is_scalar<T> {};
template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
template <typename T> struct is_floating_point :
public std::is_floating_point<T> {};
template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
template <typename T> struct is_enum : public std::is_enum<T> {};
template <typename T> struct make_unsigned : public std::make_unsigned<T> {};
template<bool B, class T, class F>
struct conditional : public std::conditional<B, T, F> {};
template<class T, T v>
struct integral_constant : public std::integral_constant<T, v> {};
template <bool B>
struct bool_constant : public integral_constant<bool, B> {};
typedef bool_constant<true> true_type;
typedef bool_constant<false> false_type;
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#ifndef FLATBUFFERS_CPP98_STL
#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
template <class T> using unique_ptr = std::unique_ptr<T>;
#else
// MSVC 2010 doesn't support C++11 aliases.
// We're manually "aliasing" the class here as we want to bring unique_ptr
// into the flatbuffers namespace. We have unique_ptr in the flatbuffers
// namespace we have a completely independent implementation (see below)
// for C++98 STL implementations.
template <class T> class unique_ptr : public std::unique_ptr<T> {
public:
unique_ptr() {}
explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
unique_ptr(unique_ptr&& u) { *this = std::move(u); }
unique_ptr& operator=(std::unique_ptr<T>&& u) {
std::unique_ptr<T>::reset(u.release());
return *this;
}
unique_ptr& operator=(unique_ptr&& u) {
std::unique_ptr<T>::reset(u.release());
return *this;
}
unique_ptr& operator=(T* p) {
return std::unique_ptr<T>::operator=(p);
}
};
#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
#else
// Very limited implementation of unique_ptr.
// This is provided simply to allow the C++ code generated from the default
// settings to function in C++98 environments with no modifications.
template <class T> class unique_ptr {
public:
typedef T element_type;
unique_ptr() : ptr_(nullptr) {}
explicit unique_ptr(T* p) : ptr_(p) {}
unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
reset(const_cast<unique_ptr*>(&u)->release());
}
~unique_ptr() { reset(); }
unique_ptr& operator=(const unique_ptr& u) {
reset(const_cast<unique_ptr*>(&u)->release());
return *this;
}
unique_ptr& operator=(unique_ptr&& u) {
reset(u.release());
return *this;
}
unique_ptr& operator=(T* p) {
reset(p);
return *this;
}
const T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
T* get() const noexcept { return ptr_; }
explicit operator bool() const { return ptr_ != nullptr; }
// modifiers
T* release() {
T* value = ptr_;
ptr_ = nullptr;
return value;
}
void reset(T* p = nullptr) {
T* value = ptr_;
ptr_ = p;
if (value) delete value;
}
void swap(unique_ptr& u) {
T* temp_ptr = ptr_;
ptr_ = u.ptr_;
u.ptr_ = temp_ptr;
}
private:
T* ptr_;
};
template <class T> bool operator==(const unique_ptr<T>& x,
const unique_ptr<T>& y) {
return x.get() == y.get();
}
template <class T, class D> bool operator==(const unique_ptr<T>& x,
const D* y) {
return static_cast<D*>(x.get()) == y;
}
template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
return reinterpret_cast<intptr_t>(x.get()) == y;
}
template <class T> bool operator!=(const unique_ptr<T>& x, decltype(nullptr)) {
return !!x;
}
template <class T> bool operator!=(decltype(nullptr), const unique_ptr<T>& x) {
return !!x;
}
template <class T> bool operator==(const unique_ptr<T>& x, decltype(nullptr)) {
return !x;
}
template <class T> bool operator==(decltype(nullptr), const unique_ptr<T>& x) {
return !x;
}
#endif // !FLATBUFFERS_CPP98_STL
#ifdef FLATBUFFERS_USE_STD_OPTIONAL
template<class T>
using Optional = std::optional<T>;
using nullopt_t = std::nullopt_t;
inline constexpr nullopt_t nullopt = std::nullopt;
#else
// Limited implementation of Optional<T> type for a scalar T.
// This implementation limited by trivial types compatible with
// std::is_arithmetic<T> or std::is_enum<T> type traits.
// A tag to indicate an empty flatbuffers::optional<T>.
struct nullopt_t {
explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {}
};
#if defined(FLATBUFFERS_CONSTEXPR_DEFINED)
namespace internal {
template <class> struct nullopt_holder {
static constexpr nullopt_t instance_ = nullopt_t(0);
};
template<class Dummy>
constexpr nullopt_t nullopt_holder<Dummy>::instance_;
}
static constexpr const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
#else
namespace internal {
template <class> struct nullopt_holder {
static const nullopt_t instance_;
};
template<class Dummy>
const nullopt_t nullopt_holder<Dummy>::instance_ = nullopt_t(0);
}
static const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
#endif
template<class T>
class Optional FLATBUFFERS_FINAL_CLASS {
// Non-scalar 'T' would extremely complicated Optional<T>.
// Use is_scalar<T> checking because flatbuffers flatbuffers::is_arithmetic<T>
// isn't implemented.
static_assert(flatbuffers::is_scalar<T>::value, "unexpected type T");
public:
~Optional() {}
FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT
: value_(), has_value_(false) {}
FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT
: value_(), has_value_(false) {}
FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT
: value_(val), has_value_(true) {}
FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT
: value_(other.value_), has_value_(other.has_value_) {}
FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT {
value_ = other.value_;
has_value_ = other.has_value_;
return *this;
}
FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT {
value_ = T();
has_value_ = false;
return *this;
}
FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT {
value_ = val;
has_value_ = true;
return *this;
}
void reset() FLATBUFFERS_NOEXCEPT {
*this = nullopt;
}
void swap(Optional &other) FLATBUFFERS_NOEXCEPT {
std::swap(value_, other.value_);
std::swap(has_value_, other.has_value_);
}
FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT {
return has_value_;
}
FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT {
return has_value_;
}
FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT {
return value_;
}
const T& value() const {
FLATBUFFERS_ASSERT(has_value());
return value_;
}
T value_or(T default_value) const FLATBUFFERS_NOEXCEPT {
return has_value() ? value_ : default_value;
}
private:
T value_;
bool has_value_;
};
template<class T>
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& opt, nullopt_t) FLATBUFFERS_NOEXCEPT {
return !opt;
}
template<class T>
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional<T>& opt) FLATBUFFERS_NOEXCEPT {
return !opt;
}
template<class T, class U>
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT {
return static_cast<bool>(lhs) && (*lhs == rhs);
}
template<class T, class U>
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
return static_cast<bool>(rhs) && (lhs == *rhs);
}
template<class T, class U>
FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
return static_cast<bool>(lhs) != static_cast<bool>(rhs)
? false
: !static_cast<bool>(lhs) ? false : (*lhs == *rhs);
}
#endif // FLATBUFFERS_USE_STD_OPTIONAL
// Very limited and naive partial implementation of C++20 std::span<T,Extent>.
#if defined(FLATBUFFERS_USE_STD_SPAN)
inline constexpr std::size_t dynamic_extent = std::dynamic_extent;
template<class T, std::size_t Extent = std::dynamic_extent>
using span = std::span<T, Extent>;
#else // !defined(FLATBUFFERS_USE_STD_SPAN)
FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast<std::size_t>(-1);
// Exclude this code if MSVC2010 or non-STL Android is active.
// The non-STL Android doesn't have `std::is_convertible` required for SFINAE.
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
namespace internal {
// This is SFINAE helper class for checking of a common condition:
// > This overload only participates in overload resolution
// > Check whether a pointer to an array of U can be converted
// > to a pointer to an array of E.
// This helper is used for checking of 'U -> const U'.
template<class E, std::size_t Extent, class U, std::size_t N>
struct is_span_convertable {
using type =
typename std::conditional<std::is_convertible<U (*)[], E (*)[]>::value
&& (Extent == dynamic_extent || N == Extent),
int, void>::type;
};
template<typename T>
struct SpanIterator {
// TODO: upgrade to std::random_access_iterator_tag.
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = typename std::remove_cv<T>::type;
using reference = T&;
using pointer = T*;
// Convince MSVC compiler that this iterator is trusted (it is verified).
#ifdef _MSC_VER
using _Unchecked_type = pointer;
#endif // _MSC_VER
SpanIterator(pointer ptr) : ptr_(ptr) {}
reference operator*() const { return *ptr_; }
pointer operator->() { return ptr_; }
SpanIterator& operator++() { ptr_++; return *this; }
SpanIterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }
friend bool operator== (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
friend bool operator!= (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ != rhs.ptr_; }
private:
pointer ptr_;
};
} // namespace internal
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
// T - element type; must be a complete type that is not an abstract
// class type.
// Extent - the number of elements in the sequence, or dynamic.
template<class T, std::size_t Extent = dynamic_extent>
class span FLATBUFFERS_FINAL_CLASS {
public:
typedef T element_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef std::size_t size_type;
static FLATBUFFERS_CONSTEXPR size_type extent = Extent;
// Returns the number of elements in the span.
FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT {
return count_;
}
// Returns the size of the sequence in bytes.
FLATBUFFERS_CONSTEXPR_CPP11
size_type size_bytes() const FLATBUFFERS_NOEXCEPT {
return size() * sizeof(element_type);
}
// Checks if the span is empty.
FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT {
return size() == 0;
}
// Returns a pointer to the beginning of the sequence.
FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT {
return data_;
}
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
using Iterator = internal::SpanIterator<T>;
using ConstIterator = internal::SpanIterator<const T>;
Iterator begin() const { return Iterator(data()); }
Iterator end() const { return Iterator(data() + size()); }
ConstIterator cbegin() const { return ConstIterator(data()); }
ConstIterator cend() const { return ConstIterator(data() + size()); }
#endif
// Returns a reference to the idx-th element of the sequence.
// The behavior is undefined if the idx is greater than or equal to size().
FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const {
return data()[idx];
}
FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT
: data_(other.data_), count_(other.count_) {}
FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other)
FLATBUFFERS_NOEXCEPT {
data_ = other.data_;
count_ = other.count_;
}
// Limited implementation of
// `template <class It> constexpr std::span(It first, size_type count);`.
//
// Constructs a span that is a view over the range [first, first + count);
// the resulting span has: data() == first and size() == count.
// The behavior is undefined if [first, first + count) is not a valid range,
// or if (extent != flatbuffers::dynamic_extent && count != extent).
FLATBUFFERS_CONSTEXPR_CPP11
explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT
: data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)),
count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) {
// Make span empty if the count argument is incompatible with span<T,N>.
}
// Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11
// compliant, it doesn't support default template arguments for functions.
#if defined(FLATBUFFERS_SPAN_MINIMAL)
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
count_(0) {
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
}
#else
// Constructs an empty span whose data() == nullptr and size() == 0.
// This overload only participates in overload resolution if
// extent == 0 || extent == flatbuffers::dynamic_extent.
// A dummy template argument N is need dependency for SFINAE.
template<std::size_t N = 0,
typename internal::is_span_convertable<element_type, Extent, element_type, (N - N)>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
count_(0) {
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
}
// Constructs a span that is a view over the array arr; the resulting span
// has size() == N and data() == std::data(arr). These overloads only
// participate in overload resolution if
// extent == std::dynamic_extent || N == extent is true and
// std::remove_pointer_t<decltype(std::data(arr))>(*)[]
// is convertible to element_type (*)[].
template<std::size_t N,
typename internal::is_span_convertable<element_type, Extent, element_type, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT
: data_(arr), count_(N) {}
template<class U, std::size_t N,
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
: data_(arr.data()), count_(N) {}
//template<class U, std::size_t N,
// int = 0>
//FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
// : data_(arr.data()), count_(N) {}
template<class U, std::size_t N,
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
: data_(arr.data()), count_(N) {}
// Converting constructor from another span s;
// the resulting span has size() == s.size() and data() == s.data().
// This overload only participates in overload resolution
// if extent == std::dynamic_extent || N == extent is true and U (*)[]
// is convertible to element_type (*)[].
template<class U, std::size_t N,
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span<U, N> &s) FLATBUFFERS_NOEXCEPT
: span(s.data(), s.size()) {
}
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
private:
// This is a naive implementation with 'count_' member even if (Extent != dynamic_extent).
pointer const data_;
const size_type count_;
};
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<U, N> make_span(U(&arr)[N]) FLATBUFFERS_NOEXCEPT {
return span<U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const U, N> make_span(const U(&arr)[N]) FLATBUFFERS_NOEXCEPT {
return span<const U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<U, N> make_span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
return span<U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const U, N> make_span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
return span<const U, N>(arr);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<U, dynamic_extent> make_span(U *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
return span<U, dynamic_extent>(first, count);
}
template<class U, std::size_t N>
FLATBUFFERS_CONSTEXPR_CPP11
flatbuffers::span<const U, dynamic_extent> make_span(const U *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
return span<const U, dynamic_extent>(first, count);
}
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
} // namespace flatbuffers
#endif // FLATBUFFERS_STL_EMULATION_H_

703
Libs/flatbuffers/util.h Normal file
View file

@ -0,0 +1,703 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_UTIL_H_
#define FLATBUFFERS_UTIL_H_
#include <errno.h>
#include "flatbuffers/base.h"
#include "flatbuffers/stl_emulation.h"
#ifndef FLATBUFFERS_PREFER_PRINTF
# include <sstream>
#else // FLATBUFFERS_PREFER_PRINTF
# include <float.h>
# include <stdio.h>
#endif // FLATBUFFERS_PREFER_PRINTF
#include <iomanip>
#include <string>
namespace flatbuffers {
// @locale-independent functions for ASCII characters set.
// Fast checking that character lies in closed range: [a <= x <= b]
// using one compare (conditional branch) operator.
inline bool check_ascii_range(char x, char a, char b) {
FLATBUFFERS_ASSERT(a <= b);
// (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`.
// The x, a, b will be promoted to int and subtracted without overflow.
return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a);
}
// Case-insensitive isalpha
inline bool is_alpha(char c) {
// ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF);
}
// Check for uppercase alpha
inline bool is_alpha_upper(char c) { return check_ascii_range(c, 'A', 'Z'); }
// Check (case-insensitive) that `c` is equal to alpha.
inline bool is_alpha_char(char c, char alpha) {
FLATBUFFERS_ASSERT(is_alpha(alpha));
// ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
return ((c & 0xDF) == (alpha & 0xDF));
}
// https://en.cppreference.com/w/cpp/string/byte/isxdigit
// isdigit and isxdigit are the only standard narrow character classification
// functions that are not affected by the currently installed C locale. although
// some implementations (e.g. Microsoft in 1252 codepage) may classify
// additional single-byte characters as digits.
inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); }
inline bool is_xdigit(char c) {
// Replace by look-up table.
return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF);
}
// Case-insensitive isalnum
inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); }
inline char CharToUpper(char c) {
return static_cast<char>(::toupper(static_cast<unsigned char>(c)));
}
inline char CharToLower(char c) {
return static_cast<char>(::tolower(static_cast<unsigned char>(c)));
}
// @end-locale-independent functions for ASCII character set
#ifdef FLATBUFFERS_PREFER_PRINTF
template<typename T> size_t IntToDigitCount(T t) {
size_t digit_count = 0;
// Count the sign for negative numbers
if (t < 0) digit_count++;
// Count a single 0 left of the dot for fractional numbers
if (-1 < t && t < 1) digit_count++;
// Count digits until fractional part
T eps = std::numeric_limits<float>::epsilon();
while (t <= (-1 + eps) || (1 - eps) <= t) {
t /= 10;
digit_count++;
}
return digit_count;
}
template<typename T> size_t NumToStringWidth(T t, int precision = 0) {
size_t string_width = IntToDigitCount(t);
// Count the dot for floating point numbers
if (precision) string_width += (precision + 1);
return string_width;
}
template<typename T>
std::string NumToStringImplWrapper(T t, const char *fmt, int precision = 0) {
size_t string_width = NumToStringWidth(t, precision);
std::string s(string_width, 0x00);
// Allow snprintf to use std::string trailing null to detect buffer overflow
snprintf(const_cast<char *>(s.data()), (s.size() + 1), fmt, string_width, t);
return s;
}
#endif // FLATBUFFERS_PREFER_PRINTF
// Convert an integer or floating point value to a string.
// In contrast to std::stringstream, "char" values are
// converted to a string of digits, and we don't use scientific notation.
template<typename T> std::string NumToString(T t) {
// clang-format off
#ifndef FLATBUFFERS_PREFER_PRINTF
std::stringstream ss;
ss << t;
return ss.str();
#else // FLATBUFFERS_PREFER_PRINTF
auto v = static_cast<long long>(t);
return NumToStringImplWrapper(v, "%.*lld");
#endif // FLATBUFFERS_PREFER_PRINTF
// clang-format on
}
// Avoid char types used as character data.
template<> inline std::string NumToString<signed char>(signed char t) {
return NumToString(static_cast<int>(t));
}
template<> inline std::string NumToString<unsigned char>(unsigned char t) {
return NumToString(static_cast<int>(t));
}
template<> inline std::string NumToString<char>(char t) {
return NumToString(static_cast<int>(t));
}
#if defined(FLATBUFFERS_CPP98_STL)
template<> inline std::string NumToString<long long>(long long t) {
char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2
snprintf(buf, sizeof(buf), "%lld", t);
return std::string(buf);
}
template<>
inline std::string NumToString<unsigned long long>(unsigned long long t) {
char buf[22]; // (log((1 << 63) - 1) / log(10)) + 1
snprintf(buf, sizeof(buf), "%llu", t);
return std::string(buf);
}
#endif // defined(FLATBUFFERS_CPP98_STL)
// Special versions for floats/doubles.
template<typename T> std::string FloatToString(T t, int precision) {
// clang-format off
#ifndef FLATBUFFERS_PREFER_PRINTF
// to_string() prints different numbers of digits for floats depending on
// platform and isn't available on Android, so we use stringstream
std::stringstream ss;
// Use std::fixed to suppress scientific notation.
ss << std::fixed;
// Default precision is 6, we want that to be higher for doubles.
ss << std::setprecision(precision);
ss << t;
auto s = ss.str();
#else // FLATBUFFERS_PREFER_PRINTF
auto v = static_cast<double>(t);
auto s = NumToStringImplWrapper(v, "%0.*f", precision);
#endif // FLATBUFFERS_PREFER_PRINTF
// clang-format on
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
auto p = s.find_last_not_of('0');
if (p != std::string::npos) {
// Strip trailing zeroes. If it is a whole number, keep one zero.
s.resize(p + (s[p] == '.' ? 2 : 1));
}
return s;
}
template<> inline std::string NumToString<double>(double t) {
return FloatToString(t, 12);
}
template<> inline std::string NumToString<float>(float t) {
return FloatToString(t, 6);
}
// Convert an integer value to a hexadecimal string.
// The returned string length is always xdigits long, prefixed by 0 digits.
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
inline std::string IntToStringHex(int i, int xdigits) {
FLATBUFFERS_ASSERT(i >= 0);
// clang-format off
#ifndef FLATBUFFERS_PREFER_PRINTF
std::stringstream ss;
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
<< i;
return ss.str();
#else // FLATBUFFERS_PREFER_PRINTF
return NumToStringImplWrapper(i, "%.*X", xdigits);
#endif // FLATBUFFERS_PREFER_PRINTF
// clang-format on
}
// clang-format off
// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}.
#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
class ClassicLocale {
#ifdef _MSC_VER
typedef _locale_t locale_type;
#else
typedef locale_t locale_type; // POSIX.1-2008 locale_t type
#endif
ClassicLocale();
~ClassicLocale();
locale_type locale_;
static ClassicLocale instance_;
public:
static locale_type Get() { return instance_.locale_; }
};
#ifdef _MSC_VER
#define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get())
#define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get())
#define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get())
#define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get())
#else
#define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get())
#define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get())
#define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get())
#define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get())
#endif
#else
#define __strtod_impl(s, pe) strtod(s, pe)
#define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe))
#ifdef _MSC_VER
#define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b)
#define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b)
#else
#define __strtoull_impl(s, pe, b) strtoull(s, pe, b)
#define __strtoll_impl(s, pe, b) strtoll(s, pe, b)
#endif
#endif
inline void strtoval_impl(int64_t *val, const char *str, char **endptr,
int base) {
*val = __strtoll_impl(str, endptr, base);
}
inline void strtoval_impl(uint64_t *val, const char *str, char **endptr,
int base) {
*val = __strtoull_impl(str, endptr, base);
}
inline void strtoval_impl(double *val, const char *str, char **endptr) {
*val = __strtod_impl(str, endptr);
}
// UBSAN: double to float is safe if numeric_limits<float>::is_iec559 is true.
__supress_ubsan__("float-cast-overflow")
inline void strtoval_impl(float *val, const char *str, char **endptr) {
*val = __strtof_impl(str, endptr);
}
#undef __strtoull_impl
#undef __strtoll_impl
#undef __strtod_impl
#undef __strtof_impl
// clang-format on
// Adaptor for strtoull()/strtoll().
// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9),
// while strtoll with base=0 interprets first leading zero as octal prefix.
// In future, it is possible to add prefixed 0b0101.
// 1) Checks errno code for overflow condition (out of range).
// 2) If base <= 0, function try to detect base of number by prefix.
//
// Return value (like strtoull and strtoll, but reject partial result):
// - If successful, an integer value corresponding to the str is returned.
// - If full string conversion can't be performed, 0 is returned.
// - If the converted value falls out of range of corresponding return type, a
// range error occurs. In this case value MAX(T)/MIN(T) is returned.
template<typename T>
inline bool StringToIntegerImpl(T *val, const char *const str,
const int base = 0,
const bool check_errno = true) {
// T is int64_t or uint64_T
FLATBUFFERS_ASSERT(str);
if (base <= 0) {
auto s = str;
while (*s && !is_digit(*s)) s++;
if (s[0] == '0' && is_alpha_char(s[1], 'X'))
return StringToIntegerImpl(val, str, 16, check_errno);
// if a prefix not match, try base=10
return StringToIntegerImpl(val, str, 10, check_errno);
} else {
if (check_errno) errno = 0; // clear thread-local errno
auto endptr = str;
strtoval_impl(val, str, const_cast<char **>(&endptr), base);
if ((*endptr != '\0') || (endptr == str)) {
*val = 0; // erase partial result
return false; // invalid string
}
// errno is out-of-range, return MAX/MIN
if (check_errno && errno) return false;
return true;
}
}
template<typename T>
inline bool StringToFloatImpl(T *val, const char *const str) {
// Type T must be either float or double.
FLATBUFFERS_ASSERT(str && val);
auto end = str;
strtoval_impl(val, str, const_cast<char **>(&end));
auto done = (end != str) && (*end == '\0');
if (!done) *val = 0; // erase partial result
return done;
}
// Convert a string to an instance of T.
// Return value (matched with StringToInteger64Impl and strtod):
// - If successful, a numeric value corresponding to the str is returned.
// - If full string conversion can't be performed, 0 is returned.
// - If the converted value falls out of range of corresponding return type, a
// range error occurs. In this case value MAX(T)/MIN(T) is returned.
template<typename T> inline bool StringToNumber(const char *s, T *val) {
// Assert on `unsigned long` and `signed long` on LP64.
// If it is necessary, it could be solved with flatbuffers::enable_if<B,T>.
static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T");
FLATBUFFERS_ASSERT(s && val);
int64_t i64;
// The errno check isn't needed, will return MAX/MIN on overflow.
if (StringToIntegerImpl(&i64, s, 0, false)) {
const int64_t max = (flatbuffers::numeric_limits<T>::max)();
const int64_t min = flatbuffers::numeric_limits<T>::lowest();
if (i64 > max) {
*val = static_cast<T>(max);
return false;
}
if (i64 < min) {
// For unsigned types return max to distinguish from
// "no conversion can be performed" when 0 is returned.
*val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min);
return false;
}
*val = static_cast<T>(i64);
return true;
}
*val = 0;
return false;
}
template<> inline bool StringToNumber<int64_t>(const char *str, int64_t *val) {
return StringToIntegerImpl(val, str);
}
template<>
inline bool StringToNumber<uint64_t>(const char *str, uint64_t *val) {
if (!StringToIntegerImpl(val, str)) return false;
// The strtoull accepts negative numbers:
// If the minus sign was part of the input sequence, the numeric value
// calculated from the sequence of digits is negated as if by unary minus
// in the result type, which applies unsigned integer wraparound rules.
// Fix this behaviour (except -0).
if (*val) {
auto s = str;
while (*s && !is_digit(*s)) s++;
s = (s > str) ? (s - 1) : s; // step back to one symbol
if (*s == '-') {
// For unsigned types return the max to distinguish from
// "no conversion can be performed".
*val = (flatbuffers::numeric_limits<uint64_t>::max)();
return false;
}
}
return true;
}
template<> inline bool StringToNumber(const char *s, float *val) {
return StringToFloatImpl(val, s);
}
template<> inline bool StringToNumber(const char *s, double *val) {
return StringToFloatImpl(val, s);
}
inline int64_t StringToInt(const char *s, int base = 10) {
int64_t val;
return StringToIntegerImpl(&val, s, base) ? val : 0;
}
inline uint64_t StringToUInt(const char *s, int base = 10) {
uint64_t val;
return StringToIntegerImpl(&val, s, base) ? val : 0;
}
typedef bool (*LoadFileFunction)(const char *filename, bool binary,
std::string *dest);
typedef bool (*FileExistsFunction)(const char *filename);
LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function);
FileExistsFunction SetFileExistsFunction(
FileExistsFunction file_exists_function);
// Check if file "name" exists.
bool FileExists(const char *name);
// Check if "name" exists and it is also a directory.
bool DirExists(const char *name);
// Load file "name" into "buf" returning true if successful
// false otherwise. If "binary" is false data is read
// using ifstream's text mode, otherwise data is read with
// no transcoding.
bool LoadFile(const char *name, bool binary, std::string *buf);
// Save data "buf" of length "len" bytes into a file
// "name" returning true if successful, false otherwise.
// If "binary" is false data is written using ifstream's
// text mode, otherwise data is written with no
// transcoding.
bool SaveFile(const char *name, const char *buf, size_t len, bool binary);
// Save data "buf" into file "name" returning true if
// successful, false otherwise. If "binary" is false
// data is written using ifstream's text mode, otherwise
// data is written with no transcoding.
inline bool SaveFile(const char *name, const std::string &buf, bool binary) {
return SaveFile(name, buf.c_str(), buf.size(), binary);
}
// Functionality for minimalistic portable path handling.
// The functions below behave correctly regardless of whether posix ('/') or
// Windows ('/' or '\\') separators are used.
// Any new separators inserted are always posix.
FLATBUFFERS_CONSTEXPR char kPathSeparator = '/';
// Returns the path with the extension, if any, removed.
std::string StripExtension(const std::string &filepath);
// Returns the extension, if any.
std::string GetExtension(const std::string &filepath);
// Return the last component of the path, after the last separator.
std::string StripPath(const std::string &filepath);
// Strip the last component of the path + separator.
std::string StripFileName(const std::string &filepath);
// Concatenates a path with a filename, regardless of whether the path
// ends in a separator or not.
std::string ConCatPathFileName(const std::string &path,
const std::string &filename);
// Replaces any '\\' separators with '/'
std::string PosixPath(const char *path);
std::string PosixPath(const std::string &path);
// This function ensure a directory exists, by recursively
// creating dirs for any parts of the path that don't exist yet.
void EnsureDirExists(const std::string &filepath);
// Obtains the absolute path from any other path.
// Returns the input path if the absolute path couldn't be resolved.
std::string AbsolutePath(const std::string &filepath);
// Returns files relative to the --project_root path, prefixed with `//`.
std::string RelativeToRootPath(const std::string &project,
const std::string &filepath);
// To and from UTF-8 unicode conversion functions
// Convert a unicode code point into a UTF-8 representation by appending it
// to a string. Returns the number of bytes generated.
inline int ToUTF8(uint32_t ucc, std::string *out) {
FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set.
// 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8
for (int i = 0; i < 6; i++) {
// Max bits this encoding can represent.
uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i);
if (ucc < (1u << max_bits)) { // does it fit?
// Remaining bits not encoded in the first byte, store 6 bits each
uint32_t remain_bits = i * 6;
// Store first byte:
(*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) |
(ucc >> remain_bits));
// Store remaining bytes:
for (int j = i - 1; j >= 0; j--) {
(*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80);
}
return i + 1; // Return the number of bytes added.
}
}
FLATBUFFERS_ASSERT(0); // Impossible to arrive here.
return -1;
}
// Converts whatever prefix of the incoming string corresponds to a valid
// UTF-8 sequence into a unicode code. The incoming pointer will have been
// advanced past all bytes parsed.
// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in
// this case).
inline int FromUTF8(const char **in) {
int len = 0;
// Count leading 1 bits.
for (int mask = 0x80; mask >= 0x04; mask >>= 1) {
if (**in & mask) {
len++;
} else {
break;
}
}
if ((static_cast<unsigned char>(**in) << len) & 0x80)
return -1; // Bit after leading 1's must be 0.
if (!len) return *(*in)++;
// UTF-8 encoded values with a length are between 2 and 4 bytes.
if (len < 2 || len > 4) { return -1; }
// Grab initial bits of the code.
int ucc = *(*in)++ & ((1 << (7 - len)) - 1);
for (int i = 0; i < len - 1; i++) {
if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0.
ucc <<= 6;
ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code.
}
// UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for
// UTF-16 surrogate pairs).
if (ucc >= 0xD800 && ucc <= 0xDFFF) { return -1; }
// UTF-8 must represent code points in their shortest possible encoding.
switch (len) {
case 2:
// Two bytes of UTF-8 can represent code points from U+0080 to U+07FF.
if (ucc < 0x0080 || ucc > 0x07FF) { return -1; }
break;
case 3:
// Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF.
if (ucc < 0x0800 || ucc > 0xFFFF) { return -1; }
break;
case 4:
// Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF.
if (ucc < 0x10000 || ucc > 0x10FFFF) { return -1; }
break;
}
return ucc;
}
#ifndef FLATBUFFERS_PREFER_PRINTF
// Wraps a string to a maximum length, inserting new lines where necessary. Any
// existing whitespace will be collapsed down to a single space. A prefix or
// suffix can be provided, which will be inserted before or after a wrapped
// line, respectively.
inline std::string WordWrap(const std::string in, size_t max_length,
const std::string wrapped_line_prefix,
const std::string wrapped_line_suffix) {
std::istringstream in_stream(in);
std::string wrapped, line, word;
in_stream >> word;
line = word;
while (in_stream >> word) {
if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) <
max_length) {
line += " " + word;
} else {
wrapped += line + wrapped_line_suffix + "\n";
line = wrapped_line_prefix + word;
}
}
wrapped += line;
return wrapped;
}
#endif // !FLATBUFFERS_PREFER_PRINTF
inline bool EscapeString(const char *s, size_t length, std::string *_text,
bool allow_non_utf8, bool natural_utf8) {
std::string &text = *_text;
text += "\"";
for (uoffset_t i = 0; i < length; i++) {
char c = s[i];
switch (c) {
case '\n': text += "\\n"; break;
case '\t': text += "\\t"; break;
case '\r': text += "\\r"; break;
case '\b': text += "\\b"; break;
case '\f': text += "\\f"; break;
case '\"': text += "\\\""; break;
case '\\': text += "\\\\"; break;
default:
if (c >= ' ' && c <= '~') {
text += c;
} else {
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
const char *utf8 = s + i;
int ucc = FromUTF8(&utf8);
if (ucc < 0) {
if (allow_non_utf8) {
text += "\\x";
text += IntToStringHex(static_cast<uint8_t>(c), 2);
} else {
// There are two cases here:
//
// 1) We reached here by parsing an IDL file. In that case,
// we previously checked for non-UTF-8, so we shouldn't reach
// here.
//
// 2) We reached here by someone calling GenerateText()
// on a previously-serialized flatbuffer. The data might have
// non-UTF-8 Strings, or might be corrupt.
//
// In both cases, we have to give up and inform the caller
// they have no JSON.
return false;
}
} else {
if (natural_utf8) {
// utf8 points to past all utf-8 bytes parsed
text.append(s + i, static_cast<size_t>(utf8 - s - i));
} else if (ucc <= 0xFFFF) {
// Parses as Unicode within JSON's \uXXXX range, so use that.
text += "\\u";
text += IntToStringHex(ucc, 4);
} else if (ucc <= 0x10FFFF) {
// Encode Unicode SMP values to a surrogate pair using two \u
// escapes.
uint32_t base = ucc - 0x10000;
auto high_surrogate = (base >> 10) + 0xD800;
auto low_surrogate = (base & 0x03FF) + 0xDC00;
text += "\\u";
text += IntToStringHex(high_surrogate, 4);
text += "\\u";
text += IntToStringHex(low_surrogate, 4);
}
// Skip past characters recognized.
i = static_cast<uoffset_t>(utf8 - s - 1);
}
}
break;
}
}
text += "\"";
return true;
}
inline std::string BufferToHexText(const void *buffer, size_t buffer_size,
size_t max_length,
const std::string &wrapped_line_prefix,
const std::string &wrapped_line_suffix) {
std::string text = wrapped_line_prefix;
size_t start_offset = 0;
const char *s = reinterpret_cast<const char *>(buffer);
for (size_t i = 0; s && i < buffer_size; i++) {
// Last iteration or do we have more?
bool have_more = i + 1 < buffer_size;
text += "0x";
text += IntToStringHex(static_cast<uint8_t>(s[i]), 2);
if (have_more) { text += ','; }
// If we have more to process and we reached max_length
if (have_more &&
text.size() + wrapped_line_suffix.size() >= start_offset + max_length) {
text += wrapped_line_suffix;
text += '\n';
start_offset = text.size();
text += wrapped_line_prefix;
}
}
text += wrapped_line_suffix;
return text;
}
// Remove paired quotes in a string: "text"|'text' -> text.
std::string RemoveStringQuotes(const std::string &s);
// Change th global C-locale to locale with name <locale_name>.
// Returns an actual locale name in <_value>, useful if locale_name is "" or
// null.
bool SetGlobalTestLocale(const char *locale_name,
std::string *_value = nullptr);
// Read (or test) a value of environment variable.
bool ReadEnvironmentVariable(const char *var_name,
std::string *_value = nullptr);
// MSVC specific: Send all assert reports to STDOUT to prevent CI hangs.
void SetupDefaultCRTReportMode();
} // namespace flatbuffers
#endif // FLATBUFFERS_UTIL_H_

264
Libs/lua/lauxlib.h Normal file
View file

@ -0,0 +1,264 @@
/*
** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
/* key, in the registry, for table of loaded modules */
#define LUA_LOADED_TABLE "_LOADED"
/* key, in the registry, for table of preloaded loaders */
#define LUA_PRELOAD_TABLE "_PRELOAD"
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
#define luaL_checkversion(L) \
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
lua_Integer def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
const char *msg, int level);
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
lua_CFunction openf, int glb);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_newlibtable(L,l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L,l) \
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,arg,extramsg) \
((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *b; /* buffer address */
size_t size; /* buffer size */
size_t n; /* number of characters in buffer */
lua_State *L;
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
((B)->b[(B)->n++] = (c)))
#define luaL_addsize(B,s) ((B)->n += (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
/* }====================================================== */
/*
** {======================================================
** File handles for IO library
** =======================================================
*/
/*
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
** initial structure 'luaL_Stream' (it may contain other fields
** after that initial structure).
*/
#define LUA_FILEHANDLE "FILE*"
typedef struct luaL_Stream {
FILE *f; /* stream (NULL for incompletely created streams) */
lua_CFunction closef; /* to close stream (NULL for closed streams) */
} luaL_Stream;
/* }====================================================== */
/* compatibility with old module system */
#if defined(LUA_COMPAT_MODULE)
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
#endif
/*
** {==================================================================
** "Abstraction Layer" for basic report of messages and errors
** ===================================================================
*/
/* print a string */
#if !defined(lua_writestring)
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
#endif
/* print a newline and flush the output */
#if !defined(lua_writeline)
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
#endif
/* print an error message */
#if !defined(lua_writestringerror)
#define lua_writestringerror(s,p) \
(fprintf(stderr, (s), (p)), fflush(stderr))
#endif
/* }================================================================== */
/*
** {============================================================
** Compatibility with deprecated conversions
** =============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
#define luaL_optunsigned(L,a,d) \
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#endif
/* }============================================================ */
#endif

486
Libs/lua/lua.h Normal file
View file

@ -0,0 +1,486 @@
/*
** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
#ifndef lua_h
#define lua_h
#include <stdarg.h>
#include <stddef.h>
#include "luaconf.h"
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "5"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2018 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
/* mark for precompiled code ('<esc>Lua') */
#define LUA_SIGNATURE "\x1bLua"
/* option for multiple returns in 'lua_pcall' and 'lua_call' */
#define LUA_MULTRET (-1)
/*
** Pseudo-indices
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
** space after that to help overflow detection)
*/
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
/* thread status */
#define LUA_OK 0
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRGCMM 5
#define LUA_ERRERR 6
typedef struct lua_State lua_State;
/*
** basic types
*/
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
#define LUA_NUMTAGS 9
/* minimum Lua stack available to a C function */
#define LUA_MINSTACK 20
/* predefined values in the registry */
#define LUA_RIDX_MAINTHREAD 1
#define LUA_RIDX_GLOBALS 2
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;
/* type for integer functions */
typedef LUA_INTEGER lua_Integer;
/* unsigned integer type */
typedef LUA_UNSIGNED lua_Unsigned;
/* type for continuation-function contexts */
typedef LUA_KCONTEXT lua_KContext;
/*
** Type for C functions registered with Lua
*/
typedef int (*lua_CFunction) (lua_State *L);
/*
** Type for continuation functions
*/
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
/*
** Type for functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
/*
** Type for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** generic extra include file
*/
#if defined(LUA_USER_H)
#include LUA_USER_H
#endif
/*
** RCS ident string
*/
extern const char lua_ident[];
/*
** state manipulation
*/
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
LUA_API const lua_Number *(lua_version) (lua_State *L);
/*
** basic stack manipulation
*/
LUA_API int (lua_absindex) (lua_State *L, int idx);
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
LUA_API int (lua_checkstack) (lua_State *L, int n);
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
/*
** access functions (stack -> C)
*/
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isinteger) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
/*
** Comparison and arithmetic functions
*/
#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
#define LUA_OPSUB 1
#define LUA_OPMUL 2
#define LUA_OPMOD 3
#define LUA_OPPOW 4
#define LUA_OPDIV 5
#define LUA_OPIDIV 6
#define LUA_OPBAND 7
#define LUA_OPBOR 8
#define LUA_OPBXOR 9
#define LUA_OPSHL 10
#define LUA_OPSHR 11
#define LUA_OPUNM 12
#define LUA_OPBNOT 13
LUA_API void (lua_arith) (lua_State *L, int op);
#define LUA_OPEQ 0
#define LUA_OPLT 1
#define LUA_OPLE 2
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
/*
** push functions (C -> stack)
*/
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
/*
** get functions (Lua -> stack)
*/
LUA_API int (lua_getglobal) (lua_State *L, const char *name);
LUA_API int (lua_gettable) (lua_State *L, int idx);
LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawget) (lua_State *L, int idx);
LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API int (lua_getuservalue) (lua_State *L, int idx);
/*
** set functions (stack -> Lua)
*/
LUA_API void (lua_setglobal) (lua_State *L, const char *name);
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API void (lua_setuservalue) (lua_State *L, int idx);
/*
** 'load' and 'call' functions (load and run Lua code)
*/
LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k);
#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k);
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname, const char *mode);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
/*
** coroutine functions
*/
LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
lua_KFunction k);
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
LUA_API int (lua_status) (lua_State *L);
LUA_API int (lua_isyieldable) (lua_State *L);
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
/*
** garbage-collection function and options
*/
#define LUA_GCSTOP 0
#define LUA_GCRESTART 1
#define LUA_GCCOLLECT 2
#define LUA_GCCOUNT 3
#define LUA_GCCOUNTB 4
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCISRUNNING 9
LUA_API int (lua_gc) (lua_State *L, int what, int data);
/*
** miscellaneous functions
*/
LUA_API int (lua_error) (lua_State *L);
LUA_API int (lua_next) (lua_State *L, int idx);
LUA_API void (lua_concat) (lua_State *L, int n);
LUA_API void (lua_len) (lua_State *L, int idx);
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
/*
** {==============================================================
** some useful macros
** ===============================================================
*/
#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
#define lua_pop(L,n) lua_settop(L, -(n)-1)
#define lua_newtable(L) lua_createtable(L, 0, 0)
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
/* }============================================================== */
/*
** {==============================================================
** compatibility macros for unsigned conversions
** ===============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
#endif
/* }============================================================== */
/*
** {======================================================================
** Debug API
** =======================================================================
*/
/*
** Event codes
*/
#define LUA_HOOKCALL 0
#define LUA_HOOKRET 1
#define LUA_HOOKLINE 2
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILCALL 4
/*
** Event masks
*/
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
#define LUA_MASKRET (1 << LUA_HOOKRET)
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
int fidx2, int n2);
LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook (lua_gethook) (lua_State *L);
LUA_API int (lua_gethookmask) (lua_State *L);
LUA_API int (lua_gethookcount) (lua_State *L);
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
const char *source; /* (S) */
int currentline; /* (l) */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
unsigned char nups; /* (u) number of upvalues */
unsigned char nparams;/* (u) number of parameters */
char isvararg; /* (u) */
char istailcall; /* (t) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
struct CallInfo *i_ci; /* active function */
};
/* }====================================================================== */
/******************************************************************************
* Copyright (C) 1994-2018 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#endif

9
Libs/lua/lua.hpp Normal file
View file

@ -0,0 +1,9 @@
// lua.hpp
// Lua header files for C++
// <<extern "C">> not supplied automatically because Lua also compiles as C++
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

BIN
Libs/lua/lua53.lib Normal file

Binary file not shown.

792
Libs/lua/luaconf.h Normal file
View file

@ -0,0 +1,792 @@
/*
** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
#ifndef luaconf_h
#define luaconf_h
#include <limits.h>
#include <stddef.h>
/*
** ===================================================================
** Search for "@@" to find all configurable definitions.
** ===================================================================
*/
/*
** {====================================================================
** System Configuration: macros to adapt (if needed) Lua to some
** particular platform, for instance compiling it with 32-bit numbers or
** restricting it to C89.
** =====================================================================
*/
/*
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
** can also define LUA_32BITS in the make file, but changing here you
** ensure that all software connected to Lua will be compiled with the
** same configuration.
*/
/* #define LUA_32BITS */
/*
@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
** Define it if you want Lua to avoid the use of a few C99 features
** or Windows-specific features on Windows.
*/
/* #define LUA_USE_C89 */
/*
** By default, Lua on Windows use (some) specific Windows features
*/
#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
#endif
#if defined(LUA_USE_WINDOWS)
#define LUA_DL_DLL /* enable support for DLL */
#define LUA_USE_C89 /* broadly, Windows is C89 */
#endif
#if defined(LUA_USE_LINUX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
#define LUA_USE_READLINE /* needs some extra libraries */
#endif
#if defined(LUA_USE_MACOSX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
#define LUA_USE_READLINE /* needs an extra library: -lreadline */
#endif
/*
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
** C89 ('long' and 'double'); Windows always has '__int64', so it does
** not need to use this case.
*/
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
#define LUA_C89_NUMBERS
#endif
/*
@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
*/
/* avoid undefined shifts */
#if ((INT_MAX >> 15) >> 15) >= 1
#define LUAI_BITSINT 32
#else
/* 'int' always must have at least 16 bits */
#define LUAI_BITSINT 16
#endif
/*
@@ LUA_INT_TYPE defines the type for Lua integers.
@@ LUA_FLOAT_TYPE defines the type for Lua floats.
** Lua should work fine with any mix of these options (if supported
** by your C compiler). The usual configurations are 64-bit integers
** and 'double' (the default), 32-bit integers and 'float' (for
** restricted platforms), and 'long'/'double' (for C compilers not
** compliant with C99, which may not have support for 'long long').
*/
/* predefined options for LUA_INT_TYPE */
#define LUA_INT_INT 1
#define LUA_INT_LONG 2
#define LUA_INT_LONGLONG 3
/* predefined options for LUA_FLOAT_TYPE */
#define LUA_FLOAT_FLOAT 1
#define LUA_FLOAT_DOUBLE 2
#define LUA_FLOAT_LONGDOUBLE 3
#if defined(LUA_32BITS) /* { */
/*
** 32-bit integers and 'float'
*/
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
#define LUA_INT_TYPE LUA_INT_INT
#else /* otherwise use 'long' */
#define LUA_INT_TYPE LUA_INT_LONG
#endif
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#elif defined(LUA_C89_NUMBERS) /* }{ */
/*
** largest types available for C89 ('long' and 'double')
*/
#define LUA_INT_TYPE LUA_INT_LONG
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif /* } */
/*
** default configuration for 64-bit Lua ('long long' and 'double')
*/
#if !defined(LUA_INT_TYPE)
#define LUA_INT_TYPE LUA_INT_LONGLONG
#endif
#if !defined(LUA_FLOAT_TYPE)
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif
/* }================================================================== */
/*
** {==================================================================
** Configuration for Paths.
** ===================================================================
*/
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
*/
#define LUA_PATH_SEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXEC_DIR "!"
/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
** Lua libraries.
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
** C libraries.
** CHANGE them if your machine has a non-conventional directory
** hierarchy or if you want to install your libraries in
** non-conventional directories.
*/
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#if defined(_WIN32) /* { */
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
".\\?.lua;" ".\\?\\init.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.dll;" \
LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
LUA_CDIR"loadall.dll;" ".\\?.dll;" \
LUA_CDIR"?53.dll;" ".\\?53.dll"
#else /* }{ */
#define LUA_ROOT "/usr/local/"
#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
"./?.lua;" "./?/init.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so;" \
LUA_CDIR"lib?53.so;" "./lib?53.so"
#endif /* } */
/*
@@ LUA_DIRSEP is the directory separator (for submodules).
** CHANGE it if your machine does not use "/" as the directory separator
** and is not Windows. (On Windows Lua automatically uses "\".)
*/
#if defined(_WIN32)
#define LUA_DIRSEP "\\"
#else
#define LUA_DIRSEP "/"
#endif
/* }================================================================== */
/*
** {==================================================================
** Marks for exported symbols in the C code
** ===================================================================
*/
/*
@@ LUA_API is a mark for all core API functions.
@@ LUALIB_API is a mark for all auxiliary library functions.
@@ LUAMOD_API is a mark for all standard library opening functions.
** CHANGE them if you need to define those functions in some special way.
** For instance, if you want to create one Windows DLL with the core and
** the libraries, you may want to use the following definition (define
** LUA_BUILD_AS_DLL to get it).
*/
#if defined(LUA_BUILD_AS_DLL) /* { */
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
#define LUA_API __declspec(dllexport)
#else /* }{ */
#define LUA_API __declspec(dllimport)
#endif /* } */
#else /* }{ */
#define LUA_API extern
#endif /* } */
/* more often than not the libs go together with the core */
#define LUALIB_API LUA_API
#define LUAMOD_API LUALIB_API
/*
@@ LUAI_FUNC is a mark for all extern functions that are not to be
** exported to outside modules.
@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
** that are not to be exported to outside modules (LUAI_DDEF for
** definitions and LUAI_DDEC for declarations).
** CHANGE them if you need to mark them in some special way. Elf/gcc
** (versions 3.2 and later) mark them as "hidden" to optimize access
** when Lua is compiled as a shared library. Not all elf targets support
** this attribute. Unfortunately, gcc does not offer a way to check
** whether the target offers that support, and those without support
** give a warning about it. To avoid these warnings, change to the
** default definition.
*/
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
defined(__ELF__) /* { */
#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
#else /* }{ */
#define LUAI_FUNC extern
#endif /* } */
#define LUAI_DDEC LUAI_FUNC
#define LUAI_DDEF /* empty */
/* }================================================================== */
/*
** {==================================================================
** Compatibility with previous versions
** ===================================================================
*/
/*
@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
** You can define it to get all options, or change specific options
** to fit your specific needs.
*/
#if defined(LUA_COMPAT_5_2) /* { */
/*
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
** functions in the mathematical library.
*/
#define LUA_COMPAT_MATHLIB
/*
@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
*/
#define LUA_COMPAT_BITLIB
/*
@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
*/
#define LUA_COMPAT_IPAIRS
/*
@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
** luaL_checkint, luaL_checklong, etc.)
*/
#define LUA_COMPAT_APIINTCASTS
#endif /* } */
#if defined(LUA_COMPAT_5_1) /* { */
/* Incompatibilities from 5.2 -> 5.3 */
#define LUA_COMPAT_MATHLIB
#define LUA_COMPAT_APIINTCASTS
/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
*/
#define LUA_COMPAT_UNPACK
/*
@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
** You can replace it with 'package.searchers'.
*/
#define LUA_COMPAT_LOADERS
/*
@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
** You can call your C function directly (with light C functions).
*/
#define lua_cpcall(L,f,u) \
(lua_pushcfunction(L, (f)), \
lua_pushlightuserdata(L,(u)), \
lua_pcall(L,1,0,0))
/*
@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
** You can rewrite 'log10(x)' as 'log(x, 10)'.
*/
#define LUA_COMPAT_LOG10
/*
@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
** library. You can rewrite 'loadstring(s)' as 'load(s)'.
*/
#define LUA_COMPAT_LOADSTRING
/*
@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
*/
#define LUA_COMPAT_MAXN
/*
@@ The following macros supply trivial compatibility for some
** changes in the API. The macros themselves document how to
** change your code to avoid using them.
*/
#define lua_strlen(L,i) lua_rawlen(L, (i))
#define lua_objlen(L,i) lua_rawlen(L, (i))
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
/*
@@ LUA_COMPAT_MODULE controls compatibility with previous
** module functions 'module' (Lua) and 'luaL_register' (C).
*/
#define LUA_COMPAT_MODULE
#endif /* } */
/*
@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
@@ a float mark ('.0').
** This macro is not on by default even in compatibility mode,
** because this is not really an incompatibility.
*/
/* #define LUA_COMPAT_FLOATSTRING */
/* }================================================================== */
/*
** {==================================================================
** Configuration for Numbers.
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs.
** ===================================================================
*/
/*
@@ LUA_NUMBER is the floating-point type used by Lua.
@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number.
@@ l_mathlim(x) corrects limit name 'x' to the proper float type
** by prefixing it with one of FLT/DBL/LDBL.
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
@@ LUA_NUMBER_FMT is the format for writing floats.
@@ lua_number2str converts a float to a string.
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
/* The following definitions are good for most cases here */
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,sz,n) \
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
/*
@@ lua_numbertointeger converts a float number to an integer, or
** returns 0 if float is not within the range of a lua_Integer.
** (The range comparisons are tricky because of rounding. The tests
** here assume a two-complement representation, where MININTEGER always
** has an exact representation as a float; MAXINTEGER may not have one,
** and therefore its conversion to float may have an ill-defined value.)
*/
#define lua_numbertointeger(n,p) \
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
(*(p) = (LUA_INTEGER)(n), 1))
/* now the variable definitions */
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
#define LUA_NUMBER float
#define l_mathlim(n) (FLT_##n)
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.7g"
#define l_mathop(op) op##f
#define lua_str2number(s,p) strtof((s), (p))
#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
#define LUA_NUMBER long double
#define l_mathlim(n) (LDBL_##n)
#define LUAI_UACNUMBER long double
#define LUA_NUMBER_FRMLEN "L"
#define LUA_NUMBER_FMT "%.19Lg"
#define l_mathop(op) op##l
#define lua_str2number(s,p) strtold((s), (p))
#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
#define LUA_NUMBER double
#define l_mathlim(n) (DBL_##n)
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
#define LUA_NUMBER_FMT "%.14g"
#define l_mathop(op) op
#define lua_str2number(s,p) strtod((s), (p))
#else /* }{ */
#error "numeric float type not defined"
#endif /* } */
/*
@@ LUA_INTEGER is the integer type used by Lua.
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
@@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a lUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ LUA_INTEGER_FMT is the format for writing integers.
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
@@ lua_integer2str converts an integer to a string.
*/
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
#define LUAI_UACINT LUA_INTEGER
#define lua_integer2str(s,sz,n) \
l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
/*
** use LUAI_UACINT here to avoid problems with promotions (which
** can turn a comparison between unsigneds into a signed comparison)
*/
#define LUA_UNSIGNED unsigned LUAI_UACINT
/* now the variable definitions */
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
#define LUA_MAXINTEGER INT_MAX
#define LUA_MININTEGER INT_MIN
#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
#define LUA_MAXINTEGER LONG_MAX
#define LUA_MININTEGER LONG_MIN
#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#if defined(LLONG_MAX) /* { */
/* use ISO C99 stuff */
#define LUA_INTEGER long long
#define LUA_INTEGER_FRMLEN "ll"
#define LUA_MAXINTEGER LLONG_MAX
#define LUA_MININTEGER LLONG_MIN
#elif defined(LUA_USE_WINDOWS) /* }{ */
/* in Windows, can use specific Windows types */
#define LUA_INTEGER __int64
#define LUA_INTEGER_FRMLEN "I64"
#define LUA_MAXINTEGER _I64_MAX
#define LUA_MININTEGER _I64_MIN
#else /* }{ */
#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
#endif /* } */
#else /* }{ */
#error "numeric integer type not defined"
#endif /* } */
/* }================================================================== */
/*
** {==================================================================
** Dependencies with C99 and other C details
** ===================================================================
*/
/*
@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
** (All uses in Lua have only one format item.)
*/
#if !defined(LUA_USE_C89)
#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
#else
#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
#endif
/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does that conversion. Otherwise, you can
** leave 'lua_strx2number' undefined and Lua will provide its own
** implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_strx2number(s,p) lua_str2number(s,p)
#endif
/*
@@ lua_pointer2str converts a pointer to a readable string in a
** non-specified way.
*/
#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p)
/*
@@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) \
((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#endif
/*
** 'strtof' and 'opf' variants for math functions are not valid in
** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
** availability of these variants. ('math.h' is already included in
** all files that use these macros.)
*/
#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
#undef l_mathop /* variants not available */
#undef lua_str2number
#define l_mathop(op) (lua_Number)op /* no variant */
#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
#endif
/*
@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
** functions. It must be a numerical type; Lua will use 'intptr_t' if
** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
** 'intptr_t' in C89)
*/
#define LUA_KCONTEXT ptrdiff_t
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined(INTPTR_MAX) /* even in C99 this type is optional */
#undef LUA_KCONTEXT
#define LUA_KCONTEXT intptr_t
#endif
#endif
/*
@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
** Change that if you do not want to use C locales. (Code using this
** macro must include header 'locale.h'.)
*/
#if !defined(lua_getlocaledecpoint)
#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
/* }================================================================== */
/*
** {==================================================================
** Language Variations
** =====================================================================
*/
/*
@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
** coercion from strings to numbers.
*/
/* #define LUA_NOCVTN2S */
/* #define LUA_NOCVTS2N */
/*
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
** Define it as a help when debugging C code.
*/
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(l,e) assert(e)
#endif
/* }================================================================== */
/*
** {==================================================================
** Macros that affect the API and must be stable (that is, must be the
** same when you compile Lua and when you compile code that links to
** Lua). You probably do not want/need to change them.
** =====================================================================
*/
/*
@@ LUAI_MAXSTACK limits the size of the Lua stack.
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
*/
#if LUAI_BITSINT >= 32
#define LUAI_MAXSTACK 1000000
#else
#define LUAI_MAXSTACK 15000
#endif
/*
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
** a Lua state with very fast access.
** CHANGE it if you need a different size.
*/
#define LUA_EXTRASPACE (sizeof(void *))
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** CHANGE it if it uses too much C-stack space. (For long double,
** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a
** smaller buffer would force a memory allocation for each call to
** 'string.format'.)
*/
#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
#define LUAL_BUFFERSIZE 8192
#else
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
#endif
/* }================================================================== */
/*
@@ LUA_QL describes how error messages quote program elements.
** Lua does not use these macros anymore; they are here for
** compatibility only.
*/
#define LUA_QL(x) "'" x "'"
#define LUA_QS LUA_QL("%s")
/* =================================================================== */
/*
** Local configuration. You can use this space to add your redefinitions
** without modifying the main part of the file.
*/
#endif

61
Libs/lua/lualib.h Normal file
View file

@ -0,0 +1,61 @@
/*
** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
#ifndef lualib_h
#define lualib_h
#include "lua.h"
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
LUAMOD_API int (luaopen_base) (lua_State *L);
#define LUA_COLIBNAME "coroutine"
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
#define LUA_TABLIBNAME "table"
LUAMOD_API int (luaopen_table) (lua_State *L);
#define LUA_IOLIBNAME "io"
LUAMOD_API int (luaopen_io) (lua_State *L);
#define LUA_OSLIBNAME "os"
LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUAMOD_API int (luaopen_string) (lua_State *L);
#define LUA_UTF8LIBNAME "utf8"
LUAMOD_API int (luaopen_utf8) (lua_State *L);
#define LUA_BITLIBNAME "bit32"
LUAMOD_API int (luaopen_bit32) (lua_State *L);
#define LUA_MATHLIBNAME "math"
LUAMOD_API int (luaopen_math) (lua_State *L);
#define LUA_DBLIBNAME "debug"
LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_LOADLIBNAME "package"
LUAMOD_API int (luaopen_package) (lua_State *L);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
#endif

56
Libs/sol/config.hpp Normal file
View file

@ -0,0 +1,56 @@
// The MIT License (MIT)
// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2020-10-15 05:19:08.645208 UTC
// This header was generated with sol v3.2.3 (revision e5e6466e)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_CONFIG_HPP
#define SOL_SINGLE_CONFIG_HPP
// beginning of sol/config.hpp
/* Base, empty configuration file!
To override, place a file in your include paths of the form:
. (your include path here)
| sol (directory, or equivalent)
| config.hpp (your config.hpp file)
So that when sol2 includes the file
#include <sol/config.hpp>
it gives you the configuration values you desire. Configuration values can be
seen in the safety.rst of the doc/src, or at
https://sol2.readthedocs.io/en/latest/safety.html ! You can also pass them through
the build system, or the command line options of your compiler.
*/
// Don't error if user scripts give floats where ints are needed; just truncate
#define SOL_NO_CHECK_NUMBER_PRECISION 1
// end of sol/config.hpp
#endif // SOL_SINGLE_CONFIG_HPP

889
Libs/sol/forward.hpp Normal file
View file

@ -0,0 +1,889 @@
// The MIT License (MIT)
// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2020-10-15 05:19:08.633139 UTC
// This header was generated with sol v3.2.3 (revision e5e6466e)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
#define SOL_SINGLE_INCLUDE_FORWARD_HPP
// beginning of sol/forward.hpp
#ifndef SOL_FORWARD_HPP
#define SOL_FORWARD_HPP
// beginning of sol/version.hpp
#include <sol/config.hpp>
#include <cstdint>
#define SOL_VERSION_MAJOR 3
#define SOL_VERSION_MINOR 2
#define SOL_VERSION_PATCH 3
#define SOL_VERSION_STRING "3.2.3"
#define SOL_VERSION ((SOL_VERSION_MAJOR * 100000) + (SOL_VERSION_MINOR * 100) + (SOL_VERSION_PATCH))
#define SOL_IS_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) != 0)
#define SOL_IS_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3) == 0)
#define SOL_IS_DEFAULT_ON(OP_SYMBOL) ((3 OP_SYMBOL 3) > 3)
#define SOL_IS_DEFAULT_OFF(OP_SYMBOL) ((3 OP_SYMBOL 3 OP_SYMBOL 3) < 0)
#define SOL_ON |
#define SOL_OFF ^
#define SOL_DEFAULT_ON +
#define SOL_DEFAULT_OFF -
#if defined(_MSC_VER)
#define SOL_COMPILER_CLANG_I_ SOL_OFF
#define SOL_COMPILER_GCC_I_ SOL_OFF
#define SOL_COMPILER_EDG_I_ SOL_OFF
#define SOL_COMPILER_VCXX_I_ SOL_ON
#elif defined(__clang__)
#define SOL_COMPILER_CLANG_I_ SOL_ON
#define SOL_COMPILER_GCC_I_ SOL_OFF
#define SOL_COMPILER_EDG_I_ SOL_OFF
#define SOL_COMPILER_VCXX_I_ SOL_OFF
#elif defined(__GNUC__)
#define SOL_COMPILER_CLANG_I_ SOL_OFF
#define SOL_COMPILER_GCC_I_ SOL_ON
#define SOL_COMPILER_EDG_I_ SOL_OFF
#define SOL_COMPILER_VCXX_I_ SOL_OFF
#else
#define SOL_COMPILER_CLANG_I_ SOL_OFF
#define SOL_COMPILER_GCC_I_ SOL_OFF
#define SOL_COMPILER_EDG_I_ SOL_OFF
#define SOL_COMPILER_VCXX_I_ SOL_OFF
#endif
#if defined(__MINGW32__)
#define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_ON
#else
#define SOL_COMPILER_FRONTEND_MINGW_I_ SOL_OFF
#endif
#if SIZE_MAX <= 0xFFFFULL
#define SOL_PLATFORM_X16_I_ SOL_ON
#define SOL_PLATFORM_X86_I_ SOL_OFF
#define SOL_PLATFORM_X64_I_ SOL_OFF
#elif SIZE_MAX <= 0xFFFFFFFFULL
#define SOL_PLATFORM_X16_I_ SOL_OFF
#define SOL_PLATFORM_X86_I_ SOL_ON
#define SOL_PLATFORM_X64_I_ SOL_OFF
#else
#define SOL_PLATFORM_X16_I_ SOL_OFF
#define SOL_PLATFORM_X86_I_ SOL_OFF
#define SOL_PLATFORM_X64_I_ SOL_ON
#endif
#define SOL_PLATFORM_ARM32_I_ SOL_OFF
#define SOL_PLATFORM_ARM64_I_ SOL_OFF
#if defined(_WIN32)
#define SOL_PLATFORM_WINDOWS_I_ SOL_ON
#else
#define SOL_PLATFORM_WINDOWS_I_ SOL_OFF
#endif
#if defined(__APPLE__)
#define SOL_PLATFORM_APPLE_I_ SOL_ON
#else
#define SOL_PLATFORM_APPLE_I_ SOL_OFF
#endif
#if defined(__unix__)
#define SOL_PLATFORM_UNIXLIKE_I_ SOL_ON
#else
#define SOL_PLATFORM_UNIXLIKE_I_ SOL_OFF
#endif
#if defined(__linux__)
#define SOL_PLATFORM_LINUXLIKE_I_ SOL_ON
#else
#define SOL_PLATFORM_LINUXLIKE_I_ SOL_OFF
#endif
#define SOL_PLATFORM_APPLE_IPHONE_I_ SOL_OFF
#define SOL_PLATFORM_BSDLIKE_I_ SOL_OFF
#if defined(SOL_IN_DEBUG_DETECTED)
#if SOL_IN_DEBUG_DETECTED != 0
#define SOL_DEBUG_BUILD_I_ SOL_ON
#else
#define SOL_DEBUG_BUILD_I_ SOL_OFF
#endif
#elif !defined(NDEBUG)
#if SOL_IS_ON(SOL_COMPILER_VCXX_I_) && defined(_DEBUG)
#define SOL_DEBUG_BUILD_I_ SOL_ON
#elif (SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)) && !defined(__OPTIMIZE__)
#define SOL_DEBUG_BUILD_I_ SOL_ON
#else
#define SOL_DEBUG_BUILD_I_ SOL_OFF
#endif
#else
#define SOL_DEBUG_BUILD_I_ SOL_DEFAULT_OFF
#endif // We are in a debug mode of some sort
#if defined(SOL_NO_EXCEPTIONS)
#if (SOL_NO_EXCEPTIONS != 0)
#define SOL_EXCEPTIONS_I_ SOL_OFF
#else
#define SOL_EXCEPTIONS_I_ SOL_ON
#endif
#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)
#if !defined(_CPPUNWIND)
#define SOL_EXCEPTIONS_I_ SOL_OFF
#else
#define SOL_EXCEPTIONS_I_ SOL_ON
#endif
#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)
#if !defined(__EXCEPTIONS)
#define SOL_EXCEPTIONS_I_ SOL_OFF
#else
#define SOL_EXCEPTIONS_I_ SOL_ON
#endif
#else
#define SOL_EXCEPTIONS_I_ SOL_DEFAULT_ON
#endif
#if defined(SOL_NO_RTTI)
#if (SOL_NO_RTTI != 0)
#define SOL_RTTI_I_ SOL_OFF
#else
#define SOL_RTTI_I_ SOL_ON
#endif
#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_)
#if !defined(_CPPRTTI)
#define SOL_RTTI_I_ SOL_OFF
#else
#define SOL_RTTI_I_ SOL_ON
#endif
#elif SOL_IS_ON(SOL_COMPILER_CLANG_I_) || SOL_IS_ON(SOL_COMPILER_GCC_I_)
#if !defined(__GXX_RTTI)
#define SOL_RTTI_I_ SOL_OFF
#else
#define SOL_RTTI_I_ SOL_ON
#endif
#else
#define SOL_RTTI_I_ SOL_DEFAULT_ON
#endif
#if defined(SOL_NO_THREAD_LOCAL)
#if SOL_NO_THREAD_LOCAL != 0
#define SOL_USE_THREAD_LOCAL_I_ SOL_OFF
#else
#define SOL_USE_THREAD_LOCAL_I_ SOL_ON
#endif
#else
#define SOL_USE_THREAD_LOCAL_I_ SOL_DEFAULT_ON
#endif // thread_local keyword is bjorked on some platforms
#if defined(SOL_ALL_SAFETIES_ON)
#if SOL_ALL_SAFETIES_ON != 0
#define SOL_ALL_SAFETIES_ON_I_ SOL_ON
#else
#define SOL_ALL_SAFETIES_ON_I_ SOL_FF
#endif
#else
#define SOL_ALL_SAFETIES_ON_I_ SOL_DEFAULT_OFF
#endif
#if defined(SOL_SAFE_GETTER)
#if SOL_SAFE_GETTER != 0
#define SOL_SAFE_GETTER_I_ SOL_ON
#else
#define SOL_SAFE_GETTER_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_GETTER_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_GETTER_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_GETTER_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_USERTYPE)
#if SOL_SAFE_USERTYPE != 0
#define SOL_SAFE_USERTYPE_I_ SOL_ON
#else
#define SOL_SAFE_USERTYPE_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_USERTYPE_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_USERTYPE_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_REFERENCES)
#if SOL_SAFE_REFERENCES != 0
#define SOL_SAFE_REFERENCES_I_ SOL_ON
#else
#define SOL_SAFE_REFERENCES_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_REFERENCES_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_REFERENCES_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_FUNCTIONS)
#if SOL_SAFE_FUNCTIONS != 0
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON
#else
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF
#endif
#elif defined (SOL_SAFE_FUNCTION_OBJECTS)
#if SOL_SAFE_FUNCTION_OBJECTS != 0
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON
#else
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_FUNCTION_OBJECTS_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_FUNCTION_CALLS)
#if SOL_SAFE_FUNCTION_CALLS != 0
#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON
#else
#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_FUNCTION_CALLS_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_PROXIES)
#if SOL_SAFE_PROXIES != 0
#define SOL_SAFE_PROXIES_I_ SOL_ON
#else
#define SOL_SAFE_PROXIES_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_PROXIES_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_PROXIES_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_NUMERICS)
#if SOL_SAFE_NUMERICS != 0
#define SOL_SAFE_NUMERICS_I_ SOL_ON
#else
#define SOL_SAFE_NUMERICS_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_NUMERICS_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_NUMERICS_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_SAFE_STACK_CHECK)
#if SOL_SAFE_STACK_CHECK != 0
#define SOL_SAFE_STACK_CHECK_I_ SOL_ON
#else
#define SOL_SAFE_STACK_CHECK_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_SAFE_STACK_CHECK_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_ON
#else
#define SOL_SAFE_STACK_CHECK_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_NO_CHECK_NUMBER_PRECISION)
#if SOL_NO_CHECK_NUMBER_PRECISION != 0
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF
#else
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON
#endif
#elif defined(SOL_NO_CHECKING_NUMBER_PRECISION)
#if SOL_NO_CHECKING_NUMBER_PRECISION != 0
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_OFF
#else
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON
#elif SOL_IS_ON(SOL_SAFE_NUMERICS_I_)
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_ON
#else
#define SOL_NUMBER_PRECISION_CHECKS_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_STRINGS_ARE_NUMBERS)
#if (SOL_STRINGS_ARE_NUMBERS != 0)
#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_ON
#else
#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_OFF
#endif
#else
#define SOL_STRINGS_ARE_NUMBERS_I_ SOL_DEFAULT_OFF
#endif
#if defined(SOL_ENABLE_INTEROP)
#if SOL_ENABLE_INTEROP != 0
#define SOL_USE_INTEROP_I_ SOL_ON
#else
#define SOL_USE_INTEROP_I_ SOL_OFF
#endif
#elif defined(SOL_USE_INTEROP)
#if SOL_USE_INTEROP != 0
#define SOL_USE_INTEROP_I_ SOL_ON
#else
#define SOL_USE_INTEROP_I_ SOL_OFF
#endif
#else
#define SOL_USE_INTEROP_I_ SOL_DEFAULT_OFF
#endif
#if defined(SOL_NO_NIL)
#if (SOL_NO_NIL != 0)
#define SOL_NIL_I_ SOL_OFF
#else
#define SOL_NIL_I_ SOL_ON
#endif
#elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)
#define SOL_NIL_I_ SOL_DEFAULT_OFF
#else
#define SOL_NIL_I_ SOL_DEFAULT_ON
#endif
#if defined(SOL_USERTYPE_TYPE_BINDING_INFO)
#if (SOL_USERTYPE_TYPE_BINDING_INFO != 0)
#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_ON
#else
#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_OFF
#endif
#else
#define SOL_USERTYPE_TYPE_BINDING_INFO_I_ SOL_DEFAULT_ON
#endif // We should generate a my_type.__type table with lots of class information for usertypes
#if defined(SOL_AUTOMAGICAL_TYPES_BY_DEFAULT)
#if (SOL_AUTOMAGICAL_TYPES_BY_DEFAULT != 0)
#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON
#else
#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF
#endif
#elif defined(SOL_DEFAULT_AUTOMAGICAL_USERTYPES)
#if (SOL_DEFAULT_AUTOMAGICAL_USERTYPES != 0)
#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_ON
#else
#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_OFF
#endif
#else
#define SOL_DEFAULT_AUTOMAGICAL_USERTYPES_I_ SOL_DEFAULT_ON
#endif // make is_automagical on/off by default
#if defined(SOL_STD_VARIANT)
#if (SOL_STD_VARIANT != 0)
#define SOL_STD_VARIANT_I_ SOL_ON
#else
#define SOL_STD_VARIANT_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_COMPILER_CLANG_I_) && SOL_IS_ON(SOL_PLATFORM_APPLE_I_)
#if defined(__has_include)
#if __has_include(<variant>)
#define SOL_STD_VARIANT_I_ SOL_ON
#else
#define SOL_STD_VARIANT_I_ SOL_OFF
#endif
#else
#define SOL_STD_VARIANT_I_ SOL_OFF
#endif
#else
#define SOL_STD_VARIANT_I_ SOL_DEFAULT_ON
#endif
#endif // make is_automagical on/off by default
#if defined(SOL_NOEXCEPT_FUNCTION_TYPE)
#if (SOL_NOEXCEPT_FUNCTION_TYPE != 0)
#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON
#else
#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF
#endif
#else
#if defined(__cpp_noexcept_function_type)
#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_ON
#elif SOL_IS_ON(SOL_COMPILER_VCXX_I_) && (defined(_MSVC_LANG) && (_MSVC_LANG < 201403L))
// There is a bug in the VC++ compiler??
// on /std:c++latest under x86 conditions (VS 15.5.2),
// compiler errors are tossed for noexcept markings being on function types
// that are identical in every other way to their non-noexcept marked types function types...
// VS 2019: There is absolutely a bug.
#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_OFF
#else
#define SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_ SOL_DEFAULT_ON
#endif
#endif // noexcept is part of a function's type
#if defined(SOL_STACK_STRING_OPTIMIZATION_SIZE) && SOL_STACK_STRING_OPTIMIZATION_SIZE > 0
#define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ SOL_STACK_STRING_OPTIMIZATION_SIZE
#else
#define SOL_OPTIMIZATION_STRING_CONVERSION_STACK_SIZE_I_ 1024
#endif
#if defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0
#define SOL_ID_SIZE_I_ SOL_ID_SIZE
#else
#define SOL_ID_SIZE_I_ 512
#endif
#if defined(LUA_IDSIZE) && LUA_IDSIZE > 0
#define SOL_FILE_ID_SIZE_I_ LUA_IDSIZE
#elif defined(SOL_ID_SIZE) && SOL_ID_SIZE > 0
#define SOL_FILE_ID_SIZE_I_ SOL_FILE_ID_SIZE
#else
#define SOL_FILE_ID_SIZE_I_ 2048
#endif
#if defined(SOL_PRINT_ERRORS)
#if (SOL_PRINT_ERRORS != 0)
#define SOL_PRINT_ERRORS_I_ SOL_ON
#else
#define SOL_PRINT_ERRORS_I_ SOL_OFF
#endif
#else
#if SOL_IS_ON(SOL_ALL_SAFETIES_ON_I_)
#define SOL_PRINT_ERRORS_I_ SOL_ON
#elif SOL_IS_ON(SOL_DEBUG_BUILD_I_)
#define SOL_PRINT_ERRORS_I_ SOL_DEFAULT_ON
#else
#define SOL_PRINT_ERRORS_I_ SOL_OFF
#endif
#endif
#if defined(SOL_DEFAULT_PASS_ON_ERROR)
#if (SOL_DEFAULT_PASS_ON_ERROR != 0)
#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_ON
#else
#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_OFF
#endif
#else
#define SOL_DEFAULT_PASS_ON_ERROR_I_ SOL_DEFAULT_OFF
#endif
#if defined(SOL_USING_CXX_LUA)
#if (SOL_USING_CXX_LUA != 0)
#define SOL_USE_CXX_LUA_I_ SOL_ON
#else
#define SOL_USE_CXX_LUA_I_ SOL_OFF
#endif
#elif defined(SOL_USE_CXX_LUA)
#if (SOL_USE_CXX_LUA != 0)
#define SOL_USE_CXX_LUA_I_ SOL_ON
#else
#define SOL_USE_CXX_LUA_I_ SOL_OFF
#endif
#else
#define SOL_USE_CXX_LUA_I_ SOL_OFF
#endif
#if defined(SOL_USING_CXX_LUAJIT)
#if (SOL_USING_CXX_LUA != 0)
#define SOL_USE_CXX_LUAJIT_I_ SOL_ON
#else
#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF
#endif
#elif defined(SOL_USE_CXX_LUAJIT)
#if (SOL_USE_CXX_LUA != 0)
#define SOL_USE_CXX_LUAJIT_I_ SOL_ON
#else
#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF
#endif
#else
#define SOL_USE_CXX_LUAJIT_I_ SOL_OFF
#endif
#if defined(SOL_NO_LUA_HPP)
#if (SOL_NO_LUA_HPP != 0)
#define SOL_USE_LUA_HPP_I_ SOL_OFF
#else
#define SOL_USE_LUA_HPP_I_ SOL_ON
#endif
#elif defined(SOL_USING_CXX_LUA)
#define SOL_USE_LUA_HPP_I_ SOL_OFF
#elif defined(__has_include)
#if __has_include(<lua.hpp>)
#define SOL_USE_LUA_HPP_I_ SOL_ON
#else
#define SOL_USE_LUA_HPP_I_ SOL_OFF
#endif
#else
#define SOL_USE_LUA_HPP_I_ SOL_DEFAULT_ON
#endif
#if defined(SOL_CONTAINERS_START)
#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START
#elif defined(SOL_CONTAINERS_START_INDEX)
#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINERS_START_INDEX
#elif defined(SOL_CONTAINER_START_INDEX)
#define SOL_CONTAINER_START_INDEX_I_ SOL_CONTAINER_START_INDEX
#else
#define SOL_CONTAINER_START_INDEX_I_ 1
#endif
#if defined (SOL_NO_MEMORY_ALIGNMENT)
#if (SOL_NO_MEMORY_ALIGNMENT != 0)
#define SOL_ALIGN_MEMORY_I_ SOL_OFF
#else
#define SOL_ALIGN_MEMORY_I_ SOL_ON
#endif
#else
#define SOL_ALIGN_MEMORY_I_ SOL_DEFAULT_ON
#endif
#if defined(SOL_USE_BOOST)
#if (SOL_USE_BOOST != 0)
#define SOL_USE_BOOST_I_ SOL_ON
#else
#define SOL_USE_BOOST_I_ SOL_OFF
#endif
#else
#define SOL_USE_BOOST_I_ SOL_OFF
#endif
#if defined(SOL_USE_UNSAFE_BASE_LOOKUP)
#if (SOL_USE_UNSAFE_BASE_LOOKUP != 0)
#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_ON
#else
#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF
#endif
#else
#define SOL_USE_UNSAFE_BASE_LOOKUP_I_ SOL_OFF
#endif
#if defined(SOL_INSIDE_UNREAL)
#if (SOL_INSIDE_UNREAL != 0)
#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON
#else
#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_OFF
#endif
#else
#if defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || defined(UE_BUILD_SHIPPING) || defined(UE_SERVER)
#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_ON
#else
#define SOL_INSIDE_UNREAL_ENGINE_I_ SOL_DEFAULT_OFF
#endif
#endif
#if defined(SOL_NO_COMPAT)
#if (SOL_NO_COMPAT != 0)
#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_OFF
#else
#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_ON
#endif
#else
#define SOL_USE_COMPATIBILITY_LAYER_I_ SOL_DEFAULT_ON
#endif
#if defined(SOL_GET_FUNCTION_POINTER_UNSAFE)
#if (SOL_GET_FUNCTION_POINTER_UNSAFE != 0)
#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_ON
#else
#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_OFF
#endif
#else
#define SOL_GET_FUNCTION_POINTER_UNSAFE_I_ SOL_DEFAULT_OFF
#endif
#if SOL_IS_ON(SOL_COMPILER_FRONTEND_MINGW_I_) && defined(__GNUC__) && (__GNUC__ < 6)
// MinGW is off its rocker in some places...
#define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_ON
#else
#define SOL_MINGW_CCTYPE_IS_POISONED_I_ SOL_DEFAULT_OFF
#endif
// end of sol/version.hpp
#include <utility>
#include <type_traits>
#include <string_view>
#if SOL_IS_ON(SOL_USE_CXX_LUA_I_) || SOL_IS_ON(SOL_USE_CXX_LUAJIT_I_)
struct lua_State;
#else
extern "C" {
struct lua_State;
}
#endif // C++ Mangling for Lua vs. Not
namespace sol {
enum class type;
class stateless_reference;
template <bool b>
class basic_reference;
using reference = basic_reference<false>;
using main_reference = basic_reference<true>;
class stateless_stack_reference;
class stack_reference;
template <typename A>
class basic_bytecode;
struct lua_value;
struct proxy_base_tag;
template <typename>
struct proxy_base;
template <typename, typename>
struct table_proxy;
template <bool, typename>
class basic_table_core;
template <bool b>
using table_core = basic_table_core<b, reference>;
template <bool b>
using main_table_core = basic_table_core<b, main_reference>;
template <bool b>
using stack_table_core = basic_table_core<b, stack_reference>;
template <typename base_type>
using basic_table = basic_table_core<false, base_type>;
using table = table_core<false>;
using global_table = table_core<true>;
using main_table = main_table_core<false>;
using main_global_table = main_table_core<true>;
using stack_table = stack_table_core<false>;
using stack_global_table = stack_table_core<true>;
template <typename>
struct basic_lua_table;
using lua_table = basic_lua_table<reference>;
using stack_lua_table = basic_lua_table<stack_reference>;
template <typename T, typename base_type>
class basic_usertype;
template <typename T>
using usertype = basic_usertype<T, reference>;
template <typename T>
using stack_usertype = basic_usertype<T, stack_reference>;
template <typename base_type>
class basic_metatable;
using metatable = basic_metatable<reference>;
using stack_metatable = basic_metatable<stack_reference>;
template <typename base_t>
struct basic_environment;
using environment = basic_environment<reference>;
using main_environment = basic_environment<main_reference>;
using stack_environment = basic_environment<stack_reference>;
template <typename T, bool>
class basic_function;
template <typename T, bool, typename H>
class basic_protected_function;
using unsafe_function = basic_function<reference, false>;
using safe_function = basic_protected_function<reference, false, reference>;
using main_unsafe_function = basic_function<main_reference, false>;
using main_safe_function = basic_protected_function<main_reference, false, reference>;
using stack_unsafe_function = basic_function<stack_reference, false>;
using stack_safe_function = basic_protected_function<stack_reference, false, reference>;
using stack_aligned_unsafe_function = basic_function<stack_reference, true>;
using stack_aligned_safe_function = basic_protected_function<stack_reference, true, reference>;
using protected_function = safe_function;
using main_protected_function = main_safe_function;
using stack_protected_function = stack_safe_function;
using stack_aligned_protected_function = stack_aligned_safe_function;
#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)
using function = protected_function;
using main_function = main_protected_function;
using stack_function = stack_protected_function;
using stack_aligned_function = stack_aligned_safe_function;
#else
using function = unsafe_function;
using main_function = main_unsafe_function;
using stack_function = stack_unsafe_function;
using stack_aligned_function = stack_aligned_unsafe_function;
#endif
using stack_aligned_stack_handler_function = basic_protected_function<stack_reference, true, stack_reference>;
struct unsafe_function_result;
struct protected_function_result;
using safe_function_result = protected_function_result;
#if SOL_IS_ON(SOL_SAFE_FUNCTION_OBJECTS_I_)
using function_result = safe_function_result;
#else
using function_result = unsafe_function_result;
#endif
template <typename base_t>
class basic_object_base;
template <typename base_t>
class basic_object;
template <typename base_t>
class basic_userdata;
template <typename base_t>
class basic_lightuserdata;
template <typename base_t>
class basic_coroutine;
template <typename base_t>
class basic_thread;
using object = basic_object<reference>;
using userdata = basic_userdata<reference>;
using lightuserdata = basic_lightuserdata<reference>;
using thread = basic_thread<reference>;
using coroutine = basic_coroutine<reference>;
using main_object = basic_object<main_reference>;
using main_userdata = basic_userdata<main_reference>;
using main_lightuserdata = basic_lightuserdata<main_reference>;
using main_coroutine = basic_coroutine<main_reference>;
using stack_object = basic_object<stack_reference>;
using stack_userdata = basic_userdata<stack_reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
using stack_thread = basic_thread<stack_reference>;
using stack_coroutine = basic_coroutine<stack_reference>;
struct stack_proxy_base;
struct stack_proxy;
struct variadic_args;
struct variadic_results;
struct stack_count;
struct this_state;
struct this_main_state;
struct this_environment;
class state_view;
class state;
template <typename T>
struct as_table_t;
template <typename T>
struct as_container_t;
template <typename T>
struct nested;
template <typename T>
struct light;
template <typename T>
struct user;
template <typename T>
struct as_args_t;
template <typename T>
struct protect_t;
template <typename F, typename... Policies>
struct policy_wrapper;
template <typename T>
struct usertype_traits;
template <typename T>
struct unique_usertype_traits;
template <typename... Args>
struct types {
typedef std::make_index_sequence<sizeof...(Args)> indices;
static constexpr std::size_t size() {
return sizeof...(Args);
}
};
template <typename T>
struct derive : std::false_type {
typedef types<> type;
};
template <typename T>
struct base : std::false_type {
typedef types<> type;
};
template <typename T>
struct weak_derive {
static bool value;
};
template <typename T>
bool weak_derive<T>::value = false;
namespace stack {
struct record;
}
#if SOL_IS_OFF(SOL_USE_BOOST_I_)
template <class T>
class optional;
template <class T>
class optional<T&>;
#endif
using check_handler_type = int(lua_State*, int, type, type, const char*);
} // namespace sol
#define SOL_BASE_CLASSES(T, ...) \
namespace sol { \
template <> \
struct base<T> : std::true_type { \
typedef ::sol::types<__VA_ARGS__> type; \
}; \
} \
void a_sol3_detail_function_decl_please_no_collide()
#define SOL_DERIVED_CLASSES(T, ...) \
namespace sol { \
template <> \
struct derive<T> : std::true_type { \
typedef ::sol::types<__VA_ARGS__> type; \
}; \
} \
void a_sol3_detail_function_decl_please_no_collide()
#endif // SOL_FORWARD_HPP
// end of sol/forward.hpp
#endif // SOL_SINGLE_INCLUDE_FORWARD_HPP

26737
Libs/sol/sol.hpp Normal file

File diff suppressed because it is too large Load diff

93
Libs/spdlog/async.h Normal file
View file

@ -0,0 +1,93 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
//
// Async logging using global thread pool
// All loggers created here share same global thread pool.
// Each log message is pushed to a queue along with a shared pointer to the
// logger.
// If a logger deleted while having pending messages in the queue, it's actual
// destruction will defer
// until all its messages are processed by the thread pool.
// This is because each message in the queue holds a shared_ptr to the
// originating logger.
#include <spdlog/async_logger.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/thread_pool.h>
#include <memory>
#include <mutex>
#include <functional>
namespace spdlog {
namespace details {
static const size_t default_async_q_size = 8192;
}
// async logger factory - creates async loggers backed with thread pool.
// if a global thread pool doesn't already exist, create it with default queue
// size of 8192 items and single thread.
template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
struct async_factory_impl
{
template<typename Sink, typename... SinkArgs>
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args)
{
auto &registry_inst = details::registry::instance();
// create global thread pool if not already exists..
auto &mutex = registry_inst.tp_mutex();
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
auto tp = registry_inst.get_tp();
if (tp == nullptr)
{
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
registry_inst.set_tp(tp);
}
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);
registry_inst.initialize_logger(new_logger);
return new_logger;
}
};
using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&...sink_args)
{
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
}
template<typename Sink, typename... SinkArgs>
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&...sink_args)
{
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
}
// set global thread pool.
inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start)
{
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start);
details::registry::instance().set_tp(std::move(tp));
}
// set global thread pool.
inline void init_thread_pool(size_t q_size, size_t thread_count)
{
init_thread_pool(q_size, thread_count, [] {});
}
// get the global thread pool.
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool()
{
return details::registry::instance().get_tp();
}
} // namespace spdlog

View file

@ -0,0 +1,92 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/async_logger.h>
#endif
#include <spdlog/sinks/sink.h>
#include <spdlog/details/thread_pool.h>
#include <memory>
#include <string>
SPDLOG_INLINE spdlog::async_logger::async_logger(
std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)
{}
SPDLOG_INLINE spdlog::async_logger::async_logger(
std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
: async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)
{}
// send the log message to the thread pool
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg)
{
if (auto pool_ptr = thread_pool_.lock())
{
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
}
else
{
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
}
}
// send flush request to the thread pool
SPDLOG_INLINE void spdlog::async_logger::flush_()
{
if (auto pool_ptr = thread_pool_.lock())
{
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
}
else
{
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
}
}
//
// backend functions - called from the thread pool to do the actual job
//
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg)
{
for (auto &sink : sinks_)
{
if (sink->should_log(msg.level))
{
SPDLOG_TRY
{
sink->log(msg);
}
SPDLOG_LOGGER_CATCH()
}
}
if (should_flush_(msg))
{
backend_flush_();
}
}
SPDLOG_INLINE void spdlog::async_logger::backend_flush_()
{
for (auto &sink : sinks_)
{
SPDLOG_TRY
{
sink->flush();
}
SPDLOG_LOGGER_CATCH()
}
}
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
{
auto cloned = std::make_shared<spdlog::async_logger>(*this);
cloned->name_ = std::move(new_name);
return cloned;
}

View file

@ -0,0 +1,68 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Fast asynchronous logger.
// Uses pre allocated queue.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until
// space is available in the queue)
// Upon destruction, logs all remaining messages in the queue before
// destructing..
#include <spdlog/logger.h>
namespace spdlog {
// Async overflow policy - block by default.
enum class async_overflow_policy
{
block, // Block until message can be enqueued
overrun_oldest // Discard oldest message in the queue if full when trying to
// add new item.
};
namespace details {
class thread_pool;
}
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>, public logger
{
friend class details::thread_pool;
public:
template<typename It>
async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block)
: logger(std::move(logger_name), begin, end)
, thread_pool_(std::move(tp))
, overflow_policy_(overflow_policy)
{}
async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
async_overflow_policy overflow_policy = async_overflow_policy::block);
std::shared_ptr<logger> clone(std::string new_name) override;
protected:
void sink_it_(const details::log_msg &msg) override;
void flush_() override;
void backend_sink_it_(const details::log_msg &incoming_log_msg);
void backend_flush_();
private:
std::weak_ptr<details::thread_pool> thread_pool_;
async_overflow_policy overflow_policy_;
};
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "async_logger-inl.h"
#endif

44
Libs/spdlog/cfg/argv.h Normal file
View file

@ -0,0 +1,44 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>
//
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
//
// set all loggers to debug level:
// example.exe "SPDLOG_LEVEL=debug"
// set logger1 to trace level
// example.exe "SPDLOG_LEVEL=logger1=trace"
// turn off all logging except for logger1 and logger2:
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
namespace spdlog {
namespace cfg {
// search for SPDLOG_LEVEL= in the args and use it to init the levels
inline void load_argv_levels(int argc, const char **argv)
{
const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
for (int i = 1; i < argc; i++)
{
std::string arg = argv[i];
if (arg.find(spdlog_level_prefix) == 0)
{
auto levels_string = arg.substr(spdlog_level_prefix.size());
helpers::load_levels(levels_string);
}
}
}
inline void load_argv_levels(int argc, char **argv)
{
load_argv_levels(argc, const_cast<const char **>(argv));
}
} // namespace cfg
} // namespace spdlog

38
Libs/spdlog/cfg/env.h Normal file
View file

@ -0,0 +1,38 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/cfg/helpers.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/os.h>
//
// Init levels and patterns from env variables SPDLOG_LEVEL
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
// Note - fallback to "info" level on unrecognized levels
//
// Examples:
//
// set global level to debug:
// export SPDLOG_LEVEL=debug
//
// turn off all logging except for logger1:
// export SPDLOG_LEVEL="*=off,logger1=debug"
//
// turn off all logging except for logger1 and logger2:
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
namespace spdlog {
namespace cfg {
inline void load_env_levels()
{
auto env_val = details::os::getenv("SPDLOG_LEVEL");
if (!env_val.empty())
{
helpers::load_levels(env_val);
}
}
} // namespace cfg
} // namespace spdlog

View file

@ -0,0 +1,120 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/cfg/helpers.h>
#endif
#include <spdlog/spdlog.h>
#include <spdlog/details/os.h>
#include <spdlog/details/registry.h>
#include <algorithm>
#include <string>
#include <utility>
#include <sstream>
namespace spdlog {
namespace cfg {
namespace helpers {
// inplace convert to lowercase
inline std::string &to_lower_(std::string &str)
{
std::transform(
str.begin(), str.end(), str.begin(), [](char ch) { return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); });
return str;
}
// inplace trim spaces
inline std::string &trim_(std::string &str)
{
const char *spaces = " \n\r\t";
str.erase(str.find_last_not_of(spaces) + 1);
str.erase(0, str.find_first_not_of(spaces));
return str;
}
// return (name,value) trimmed pair from given "name=value" string.
// return empty string on missing parts
// "key=val" => ("key", "val")
// " key = val " => ("key", "val")
// "key=" => ("key", "")
// "val" => ("", "val")
inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str)
{
auto n = str.find(sep);
std::string k, v;
if (n == std::string::npos)
{
v = str;
}
else
{
k = str.substr(0, n);
v = str.substr(n + 1);
}
return std::make_pair(trim_(k), trim_(v));
}
// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.."
// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str)
{
std::string token;
std::istringstream token_stream(str);
std::unordered_map<std::string, std::string> rv{};
while (std::getline(token_stream, token, ','))
{
if (token.empty())
{
continue;
}
auto kv = extract_kv_('=', token);
rv[kv.first] = kv.second;
}
return rv;
}
SPDLOG_INLINE void load_levels(const std::string &input)
{
if (input.empty() || input.size() > 512)
{
return;
}
auto key_vals = extract_key_vals_(input);
std::unordered_map<std::string, level::level_enum> levels;
level::level_enum global_level = level::info;
bool global_level_found = false;
for (auto &name_level : key_vals)
{
auto &logger_name = name_level.first;
auto level_name = to_lower_(name_level.second);
auto level = level::from_str(level_name);
// ignore unrecognized level names
if (level == level::off && level_name != "off")
{
continue;
}
if (logger_name.empty()) // no logger name indicate global level
{
global_level_found = true;
global_level = level;
}
else
{
levels[logger_name] = level;
}
}
details::registry::instance().set_levels(std::move(levels), global_level_found ? &global_level : nullptr);
}
} // namespace helpers
} // namespace cfg
} // namespace spdlog

29
Libs/spdlog/cfg/helpers.h Normal file
View file

@ -0,0 +1,29 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <unordered_map>
namespace spdlog {
namespace cfg {
namespace helpers {
//
// Init levels from given string
//
// Examples:
//
// set global level to debug: "debug"
// turn off all logging except for logger1: "off,logger1=debug"
// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
//
SPDLOG_API void load_levels(const std::string &txt);
} // namespace helpers
} // namespace cfg
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "helpers-inl.h"
#endif // SPDLOG_HEADER_ONLY

78
Libs/spdlog/common-inl.h Normal file
View file

@ -0,0 +1,78 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/common.h>
#endif
#include <algorithm>
#include <iterator>
namespace spdlog {
namespace level {
#if __cplusplus >= 201703L
constexpr
#endif
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{
return level_string_views[l];
}
SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{
return short_level_names[l];
}
SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT
{
auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name);
if (it != std::end(level_string_views))
return static_cast<level::level_enum>(std::distance(std::begin(level_string_views), it));
// check also for "warn" and "err" before giving up..
if (name == "warn")
{
return level::warn;
}
if (name == "err")
{
return level::err;
}
return level::off;
}
} // namespace level
SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
: msg_(std::move(msg))
{}
SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno)
{
memory_buf_t outbuf;
fmt::format_system_error(outbuf, last_errno, msg.c_str());
msg_ = fmt::to_string(outbuf);
}
SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT
{
return msg_.c_str();
}
SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno)
{
SPDLOG_THROW(spdlog_ex(msg, last_errno));
}
SPDLOG_INLINE void throw_spdlog_ex(std::string msg)
{
SPDLOG_THROW(spdlog_ex(std::move(msg)));
}
} // namespace spdlog

279
Libs/spdlog/common.h Normal file
View file

@ -0,0 +1,279 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/tweakme.h>
#include <spdlog/details/null_mutex.h>
#include <atomic>
#include <chrono>
#include <initializer_list>
#include <memory>
#include <exception>
#include <string>
#include <type_traits>
#include <functional>
#ifdef SPDLOG_COMPILED_LIB
# undef SPDLOG_HEADER_ONLY
# if defined(_WIN32) && defined(SPDLOG_SHARED_LIB)
# ifdef spdlog_EXPORTS
# define SPDLOG_API __declspec(dllexport)
# else
# define SPDLOG_API __declspec(dllimport)
# endif
# else // !defined(_WIN32) || !defined(SPDLOG_SHARED_LIB)
# define SPDLOG_API
# endif
# define SPDLOG_INLINE
#else // !defined(SPDLOG_COMPILED_LIB)
# define SPDLOG_API
# define SPDLOG_HEADER_ONLY
# define SPDLOG_INLINE inline
#endif // #ifdef SPDLOG_COMPILED_LIB
#include <spdlog/fmt/fmt.h>
// backward compatibility with fmt versions older than 8
#if FMT_VERSION >= 80000
# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
# include <spdlog/fmt/xchar.h>
# endif
#else
# define SPDLOG_FMT_RUNTIME(format_string) format_string
#endif
// visual studio upto 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900)
# define SPDLOG_NOEXCEPT _NOEXCEPT
# define SPDLOG_CONSTEXPR
#else
# define SPDLOG_NOEXCEPT noexcept
# define SPDLOG_CONSTEXPR constexpr
#endif
#if defined(__GNUC__) || defined(__clang__)
# define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
# define SPDLOG_DEPRECATED __declspec(deprecated)
#else
# define SPDLOG_DEPRECATED
#endif
// disable thread local on msvc 2013
#ifndef SPDLOG_NO_TLS
# if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
# define SPDLOG_NO_TLS 1
# endif
#endif
#ifndef SPDLOG_FUNCTION
# define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__)
#endif
#ifdef SPDLOG_NO_EXCEPTIONS
# define SPDLOG_TRY
# define SPDLOG_THROW(ex) \
do \
{ \
printf("spdlog fatal error: %s\n", ex.what()); \
std::abort(); \
} while (0)
# define SPDLOG_CATCH_STD
#else
# define SPDLOG_TRY try
# define SPDLOG_THROW(ex) throw(ex)
# define SPDLOG_CATCH_STD \
catch (const std::exception &) {}
#endif
namespace spdlog {
class formatter;
namespace sinks {
class sink;
}
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
using filename_t = std::wstring;
// allow macro expansion to occur in SPDLOG_FILENAME_T
# define SPDLOG_FILENAME_T_INNER(s) L##s
# define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s)
#else
using filename_t = std::string;
# define SPDLOG_FILENAME_T(s) s
#endif
using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using err_handler = std::function<void(const std::string &err_msg)>;
using string_view_t = fmt::basic_string_view<char>;
using wstring_view_t = fmt::basic_string_view<wchar_t>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
# ifndef _WIN32
# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
# else
template<typename T>
struct is_convertible_to_wstring_view : std::is_convertible<T, wstring_view_t>
{};
template<class T>
struct is_convertible_to_wformat_string : std::is_convertible<T, fmt::wformat_string<>>
{};
# endif // _WIN32
#else
template<typename>
struct is_convertible_to_wstring_view : std::false_type
{};
template<class>
struct is_convertible_to_wformat_string : std::false_type
{};
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<class T>
struct is_convertible_to_basic_format_string
: std::integral_constant<bool, std::is_convertible<const T &, fmt::format_string<>>::value || is_convertible_to_wformat_string<T>::value>
{};
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int;
#else
using level_t = std::atomic<int>;
#endif
#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6
#if !defined(SPDLOG_ACTIVE_LEVEL)
# define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#endif
// Log level enum
namespace level {
enum level_enum
{
trace = SPDLOG_LEVEL_TRACE,
debug = SPDLOG_LEVEL_DEBUG,
info = SPDLOG_LEVEL_INFO,
warn = SPDLOG_LEVEL_WARN,
err = SPDLOG_LEVEL_ERROR,
critical = SPDLOG_LEVEL_CRITICAL,
off = SPDLOG_LEVEL_OFF,
n_levels
};
#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5)
#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5)
#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4)
#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7)
#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5)
#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8)
#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3)
#if !defined(SPDLOG_LEVEL_NAMES)
# define SPDLOG_LEVEL_NAMES \
{ \
SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, \
SPDLOG_LEVEL_NAME_CRITICAL, SPDLOG_LEVEL_NAME_OFF \
}
#endif
#if !defined(SPDLOG_SHORT_LEVEL_NAMES)
# define SPDLOG_SHORT_LEVEL_NAMES \
{ \
"T", "D", "I", "W", "E", "C", "O" \
}
#endif
SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;
} // namespace level
//
// Color mode used by sinks with color support.
//
enum class color_mode
{
always,
automatic,
never
};
//
// Pattern time - specific time getting to use for pattern_formatter.
// local time by default
//
enum class pattern_time_type
{
local, // log localtime
utc // log utc
};
//
// Log exception
//
class SPDLOG_API spdlog_ex : public std::exception
{
public:
explicit spdlog_ex(std::string msg);
spdlog_ex(const std::string &msg, int last_errno);
const char *what() const SPDLOG_NOEXCEPT override;
private:
std::string msg_;
};
[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno);
[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg);
struct source_loc
{
SPDLOG_CONSTEXPR source_loc() = default;
SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
: filename{filename_in}
, line{line_in}
, funcname{funcname_in}
{}
SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT
{
return line == 0;
}
const char *filename{nullptr};
int line{0};
const char *funcname{nullptr};
};
namespace details {
// make_unique support for pre c++14
#if __cplusplus >= 201402L // C++14 and beyond
using std::make_unique;
#else
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&...args)
{
static_assert(!std::is_array<T>::value, "arrays not supported");
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "common-inl.h"
#endif

View file

@ -0,0 +1,69 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/backtracer.h>
#endif
namespace spdlog {
namespace details {
SPDLOG_INLINE backtracer::backtracer(const backtracer &other)
{
std::lock_guard<std::mutex> lock(other.mutex_);
enabled_ = other.enabled();
messages_ = other.messages_;
}
SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT
{
std::lock_guard<std::mutex> lock(other.mutex_);
enabled_ = other.enabled();
messages_ = std::move(other.messages_);
}
SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other)
{
std::lock_guard<std::mutex> lock(mutex_);
enabled_ = other.enabled();
messages_ = std::move(other.messages_);
return *this;
}
SPDLOG_INLINE void backtracer::enable(size_t size)
{
std::lock_guard<std::mutex> lock{mutex_};
enabled_.store(true, std::memory_order_relaxed);
messages_ = circular_q<log_msg_buffer>{size};
}
SPDLOG_INLINE void backtracer::disable()
{
std::lock_guard<std::mutex> lock{mutex_};
enabled_.store(false, std::memory_order_relaxed);
}
SPDLOG_INLINE bool backtracer::enabled() const
{
return enabled_.load(std::memory_order_relaxed);
}
SPDLOG_INLINE void backtracer::push_back(const log_msg &msg)
{
std::lock_guard<std::mutex> lock{mutex_};
messages_.push_back(log_msg_buffer{msg});
}
// pop all items in the q and apply the given fun on each of them.
SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun)
{
std::lock_guard<std::mutex> lock{mutex_};
while (!messages_.empty())
{
auto &front_msg = messages_.front();
fun(front_msg);
messages_.pop_front();
}
}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,45 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/log_msg_buffer.h>
#include <spdlog/details/circular_q.h>
#include <atomic>
#include <mutex>
#include <functional>
// Store log messages in circular buffer.
// Useful for storing debug data in case of error/warning happens.
namespace spdlog {
namespace details {
class SPDLOG_API backtracer
{
mutable std::mutex mutex_;
std::atomic<bool> enabled_{false};
circular_q<log_msg_buffer> messages_;
public:
backtracer() = default;
backtracer(const backtracer &other);
backtracer(backtracer &&other) SPDLOG_NOEXCEPT;
backtracer &operator=(backtracer other);
void enable(size_t size);
void disable();
bool enabled() const;
void push_back(const log_msg &msg);
// pop all items in the q and apply the given fun on each of them.
void foreach_pop(std::function<void(const details::log_msg &)> fun);
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "backtracer-inl.h"
#endif

View file

@ -0,0 +1,141 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
// circular q view of std::vector.
#pragma once
#include <vector>
#include <cassert>
namespace spdlog {
namespace details {
template<typename T>
class circular_q
{
size_t max_items_ = 0;
typename std::vector<T>::size_type head_ = 0;
typename std::vector<T>::size_type tail_ = 0;
size_t overrun_counter_ = 0;
std::vector<T> v_;
public:
using value_type = T;
// empty ctor - create a disabled queue with no elements allocated at all
circular_q() = default;
explicit circular_q(size_t max_items)
: max_items_(max_items + 1) // one item is reserved as marker for full q
, v_(max_items_)
{}
circular_q(const circular_q &) = default;
circular_q &operator=(const circular_q &) = default;
// move cannot be default,
// since we need to reset head_, tail_, etc to zero in the moved object
circular_q(circular_q &&other) SPDLOG_NOEXCEPT
{
copy_moveable(std::move(other));
}
circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT
{
copy_moveable(std::move(other));
return *this;
}
// push back, overrun (oldest) item if no room left
void push_back(T &&item)
{
if (max_items_ > 0)
{
v_[tail_] = std::move(item);
tail_ = (tail_ + 1) % max_items_;
if (tail_ == head_) // overrun last item if full
{
head_ = (head_ + 1) % max_items_;
++overrun_counter_;
}
}
}
// Return reference to the front item.
// If there are no elements in the container, the behavior is undefined.
const T &front() const
{
return v_[head_];
}
T &front()
{
return v_[head_];
}
// Return number of elements actually stored
size_t size() const
{
if (tail_ >= head_)
{
return tail_ - head_;
}
else
{
return max_items_ - (head_ - tail_);
}
}
// Return const reference to item by index.
// If index is out of range 0…size()-1, the behavior is undefined.
const T &at(size_t i) const
{
assert(i < size());
return v_[(head_ + i) % max_items_];
}
// Pop item from front.
// If there are no elements in the container, the behavior is undefined.
void pop_front()
{
head_ = (head_ + 1) % max_items_;
}
bool empty() const
{
return tail_ == head_;
}
bool full() const
{
// head is ahead of the tail by 1
if (max_items_ > 0)
{
return ((tail_ + 1) % max_items_) == head_;
}
return false;
}
size_t overrun_counter() const
{
return overrun_counter_;
}
private:
// copy from other&& and reset it to disabled state
void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT
{
max_items_ = other.max_items_;
head_ = other.head_;
tail_ = other.tail_;
overrun_counter_ = other.overrun_counter_;
v_ = std::move(other.v_);
// put &&other in disabled, but valid state
other.max_items_ = 0;
other.head_ = other.tail_ = 0;
other.overrun_counter_ = 0;
}
};
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,32 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/null_mutex.h>
#include <mutex>
namespace spdlog {
namespace details {
struct console_mutex
{
using mutex_t = std::mutex;
static mutex_t &mutex()
{
static mutex_t s_mutex;
return s_mutex;
}
};
struct console_nullmutex
{
using mutex_t = null_mutex;
static mutex_t &mutex()
{
static mutex_t s_mutex;
return s_mutex;
}
};
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,147 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/file_helper.h>
#endif
#include <spdlog/details/os.h>
#include <spdlog/common.h>
#include <cerrno>
#include <chrono>
#include <cstdio>
#include <string>
#include <thread>
#include <tuple>
namespace spdlog {
namespace details {
SPDLOG_INLINE file_helper::~file_helper()
{
close();
}
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
{
close();
filename_ = fname;
auto *mode = SPDLOG_FILENAME_T("ab");
auto *trunc_mode = SPDLOG_FILENAME_T("wb");
for (int tries = 0; tries < open_tries_; ++tries)
{
// create containing folder if not exists already.
os::create_dir(os::dir_name(fname));
if (truncate)
{
// Truncate by opening-and-closing a tmp file in "wb" mode, always
// opening the actual log-we-write-to in "ab" mode, since that
// interacts more politely with eternal processes that might
// rotate/truncate the file underneath us.
std::FILE *tmp;
if (os::fopen_s(&tmp, fname, trunc_mode))
{
continue;
}
std::fclose(tmp);
}
if (!os::fopen_s(&fd_, fname, mode))
{
return;
}
details::os::sleep_for_millis(open_interval_);
}
throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno);
}
SPDLOG_INLINE void file_helper::reopen(bool truncate)
{
if (filename_.empty())
{
throw_spdlog_ex("Failed re opening file - was not opened before");
}
this->open(filename_, truncate);
}
SPDLOG_INLINE void file_helper::flush()
{
std::fflush(fd_);
}
SPDLOG_INLINE void file_helper::close()
{
if (fd_ != nullptr)
{
std::fclose(fd_);
fd_ = nullptr;
}
}
SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf)
{
size_t msg_size = buf.size();
auto data = buf.data();
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
{
throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno);
}
}
SPDLOG_INLINE size_t file_helper::size() const
{
if (fd_ == nullptr)
{
throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_));
}
return os::filesize(fd_);
}
SPDLOG_INLINE const filename_t &file_helper::filename() const
{
return filename_;
}
//
// return file path and its extension:
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
//
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(const filename_t &fname)
{
auto ext_index = fname.rfind('.');
// no valid extension found - return whole path and empty string as
// extension
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
{
return std::make_tuple(fname, filename_t());
}
// treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
auto folder_index = fname.find_last_of(details::os::folder_seps_filename);
if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
{
return std::make_tuple(fname, filename_t());
}
// finally - return a valid base and extension tuple
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,59 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <tuple>
namespace spdlog {
namespace details {
// Helper class for file sinks.
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
// Throw spdlog_ex exception on errors.
class SPDLOG_API file_helper
{
public:
explicit file_helper() = default;
file_helper(const file_helper &) = delete;
file_helper &operator=(const file_helper &) = delete;
~file_helper();
void open(const filename_t &fname, bool truncate = false);
void reopen(bool truncate);
void flush();
void close();
void write(const memory_buf_t &buf);
size_t size() const;
const filename_t &filename() const;
//
// return file path and its extension:
//
// "mylog.txt" => ("mylog", ".txt")
// "mylog" => ("mylog", "")
// "mylog." => ("mylog.", "")
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
//
// the starting dot in filenames is ignored (hidden files):
//
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
private:
const int open_tries_ = 5;
const unsigned int open_interval_ = 10;
std::FILE *fd_{nullptr};
filename_t filename_;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "file_helper-inl.h"
#endif

View file

@ -0,0 +1,117 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <chrono>
#include <type_traits>
#include <iterator>
#include <spdlog/fmt/fmt.h>
#include <spdlog/common.h>
// Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog {
namespace details {
namespace fmt_helper {
inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT
{
return spdlog::string_view_t{buf.data(), buf.size()};
}
inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest)
{
auto *buf_ptr = view.data();
dest.append(buf_ptr, buf_ptr + view.size());
}
template<typename T>
inline void append_int(T n, memory_buf_t &dest)
{
fmt::format_int i(n);
dest.append(i.data(), i.data() + i.size());
}
template<typename T>
inline unsigned int count_digits(T n)
{
using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
return static_cast<unsigned int>(fmt::
// fmt 7.0.0 renamed the internal namespace to detail.
// See: https://github.com/fmtlib/fmt/issues/1538
#if FMT_VERSION < 70000
internal
#else
detail
#endif
::count_digits(static_cast<count_type>(n)));
}
inline void pad2(int n, memory_buf_t &dest)
{
if (n >= 0 && n < 100) // 0-99
{
dest.push_back(static_cast<char>('0' + n / 10));
dest.push_back(static_cast<char>('0' + n % 10));
}
else // unlikely, but just in case, let fmt deal with it
{
fmt::format_to(std::back_inserter(dest), SPDLOG_FMT_RUNTIME("{:02}"), n);
}
}
template<typename T>
inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
{
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
for (auto digits = count_digits(n); digits < width; digits++)
{
dest.push_back('0');
}
append_int(n, dest);
}
template<typename T>
inline void pad3(T n, memory_buf_t &dest)
{
static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T");
if (n < 1000)
{
dest.push_back(static_cast<char>(n / 100 + '0'));
n = n % 100;
dest.push_back(static_cast<char>((n / 10) + '0'));
dest.push_back(static_cast<char>((n % 10) + '0'));
}
else
{
append_int(n, dest);
}
}
template<typename T>
inline void pad6(T n, memory_buf_t &dest)
{
pad_uint(n, 6, dest);
}
template<typename T>
inline void pad9(T n, memory_buf_t &dest)
{
pad_uint(n, 9, dest);
}
// return fraction of a second of the given time_point.
// e.g.
// fraction<std::milliseconds>(tp) -> will return the millis part of the second
template<typename ToDuration>
inline ToDuration time_fraction(log_clock::time_point tp)
{
using std::chrono::duration_cast;
using std::chrono::seconds;
auto duration = tp.time_since_epoch();
auto secs = duration_cast<seconds>(duration);
return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
}
} // namespace fmt_helper
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,37 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/log_msg.h>
#endif
#include <spdlog/details/os.h>
namespace spdlog {
namespace details {
SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name,
spdlog::level::level_enum lvl, spdlog::string_view_t msg)
: logger_name(a_logger_name)
, level(lvl)
, time(log_time)
#ifndef SPDLOG_NO_THREAD_ID
, thread_id(os::thread_id())
#endif
, source(loc)
, payload(msg)
{}
SPDLOG_INLINE log_msg::log_msg(
spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
: log_msg(os::now(), loc, a_logger_name, lvl, msg)
{}
SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
: log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg)
{}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,37 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <string>
namespace spdlog {
namespace details {
struct SPDLOG_API log_msg
{
log_msg() = default;
log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);
log_msg(const log_msg &other) = default;
log_msg &operator=(const log_msg &other) = default;
string_view_t logger_name;
level::level_enum level{level::off};
log_clock::time_point time;
size_t thread_id{0};
// wrapping the formatted text with color (updated by pattern_formatter).
mutable size_t color_range_start{0};
mutable size_t color_range_end{0};
source_loc source;
string_view_t payload;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "log_msg-inl.h"
#endif

View file

@ -0,0 +1,58 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/log_msg_buffer.h>
#endif
namespace spdlog {
namespace details {
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
: log_msg{orig_msg}
{
buffer.append(logger_name.begin(), logger_name.end());
buffer.append(payload.begin(), payload.end());
update_string_views();
}
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
: log_msg{other}
{
buffer.append(logger_name.begin(), logger_name.end());
buffer.append(payload.begin(), payload.end());
update_string_views();
}
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)}
{
update_string_views();
}
SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other)
{
log_msg::operator=(other);
buffer.clear();
buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
update_string_views();
return *this;
}
SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT
{
log_msg::operator=(other);
buffer = std::move(other.buffer);
update_string_views();
return *this;
}
SPDLOG_INLINE void log_msg_buffer::update_string_views()
{
logger_name = string_view_t{buffer.data(), logger_name.size()};
payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,33 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/log_msg.h>
namespace spdlog {
namespace details {
// Extend log_msg with internal buffer to store its payload.
// This is needed since log_msg holds string_views that points to stack data.
class SPDLOG_API log_msg_buffer : public log_msg
{
memory_buf_t buffer;
void update_string_views();
public:
log_msg_buffer() = default;
explicit log_msg_buffer(const log_msg &orig_msg);
log_msg_buffer(const log_msg_buffer &other);
log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
log_msg_buffer &operator=(const log_msg_buffer &other);
log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "log_msg_buffer-inl.h"
#endif

View file

@ -0,0 +1,126 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// multi producer-multi consumer blocking queue.
// enqueue(..) - will block until room found to put the new message.
// enqueue_nowait(..) - will return immediately with false if no room left in
// the queue.
// dequeue_for(..) - will block until the queue is not empty or timeout have
// passed.
#include <spdlog/details/circular_q.h>
#include <condition_variable>
#include <mutex>
namespace spdlog {
namespace details {
template<typename T>
class mpmc_blocking_queue
{
public:
using item_type = T;
explicit mpmc_blocking_queue(size_t max_items)
: q_(max_items)
{}
#ifndef __MINGW32__
// try to enqueue and block if no room left
void enqueue(T &&item)
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
q_.push_back(std::move(item));
}
push_cv_.notify_one();
}
// enqueue immediately. overrun oldest message in the queue if no room left.
void enqueue_nowait(T &&item)
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
q_.push_back(std::move(item));
}
push_cv_.notify_one();
}
// try to dequeue item. if no item found. wait upto timeout and try again
// Return true, if succeeded dequeue item, false otherwise
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
{
{
std::unique_lock<std::mutex> lock(queue_mutex_);
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
{
return false;
}
popped_item = std::move(q_.front());
q_.pop_front();
}
pop_cv_.notify_one();
return true;
}
#else
// apparently mingw deadlocks if the mutex is released before cv.notify_one(),
// so release the mutex at the very end each function.
// try to enqueue and block if no room left
void enqueue(T &&item)
{
std::unique_lock<std::mutex> lock(queue_mutex_);
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
q_.push_back(std::move(item));
push_cv_.notify_one();
}
// enqueue immediately. overrun oldest message in the queue if no room left.
void enqueue_nowait(T &&item)
{
std::unique_lock<std::mutex> lock(queue_mutex_);
q_.push_back(std::move(item));
push_cv_.notify_one();
}
// try to dequeue item. if no item found. wait upto timeout and try again
// Return true, if succeeded dequeue item, false otherwise
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
{
std::unique_lock<std::mutex> lock(queue_mutex_);
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
{
return false;
}
popped_item = std::move(q_.front());
q_.pop_front();
pop_cv_.notify_one();
return true;
}
#endif
size_t overrun_counter()
{
std::unique_lock<std::mutex> lock(queue_mutex_);
return q_.overrun_counter();
}
size_t size()
{
std::unique_lock<std::mutex> lock(queue_mutex_);
return q_.size();
}
private:
std::mutex queue_mutex_;
std::condition_variable push_cv_;
std::condition_variable pop_cv_;
spdlog::details::circular_q<T> q_;
};
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,49 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <atomic>
#include <utility>
// null, no cost dummy "mutex" and dummy "atomic" int
namespace spdlog {
namespace details {
struct null_mutex
{
void lock() const {}
void unlock() const {}
bool try_lock() const
{
return true;
}
};
struct null_atomic_int
{
int value;
null_atomic_int() = default;
explicit null_atomic_int(int new_value)
: value(new_value)
{}
int load(std::memory_order = std::memory_order_relaxed) const
{
return value;
}
void store(int new_value, std::memory_order = std::memory_order_relaxed)
{
value = new_value;
}
int exchange(int new_value, std::memory_order = std::memory_order_relaxed)
{
std::swap(new_value, value);
return new_value; // return value before the call
}
};
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,599 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/os.h>
#endif
#include <spdlog/common.h>
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <thread>
#include <array>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef _WIN32
# include <io.h> // _get_osfhandle and _isatty support
# include <process.h> // _get_pid support
# include <spdlog/details/windows_include.h>
# ifdef __MINGW32__
# include <share.h>
# endif
# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
# include <limits>
# endif
# include <direct.h> // for _mkdir/_wmkdir
#else // unix
# include <fcntl.h>
# include <unistd.h>
# ifdef __linux__
# include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
# elif defined(_AIX)
# include <pthread.h> // for pthread_getthreadid_np
# elif defined(__DragonFly__) || defined(__FreeBSD__)
# include <pthread_np.h> // for pthread_getthreadid_np
# elif defined(__NetBSD__)
# include <lwp.h> // for _lwp_self
# elif defined(__sun)
# include <thread.h> // for thr_self
# endif
#endif // unix
#ifndef __has_feature // Clang - feature checking macros.
# define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
namespace spdlog {
namespace details {
namespace os {
SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
{
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
timespec ts;
::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
return std::chrono::time_point<log_clock, typename log_clock::duration>(
std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
#else
return log_clock::now();
#endif
}
SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
std::tm tm;
::localtime_s(&tm, &time_tt);
#else
std::tm tm;
::localtime_r(&time_tt, &tm);
#endif
return tm;
}
SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
{
std::time_t now_t = ::time(nullptr);
return localtime(now_t);
}
SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
std::tm tm;
::gmtime_s(&tm, &time_tt);
#else
std::tm tm;
::gmtime_r(&time_tt, &tm);
#endif
return tm;
}
SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
{
std::time_t now_t = ::time(nullptr);
return gmtime(now_t);
}
// fopen_s on non windows for writing
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
{
#ifdef _WIN32
# ifdef SPDLOG_WCHAR_FILENAMES
*fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
# else
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
# endif
# if defined(SPDLOG_PREVENT_CHILD_FD)
if (*fp != nullptr)
{
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
{
::fclose(*fp);
*fp = nullptr;
}
}
# endif
#else // unix
# if defined(SPDLOG_PREVENT_CHILD_FD)
const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
if (fd == -1)
{
return false;
}
*fp = ::fdopen(fd, mode.c_str());
if (*fp == nullptr)
{
::close(fd);
}
# else
*fp = ::fopen((filename.c_str()), mode.c_str());
# endif
#endif
return *fp == nullptr;
}
SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return ::_wremove(filename.c_str());
#else
return std::remove(filename.c_str());
#endif
}
SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
{
return path_exists(filename) ? remove(filename) : 0;
}
SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return ::_wrename(filename1.c_str(), filename2.c_str());
#else
return std::rename(filename1.c_str(), filename2.c_str());
#endif
}
// Return true if path exists (file or directory)
SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
# ifdef SPDLOG_WCHAR_FILENAMES
auto attribs = ::GetFileAttributesW(filename.c_str());
# else
auto attribs = ::GetFileAttributesA(filename.c_str());
# endif
return attribs != INVALID_FILE_ATTRIBUTES;
#else // common linux/unix all have the stat system call
struct stat buffer;
return (::stat(filename.c_str(), &buffer) == 0);
#endif
}
#ifdef _MSC_VER
// avoid warning about unreachable statement at the end of filesize()
# pragma warning(push)
# pragma warning(disable : 4702)
#endif
// Return file size according to open FILE* object
SPDLOG_INLINE size_t filesize(FILE *f)
{
if (f == nullptr)
{
throw_spdlog_ex("Failed getting file size. fd is null");
}
#if defined(_WIN32) && !defined(__CYGWIN__)
int fd = ::_fileno(f);
# if defined(_WIN64) // 64 bits
__int64 ret = ::_filelengthi64(fd);
if (ret >= 0)
{
return static_cast<size_t>(ret);
}
# else // windows 32 bits
long ret = ::_filelength(fd);
if (ret >= 0)
{
return static_cast<size_t>(ret);
}
# endif
#else // unix
// OpenBSD doesn't compile with :: before the fileno(..)
# if defined(__OpenBSD__)
int fd = fileno(f);
# else
int fd = ::fileno(f);
# endif
// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
# if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
struct stat64 st;
if (::fstat64(fd, &st) == 0)
{
return static_cast<size_t>(st.st_size);
}
# else // other unix or linux 32 bits or cygwin
struct stat st;
if (::fstat(fd, &st) == 0)
{
return static_cast<size_t>(st.st_size);
}
# endif
#endif
throw_spdlog_ex("Failed getting file size from fd", errno);
return 0; // will not be reached.
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif
// Return utc offset in minutes or throw spdlog_ex on failure
SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
{
#ifdef _WIN32
# if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION tzinfo;
auto rv = ::GetTimeZoneInformation(&tzinfo);
# else
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
# endif
if (rv == TIME_ZONE_ID_INVALID)
throw_spdlog_ex("Failed getting timezone info. ", errno);
int offset = -tzinfo.Bias;
if (tm.tm_isdst)
{
offset -= tzinfo.DaylightBias;
}
else
{
offset -= tzinfo.StandardBias;
}
return offset;
#else
# if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
struct helper
{
static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
{
int local_year = localtm.tm_year + (1900 - 1);
int gmt_year = gmtm.tm_year + (1900 - 1);
long int days = (
// difference in day of year
localtm.tm_yday -
gmtm.tm_yday
// + intervening leap days
+ ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
// + difference in years * 365 */
+ (long int)(local_year - gmt_year) * 365);
long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
return secs;
}
};
auto offset_seconds = helper::calculate_gmt_offset(tm);
# else
auto offset_seconds = tm.tm_gmtoff;
# endif
return static_cast<int>(offset_seconds / 60);
#endif
}
// Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013)
SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return static_cast<size_t>(::GetCurrentThreadId());
#elif defined(__linux__)
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
# define SYS_gettid __NR_gettid
# endif
return static_cast<size_t>(::syscall(SYS_gettid));
#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
return static_cast<size_t>(::pthread_getthreadid_np());
#elif defined(__NetBSD__)
return static_cast<size_t>(::_lwp_self());
#elif defined(__OpenBSD__)
return static_cast<size_t>(::getthrid());
#elif defined(__sun)
return static_cast<size_t>(::thr_self());
#elif __APPLE__
uint64_t tid;
pthread_threadid_np(nullptr, &tid);
return static_cast<size_t>(tid);
#else // Default to standard C++11 (other Unix)
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
#endif
}
// Return current thread id as size_t (from thread local storage)
SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT
{
#if defined(SPDLOG_NO_TLS)
return _thread_id();
#else // cache thread id in tls
static thread_local const size_t tid = _thread_id();
return tid;
#endif
}
// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT
{
#if defined(_WIN32)
::Sleep(milliseconds);
#else
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
#endif
}
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
{
memory_buf_t buf;
wstr_to_utf8buf(filename, buf);
return fmt::to_string(buf);
}
#else
SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
{
return filename;
}
#endif
SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return static_cast<int>(::GetCurrentProcessId());
#else
return static_cast<int>(::getpid());
#endif
}
// Determine if the terminal supports colors
// Based on: https://github.com/agauniyal/rang/
SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return true;
#else
static const bool result = []() {
const char *env_colorterm_p = std::getenv("COLORTERM");
if (env_colorterm_p != nullptr)
{
return true;
}
static constexpr std::array<const char *, 16> terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux",
"msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}};
const char *env_term_p = std::getenv("TERM");
if (env_term_p == nullptr)
{
return false;
}
return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; });
}();
return result;
#endif
}
// Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/
SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
{
#ifdef _WIN32
return ::_isatty(_fileno(file)) != 0;
#else
return ::isatty(fileno(file)) != 0;
#endif
}
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
{
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 2 - 1)
{
throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
}
int wstr_size = static_cast<int>(wstr.size());
if (wstr_size == 0)
{
target.resize(0);
return;
}
int result_size = static_cast<int>(target.capacity());
if ((wstr_size + 1) * 2 > result_size)
{
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
}
if (result_size > 0)
{
target.resize(result_size);
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
if (result_size > 0)
{
target.resize(result_size);
return;
}
}
throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}
SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
{
if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1)
{
throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
}
int str_size = static_cast<int>(str.size());
if (str_size == 0)
{
target.resize(0);
return;
}
int result_size = static_cast<int>(target.capacity());
if (str_size + 1 > result_size)
{
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
}
if (result_size > 0)
{
target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
if (result_size > 0)
{
target.resize(result_size);
return;
}
}
throw_spdlog_ex(fmt::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
}
#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
// return true on success
static SPDLOG_INLINE bool mkdir_(const filename_t &path)
{
#ifdef _WIN32
# ifdef SPDLOG_WCHAR_FILENAMES
return ::_wmkdir(path.c_str()) == 0;
# else
return ::_mkdir(path.c_str()) == 0;
# endif
#else
return ::mkdir(path.c_str(), mode_t(0755)) == 0;
#endif
}
// create the given directory - and all directories leading to it
// return true on success or if the directory already exists
SPDLOG_INLINE bool create_dir(filename_t path)
{
if (path_exists(path))
{
return true;
}
if (path.empty())
{
return false;
}
size_t search_offset = 0;
do
{
auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
// treat the entire path as a folder if no folder separator not found
if (token_pos == filename_t::npos)
{
token_pos = path.size();
}
auto subdir = path.substr(0, token_pos);
if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir))
{
return false; // return error if failed creating dir
}
search_offset = token_pos + 1;
} while (search_offset < path.size());
return true;
}
// Return directory name from given path or empty string
// "abc/file" => "abc"
// "abc/" => "abc"
// "abc" => ""
// "abc///" => "abc//"
SPDLOG_INLINE filename_t dir_name(filename_t path)
{
auto pos = path.find_last_of(folder_seps_filename);
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
}
std::string SPDLOG_INLINE getenv(const char *field)
{
#if defined(_MSC_VER)
# if defined(__cplusplus_winrt)
return std::string{}; // not supported under uwp
# else
size_t len = 0;
char buf[128];
bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
return ok ? buf : std::string{};
# endif
#else // revert to getenv
char *buf = ::getenv(field);
return buf ? buf : std::string{};
#endif
}
} // namespace os
} // namespace details
} // namespace spdlog

118
Libs/spdlog/details/os.h Normal file
View file

@ -0,0 +1,118 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <ctime> // std::time_t
namespace spdlog {
namespace details {
namespace os {
SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;
SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT;
SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT;
// eol definition
#if !defined(SPDLOG_EOL)
# ifdef _WIN32
# define SPDLOG_EOL "\r\n"
# else
# define SPDLOG_EOL "\n"
# endif
#endif
SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
// folder separator
#if !defined(SPDLOG_FOLDER_SEPS)
# ifdef _WIN32
# define SPDLOG_FOLDER_SEPS "\\/"
# else
# define SPDLOG_FOLDER_SEPS "/"
# endif
#endif
SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS;
SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS);
// fopen_s on non windows for writing
SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
// Remove filename. return 0 on success
SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT;
// Remove file if exists. return 0 on success
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
// Return if file exists.
SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
// Return file size according to open FILE* object
SPDLOG_API size_t filesize(FILE *f);
// Return utc offset in minutes or throw spdlog_ex on failure
SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime());
// Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013)
SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT;
// Return current thread id as size_t (from thread local storage)
SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT;
// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT;
SPDLOG_API std::string filename_to_str(const filename_t &filename);
SPDLOG_API int pid() SPDLOG_NOEXCEPT;
// Determine if the terminal supports colors
// Source: https://github.com/agauniyal/rang/
SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT;
// Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/
SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target);
#endif
// Return directory name from given path or empty string
// "abc/file" => "abc"
// "abc/" => "abc"
// "abc" => ""
// "abc///" => "abc//"
SPDLOG_API filename_t dir_name(filename_t path);
// Create a dir from the given path.
// Return true if succeeded or if this dir already exists.
SPDLOG_API bool create_dir(filename_t path);
// non thread safe, cross platform getenv/getenv_s
// return empty string if field not found
SPDLOG_API std::string getenv(const char *field);
} // namespace os
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "os-inl.h"
#endif

View file

@ -0,0 +1,49 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/periodic_worker.h>
#endif
namespace spdlog {
namespace details {
SPDLOG_INLINE periodic_worker::periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)
{
active_ = (interval > std::chrono::seconds::zero());
if (!active_)
{
return;
}
worker_thread_ = std::thread([this, callback_fun, interval]() {
for (;;)
{
std::unique_lock<std::mutex> lock(this->mutex_);
if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
{
return; // active_ == false, so exit this thread
}
callback_fun();
}
});
}
// stop the worker thread and join it
SPDLOG_INLINE periodic_worker::~periodic_worker()
{
if (worker_thread_.joinable())
{
{
std::lock_guard<std::mutex> lock(mutex_);
active_ = false;
}
cv_.notify_one();
worker_thread_.join();
}
}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,40 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// periodic worker thread - periodically executes the given callback function.
//
// RAII over the owned thread:
// creates the thread on construction.
// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
namespace spdlog {
namespace details {
class SPDLOG_API periodic_worker
{
public:
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);
periodic_worker(const periodic_worker &) = delete;
periodic_worker &operator=(const periodic_worker &) = delete;
// stop the worker thread and join it
~periodic_worker();
private:
bool active_;
std::thread worker_thread_;
std::mutex mutex_;
std::condition_variable cv_;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "periodic_worker-inl.h"
#endif

View file

@ -0,0 +1,313 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/registry.h>
#endif
#include <spdlog/common.h>
#include <spdlog/details/periodic_worker.h>
#include <spdlog/logger.h>
#include <spdlog/pattern_formatter.h>
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
// support for the default stdout color logger
# ifdef _WIN32
# include <spdlog/sinks/wincolor_sink.h>
# else
# include <spdlog/sinks/ansicolor_sink.h>
# endif
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
namespace spdlog {
namespace details {
SPDLOG_INLINE registry::registry()
: formatter_(new pattern_formatter())
{
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
// create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows).
# ifdef _WIN32
auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>();
# else
auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();
# endif
const char *default_logger_name = "";
default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink));
loggers_[default_logger_name] = default_logger_;
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
}
SPDLOG_INLINE registry::~registry() = default;
SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
register_logger_(std::move(new_logger));
}
SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
new_logger->set_formatter(formatter_->clone());
if (err_handler_)
{
new_logger->set_error_handler(err_handler_);
}
// set new level according to previously configured level or default level
auto it = log_levels_.find(new_logger->name());
auto new_level = it != log_levels_.end() ? it->second : global_log_level_;
new_logger->set_level(new_level);
new_logger->flush_on(flush_level_);
if (backtrace_n_messages_ > 0)
{
new_logger->enable_backtrace(backtrace_n_messages_);
}
if (automatic_registration_)
{
register_logger_(std::move(new_logger));
}
}
SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_name)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
auto found = loggers_.find(logger_name);
return found == loggers_.end() ? nullptr : found->second;
}
SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger()
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
return default_logger_;
}
// Return raw ptr to the default logger.
// To be used directly by the spdlog default api (e.g. spdlog::info)
// This make the default API faster, but cannot be used concurrently with set_default_logger().
// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
SPDLOG_INLINE logger *registry::get_default_raw()
{
return default_logger_.get();
}
// set default logger.
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
// remove previous default logger from the map
if (default_logger_ != nullptr)
{
loggers_.erase(default_logger_->name());
}
if (new_default_logger != nullptr)
{
loggers_[new_default_logger->name()] = new_default_logger;
}
default_logger_ = std::move(new_default_logger);
}
SPDLOG_INLINE void registry::set_tp(std::shared_ptr<thread_pool> tp)
{
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
tp_ = std::move(tp);
}
SPDLOG_INLINE std::shared_ptr<thread_pool> registry::get_tp()
{
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
return tp_;
}
// Set global formatter. Each sink in each logger will get a clone of this object
SPDLOG_INLINE void registry::set_formatter(std::unique_ptr<formatter> formatter)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
formatter_ = std::move(formatter);
for (auto &l : loggers_)
{
l.second->set_formatter(formatter_->clone());
}
}
SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
backtrace_n_messages_ = n_messages;
for (auto &l : loggers_)
{
l.second->enable_backtrace(n_messages);
}
}
SPDLOG_INLINE void registry::disable_backtrace()
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
backtrace_n_messages_ = 0;
for (auto &l : loggers_)
{
l.second->disable_backtrace();
}
}
SPDLOG_INLINE void registry::set_level(level::level_enum log_level)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->set_level(log_level);
}
global_log_level_ = log_level;
}
SPDLOG_INLINE void registry::flush_on(level::level_enum log_level)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->flush_on(log_level);
}
flush_level_ = log_level;
}
SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)
{
std::lock_guard<std::mutex> lock(flusher_mutex_);
auto clbk = [this]() { this->flush_all(); };
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
}
SPDLOG_INLINE void registry::set_error_handler(err_handler handler)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->set_error_handler(handler);
}
err_handler_ = std::move(handler);
}
SPDLOG_INLINE void registry::apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
fun(l.second);
}
}
SPDLOG_INLINE void registry::flush_all()
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->flush();
}
}
SPDLOG_INLINE void registry::drop(const std::string &logger_name)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
loggers_.erase(logger_name);
if (default_logger_ && default_logger_->name() == logger_name)
{
default_logger_.reset();
}
}
SPDLOG_INLINE void registry::drop_all()
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
loggers_.clear();
default_logger_.reset();
}
// clean all resources and threads started by the registry
SPDLOG_INLINE void registry::shutdown()
{
{
std::lock_guard<std::mutex> lock(flusher_mutex_);
periodic_flusher_.reset();
}
drop_all();
{
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
tp_.reset();
}
}
SPDLOG_INLINE std::recursive_mutex &registry::tp_mutex()
{
return tp_mutex_;
}
SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
automatic_registration_ = automatic_registration;
}
SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level)
{
std::lock_guard<std::mutex> lock(logger_map_mutex_);
log_levels_ = std::move(levels);
auto global_level_requested = global_level != nullptr;
global_log_level_ = global_level_requested ? *global_level : global_log_level_;
for (auto &logger : loggers_)
{
auto logger_entry = log_levels_.find(logger.first);
if (logger_entry != log_levels_.end())
{
logger.second->set_level(logger_entry->second);
}
else if (global_level_requested)
{
logger.second->set_level(*global_level);
}
}
}
SPDLOG_INLINE registry &registry::instance()
{
static registry s_instance;
return s_instance;
}
SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)
{
if (loggers_.find(logger_name) != loggers_.end())
{
throw_spdlog_ex("logger with name '" + logger_name + "' already exists");
}
}
SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger)
{
auto logger_name = new_logger->name();
throw_if_exists_(logger_name);
loggers_[logger_name] = std::move(new_logger);
}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,115 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Loggers registry of unique name->logger pointer
// An attempt to create a logger with an already existing name will result with spdlog_ex exception.
// If user requests a non existing logger, nullptr will be returned
// This class is thread safe
#include <spdlog/common.h>
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <mutex>
namespace spdlog {
class logger;
namespace details {
class thread_pool;
class periodic_worker;
class SPDLOG_API registry
{
public:
using log_levels = std::unordered_map<std::string, level::level_enum>;
registry(const registry &) = delete;
registry &operator=(const registry &) = delete;
void register_logger(std::shared_ptr<logger> new_logger);
void initialize_logger(std::shared_ptr<logger> new_logger);
std::shared_ptr<logger> get(const std::string &logger_name);
std::shared_ptr<logger> default_logger();
// Return raw ptr to the default logger.
// To be used directly by the spdlog default api (e.g. spdlog::info)
// This make the default API faster, but cannot be used concurrently with set_default_logger().
// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
logger *get_default_raw();
// set default logger.
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
void set_default_logger(std::shared_ptr<logger> new_default_logger);
void set_tp(std::shared_ptr<thread_pool> tp);
std::shared_ptr<thread_pool> get_tp();
// Set global formatter. Each sink in each logger will get a clone of this object
void set_formatter(std::unique_ptr<formatter> formatter);
void enable_backtrace(size_t n_messages);
void disable_backtrace();
void set_level(level::level_enum log_level);
void flush_on(level::level_enum log_level);
void flush_every(std::chrono::seconds interval);
void set_error_handler(err_handler handler);
void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun);
void flush_all();
void drop(const std::string &logger_name);
void drop_all();
// clean all resources and threads started by the registry
void shutdown();
std::recursive_mutex &tp_mutex();
void set_automatic_registration(bool automatic_registration);
// set levels for all existing/future loggers. global_level can be null if should not set.
void set_levels(log_levels levels, level::level_enum *global_level);
static registry &instance();
private:
registry();
~registry();
void throw_if_exists_(const std::string &logger_name);
void register_logger_(std::shared_ptr<logger> new_logger);
bool set_level_from_cfg_(logger *logger);
std::mutex logger_map_mutex_, flusher_mutex_;
std::recursive_mutex tp_mutex_;
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
log_levels log_levels_;
std::unique_ptr<formatter> formatter_;
spdlog::level::level_enum global_log_level_ = level::info;
level::level_enum flush_level_ = level::off;
err_handler err_handler_;
std::shared_ptr<thread_pool> tp_;
std::unique_ptr<periodic_worker> periodic_flusher_;
std::shared_ptr<logger> default_logger_;
bool automatic_registration_ = true;
size_t backtrace_n_messages_ = 0;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "registry-inl.h"
#endif

View file

@ -0,0 +1,24 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include "registry.h"
namespace spdlog {
// Default logger factory- creates synchronous loggers
class logger;
struct synchronous_factory
{
template<typename Sink, typename... SinkArgs>
static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&...args)
{
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));
details::registry::instance().initialize_logger(new_logger);
return new_logger;
}
};
} // namespace spdlog

View file

@ -0,0 +1,175 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#define WIN32_LEAN_AND_MEAN
// tcp client helper
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")
#pragma comment(lib, "AdvApi32.lib")
namespace spdlog {
namespace details {
class tcp_client
{
SOCKET socket_ = INVALID_SOCKET;
static bool winsock_initialized_()
{
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
return false;
}
else
{
closesocket(s);
return true;
}
}
static void init_winsock_()
{
WSADATA wsaData;
auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rv != 0)
{
throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
}
}
static void throw_winsock_error_(const std::string &msg, int last_error)
{
char buf[512];
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf));
}
public:
bool is_connected() const
{
return socket_ != INVALID_SOCKET;
}
void close()
{
::closesocket(socket_);
socket_ = INVALID_SOCKET;
WSACleanup();
}
SOCKET fd() const
{
return socket_;
}
~tcp_client()
{
close();
}
// try to connect or throw on failure
void connect(const std::string &host, int port)
{
// initialize winsock if needed
if (!winsock_initialized_())
{
init_winsock_();
}
if (is_connected())
{
close();
}
struct addrinfo hints
{};
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
hints.ai_protocol = 0;
auto port_str = std::to_string(port);
struct addrinfo *addrinfo_result;
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
int last_error = 0;
if (rv != 0)
{
last_error = ::WSAGetLastError();
WSACleanup();
throw_winsock_error_("getaddrinfo failed", last_error);
}
// Try each address until we successfully connect(2).
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
{
socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (socket_ == INVALID_SOCKET)
{
last_error = ::WSAGetLastError();
WSACleanup();
continue;
}
if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0)
{
break;
}
else
{
last_error = ::WSAGetLastError();
close();
}
}
::freeaddrinfo(addrinfo_result);
if (socket_ == INVALID_SOCKET)
{
WSACleanup();
throw_winsock_error_("connect failed", last_error);
}
// set TCP_NODELAY
int enable_flag = 1;
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void send(const char *data, size_t n_bytes)
{
size_t bytes_sent = 0;
while (bytes_sent < n_bytes)
{
const int send_flags = 0;
auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags);
if (write_result == SOCKET_ERROR)
{
int last_error = ::WSAGetLastError();
close();
throw_winsock_error_("send failed", last_error);
}
if (write_result == 0) // (probably should not happen but in any case..)
{
break;
}
bytes_sent += static_cast<size_t>(write_result);
}
}
};
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,146 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifdef _WIN32
# error include tcp_client-windows.h instead
#endif
// tcp client helper
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <string>
namespace spdlog {
namespace details {
class tcp_client
{
int socket_ = -1;
public:
bool is_connected() const
{
return socket_ != -1;
}
void close()
{
if (is_connected())
{
::close(socket_);
socket_ = -1;
}
}
int fd() const
{
return socket_;
}
~tcp_client()
{
close();
}
// try to connect or throw on failure
void connect(const std::string &host, int port)
{
close();
struct addrinfo hints
{};
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
hints.ai_protocol = 0;
auto port_str = std::to_string(port);
struct addrinfo *addrinfo_result;
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
if (rv != 0)
{
auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv));
throw_spdlog_ex(msg);
}
// Try each address until we successfully connect(2).
int last_errno = 0;
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
{
#if defined(SOCK_CLOEXEC)
const int flags = SOCK_CLOEXEC;
#else
const int flags = 0;
#endif
socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol);
if (socket_ == -1)
{
last_errno = errno;
continue;
}
rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen);
if (rv == 0)
{
break;
}
last_errno = errno;
::close(socket_);
socket_ = -1;
}
::freeaddrinfo(addrinfo_result);
if (socket_ == -1)
{
throw_spdlog_ex("::connect failed", last_errno);
}
// set TCP_NODELAY
int enable_flag = 1;
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
// prevent sigpipe on systems where MSG_NOSIGNAL is not available
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
#endif
#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
# error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
#endif
}
// Send exactly n_bytes of the given data.
// On error close the connection and throw.
void send(const char *data, size_t n_bytes)
{
size_t bytes_sent = 0;
while (bytes_sent < n_bytes)
{
#if defined(MSG_NOSIGNAL)
const int send_flags = MSG_NOSIGNAL;
#else
const int send_flags = 0;
#endif
auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags);
if (write_result < 0)
{
close();
throw_spdlog_ex("write(2) failed", errno);
}
if (write_result == 0) // (probably should not happen but in any case..)
{
break;
}
bytes_sent += static_cast<size_t>(write_result);
}
}
};
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,129 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/details/thread_pool.h>
#endif
#include <spdlog/common.h>
#include <cassert>
namespace spdlog {
namespace details {
SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start)
: q_(q_max_items)
{
if (threads_n == 0 || threads_n > 1000)
{
throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
"range is 1-1000)");
}
for (size_t i = 0; i < threads_n; i++)
{
threads_.emplace_back([this, on_thread_start] {
on_thread_start();
this->thread_pool::worker_loop_();
});
}
}
SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n)
: thread_pool(q_max_items, threads_n, [] {})
{}
// message all threads to terminate gracefully join them
SPDLOG_INLINE thread_pool::~thread_pool()
{
SPDLOG_TRY
{
for (size_t i = 0; i < threads_.size(); i++)
{
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
}
for (auto &t : threads_)
{
t.join();
}
}
SPDLOG_CATCH_STD
}
void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy)
{
async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg);
post_async_msg_(std::move(async_m), overflow_policy);
}
void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)
{
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
}
size_t SPDLOG_INLINE thread_pool::overrun_counter()
{
return q_.overrun_counter();
}
size_t SPDLOG_INLINE thread_pool::queue_size()
{
return q_.size();
}
void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy)
{
if (overflow_policy == async_overflow_policy::block)
{
q_.enqueue(std::move(new_msg));
}
else
{
q_.enqueue_nowait(std::move(new_msg));
}
}
void SPDLOG_INLINE thread_pool::worker_loop_()
{
while (process_next_msg_()) {}
}
// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool SPDLOG_INLINE thread_pool::process_next_msg_()
{
async_msg incoming_async_msg;
bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));
if (!dequeued)
{
return true;
}
switch (incoming_async_msg.msg_type)
{
case async_msg_type::log: {
incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
return true;
}
case async_msg_type::flush: {
incoming_async_msg.worker_ptr->backend_flush_();
return true;
}
case async_msg_type::terminate: {
return false;
}
default: {
assert(false);
}
}
return true;
}
} // namespace details
} // namespace spdlog

View file

@ -0,0 +1,121 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/log_msg_buffer.h>
#include <spdlog/details/mpmc_blocking_q.h>
#include <spdlog/details/os.h>
#include <chrono>
#include <memory>
#include <thread>
#include <vector>
#include <functional>
namespace spdlog {
class async_logger;
namespace details {
using async_logger_ptr = std::shared_ptr<spdlog::async_logger>;
enum class async_msg_type
{
log,
flush,
terminate
};
#include <spdlog/details/log_msg_buffer.h>
// Async msg to move to/from the queue
// Movable only. should never be copied
struct async_msg : log_msg_buffer
{
async_msg_type msg_type{async_msg_type::log};
async_logger_ptr worker_ptr;
async_msg() = default;
~async_msg() = default;
// should only be moved in or out of the queue..
async_msg(const async_msg &) = delete;
// support for vs2013 move
#if defined(_MSC_VER) && _MSC_VER <= 1800
async_msg(async_msg &&other)
: log_msg_buffer(std::move(other))
, msg_type(other.msg_type)
, worker_ptr(std::move(other.worker_ptr))
{}
async_msg &operator=(async_msg &&other)
{
*static_cast<log_msg_buffer *>(this) = std::move(other);
msg_type = other.msg_type;
worker_ptr = std::move(other.worker_ptr);
return *this;
}
#else // (_MSC_VER) && _MSC_VER <= 1800
async_msg(async_msg &&) = default;
async_msg &operator=(async_msg &&) = default;
#endif
// construct from log_msg with given type
async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m)
: log_msg_buffer{m}
, msg_type{the_type}
, worker_ptr{std::move(worker)}
{}
async_msg(async_logger_ptr &&worker, async_msg_type the_type)
: log_msg_buffer{}
, msg_type{the_type}
, worker_ptr{std::move(worker)}
{}
explicit async_msg(async_msg_type the_type)
: async_msg{nullptr, the_type}
{}
};
class SPDLOG_API thread_pool
{
public:
using item_type = async_msg;
using q_type = details::mpmc_blocking_queue<item_type>;
thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start);
thread_pool(size_t q_max_items, size_t threads_n);
// message all threads to terminate gracefully join them
~thread_pool();
thread_pool(const thread_pool &) = delete;
thread_pool &operator=(thread_pool &&) = delete;
void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy);
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy);
size_t overrun_counter();
size_t queue_size();
private:
q_type q_;
std::vector<std::thread> threads_;
void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy);
void worker_loop_();
// process next message in the queue
// return true if this thread should still be active (while no terminate msg
// was received)
bool process_next_msg_();
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "thread_pool-inl.h"
#endif

View file

@ -0,0 +1,11 @@
#pragma once
#ifndef NOMINMAX
# define NOMINMAX // prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>

View file

@ -0,0 +1,216 @@
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <cctype>
//
// Support for logging binary data as hex
// format flags, any combination of the followng:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.
// {:a} - show ASCII if :n is not set
//
// Examples:
//
// std::vector<char> v(200, 0x0b);
// logger->info("Some buffer {}", spdlog::to_hex(v));
// char buf[128];
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
namespace spdlog {
namespace details {
template<typename It>
class dump_info
{
public:
dump_info(It range_begin, It range_end, size_t size_per_line)
: begin_(range_begin)
, end_(range_end)
, size_per_line_(size_per_line)
{}
It begin() const
{
return begin_;
}
It end() const
{
return end_;
}
size_t size_per_line() const
{
return size_per_line_;
}
private:
It begin_, end_;
size_t size_per_line_;
};
} // namespace details
// create a dump_info that wraps the given container
template<typename Container>
inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container, size_t size_per_line = 32)
{
static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
using Iter = typename Container::const_iterator;
return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
}
// create dump_info from ranges
template<typename It>
inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32)
{
return details::dump_info<It>(range_begin, range_end, size_per_line);
}
} // namespace spdlog
namespace fmt {
template<typename T>
struct formatter<spdlog::details::dump_info<T>>
{
const char delimiter = ' ';
bool put_newlines = true;
bool put_delimiters = true;
bool use_uppercase = false;
bool put_positions = true; // position on start of each line
bool show_ascii = false;
// parse the format string flags
template<typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
auto it = ctx.begin();
while (it != ctx.end() && *it != '}')
{
switch (*it)
{
case 'X':
use_uppercase = true;
break;
case 's':
put_delimiters = false;
break;
case 'p':
put_positions = false;
break;
case 'n':
put_newlines = false;
show_ascii = false;
break;
case 'a':
if (put_newlines)
{
show_ascii = true;
}
break;
}
++it;
}
return it;
}
// format the given bytes range as hex
template<typename FormatContext, typename Container>
auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
{
SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
#if FMT_VERSION < 60000
auto inserter = ctx.begin();
#else
auto inserter = ctx.out();
#endif
int size_per_line = static_cast<int>(the_range.size_per_line());
auto start_of_line = the_range.begin();
for (auto i = the_range.begin(); i != the_range.end(); i++)
{
auto ch = static_cast<unsigned char>(*i);
if (put_newlines && (i == the_range.begin() || i - start_of_line >= size_per_line))
{
if (show_ascii && i != the_range.begin())
{
*inserter++ = delimiter;
*inserter++ = delimiter;
for (auto j = start_of_line; j < i; j++)
{
auto pc = static_cast<unsigned char>(*j);
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
}
}
put_newline(inserter, static_cast<size_t>(i - the_range.begin()));
// put first byte without delimiter in front of it
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f];
start_of_line = i;
continue;
}
if (put_delimiters)
{
*inserter++ = delimiter;
}
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
*inserter++ = hex_chars[ch & 0x0f];
}
if (show_ascii) // add ascii to last line
{
if (the_range.end() - the_range.begin() > size_per_line)
{
auto blank_num = size_per_line - (the_range.end() - start_of_line);
while (blank_num-- > 0)
{
*inserter++ = delimiter;
*inserter++ = delimiter;
if (put_delimiters)
{
*inserter++ = delimiter;
}
}
}
*inserter++ = delimiter;
*inserter++ = delimiter;
for (auto j = start_of_line; j != the_range.end(); j++)
{
auto pc = static_cast<unsigned char>(*j);
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
}
}
return inserter;
}
// put newline(and position header)
template<typename It>
void put_newline(It inserter, std::size_t pos)
{
#ifdef _WIN32
*inserter++ = '\r';
#endif
*inserter++ = '\n';
if (put_positions)
{
fmt::format_to(inserter, "{:04X}: ", pos);
}
}
};
} // namespace fmt

View file

@ -0,0 +1,232 @@
// Formatting library for C++ - dynamic format arguments
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_ARGS_H_
#define FMT_ARGS_H_
#include <functional> // std::reference_wrapper
#include <memory> // std::unique_ptr
#include <vector>
#include "core.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T> struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T> const T& unwrap(const T& v) { return v; }
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
return static_cast<const T&>(v);
}
class dynamic_arg_list {
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
// templates it doesn't complain about inability to deduce single translation
// unit for placing vtable. So storage_node_base is made a fake template.
template <typename = void> struct node {
virtual ~node() = default;
std::unique_ptr<node<>> next;
};
template <typename T> struct typed_node : node<> {
T value;
template <typename Arg>
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
template <typename Char>
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
: value(arg.data(), arg.size()) {}
};
std::unique_ptr<node<>> head_;
public:
template <typename T, typename Arg> const T& push(const Arg& arg) {
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
auto& value = new_node->value;
new_node->next = std::move(head_);
head_ = std::move(new_node);
return value;
}
};
} // namespace detail
/**
\rst
A dynamic version of `fmt::format_arg_store`.
It's equipped with a storage to potentially temporary objects which lifetimes
could be shorter than the format arguments object.
It can be implicitly converted into `~fmt::basic_format_args` for passing
into type-erased formatting functions such as `~fmt::vformat`.
\endrst
*/
template <typename Context>
class dynamic_format_arg_store
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround a GCC template argument substitution bug.
: public basic_format_args<Context>
#endif
{
private:
using char_type = typename Context::char_type;
template <typename T> struct need_copy {
static constexpr detail::type mapped_type =
detail::mapped_type_constant<T, Context>::value;
enum {
value = !(detail::is_reference_wrapper<T>::value ||
std::is_same<T, basic_string_view<char_type>>::value ||
std::is_same<T, detail::std_string_view<char_type>>::value ||
(mapped_type != detail::type::cstring_type &&
mapped_type != detail::type::string_type &&
mapped_type != detail::type::custom_type))
};
};
template <typename T>
using stored_type = conditional_t<detail::is_string<T>::value &&
!has_formatter<T, Context>::value &&
!detail::is_reference_wrapper<T>::value,
std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
std::vector<detail::named_arg_info<char_type>> named_info_;
// Storage of arguments not fitting into basic_format_arg must grow
// without relocation because items in data_ refer to it.
detail::dynamic_arg_list dynamic_args_;
friend class basic_format_args<Context>;
unsigned long long get_types() const {
return detail::is_unpacked_bit | data_.size() |
(named_info_.empty()
? 0ULL
: static_cast<unsigned long long>(detail::has_named_args_bit));
}
const basic_format_arg<Context>* data() const {
return named_info_.empty() ? data_.data() : data_.data() + 1;
}
template <typename T> void emplace_arg(const T& arg) {
data_.emplace_back(detail::make_arg<Context>(arg));
}
template <typename T>
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
if (named_info_.empty()) {
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
data_.insert(data_.begin(), {zero_ptr, 0});
}
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
data->pop_back();
};
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
guard{&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
guard.release();
}
public:
/**
\rst
Adds an argument into the dynamic store for later passing to a formatting
function.
Note that custom types and string types (but not string views) are copied
into the store dynamically allocating memory if necessary.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(42);
store.push_back("abc");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
\endrst
*/
template <typename T> void push_back(const T& arg) {
if (detail::const_check(need_copy<T>::value))
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
else
emplace_arg(detail::unwrap(arg));
}
/**
\rst
Adds a reference to the argument into the dynamic store for later passing to
a formatting function.
**Example**::
fmt::dynamic_format_arg_store<fmt::format_context> store;
char band[] = "Rolling Stones";
store.push_back(std::cref(band));
band[9] = 'c'; // Changing str affects the output.
std::string result = fmt::vformat("{}", store);
// result == "Rolling Scones"
\endrst
*/
template <typename T> void push_back(std::reference_wrapper<T> arg) {
static_assert(
need_copy<T>::value,
"objects of built-in types and string views are always copied");
emplace_arg(arg.get());
}
/**
Adds named argument into the dynamic store for later passing to a formatting
function. ``std::reference_wrapper`` is supported to avoid copying of the
argument. The name is always copied into the store.
*/
template <typename T>
void push_back(const detail::named_arg<char_type, T>& arg) {
const char_type* arg_name =
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
if (detail::const_check(need_copy<T>::value)) {
emplace_arg(
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
} else {
emplace_arg(fmt::arg(arg_name, arg.value));
}
}
/** Erase all elements from the store */
void clear() {
data_.clear();
named_info_.clear();
dynamic_args_ = detail::dynamic_arg_list();
}
/**
\rst
Reserves space to store at least *new_cap* arguments including
*new_cap_named* named arguments.
\endrst
*/
void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named,
"Set of arguments includes set of named arguments");
data_.reserve(new_cap);
named_info_.reserve(new_cap_named);
}
};
FMT_END_NAMESPACE
#endif // FMT_ARGS_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,627 @@
// Formatting library for C++ - color support
//
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COLOR_H_
#define FMT_COLOR_H_
#include "format.h"
// __declspec(deprecated) is broken in some MSVC versions.
#if FMT_MSC_VER
# define FMT_DEPRECATED_NONMSVC
#else
# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
#endif
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32 // rgb(154,205,50)
}; // enum class color
enum class terminal_color : uint8_t {
black = 30,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
bright_black = 90,
bright_red,
bright_green,
bright_yellow,
bright_blue,
bright_magenta,
bright_cyan,
bright_white
};
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
};
// rgb is a struct for red, green and blue colors.
// Using the name "rgb" makes some editors show the color in a tooltip.
struct rgb {
FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
FMT_CONSTEXPR rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF),
g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
uint8_t r;
uint8_t g;
uint8_t b;
};
FMT_BEGIN_DETAIL_NAMESPACE
// color is a struct of either a rgb color or a terminal color.
struct color_type {
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
union color_union {
uint8_t term_color;
uint32_t rgb_color;
} value;
};
FMT_END_DETAIL_NAMESPACE
/** A text style consisting of foreground and background colors and emphasis. */
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems(em) {}
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
FMT_THROW(format_error("can't OR a terminal color"));
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
FMT_THROW(format_error("can't OR a terminal color"));
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR text_style operator|(text_style lhs,
const text_style& rhs) {
return lhs |= rhs;
}
FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
const text_style& rhs) {
return and_assign(rhs);
}
FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
operator&(text_style lhs, const text_style& rhs) {
return lhs.and_assign(rhs);
}
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
return set_foreground_color;
}
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
return set_background_color;
}
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
FMT_ASSERT(has_background(), "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
detail::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
} else {
background_color = text_color;
set_background_color = true;
}
}
// DEPRECATED!
FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color"));
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
FMT_THROW(format_error("can't AND a terminal color"));
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
FMT_NOEXCEPT;
detail::color_type foreground_color;
detail::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
/** Creates a text style from the foreground (text) color. */
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
return text_style(true, foreground);
}
/** Creates a text style from the background color. */
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
return text_style(false, background);
}
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
emphasis rhs) FMT_NOEXCEPT {
return text_style(lhs) | rhs;
}
FMT_BEGIN_DETAIL_NAMESPACE
template <typename Char> struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
const char* esc) FMT_NOEXCEPT {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
bool is_background = esc == string_view("\x1b[48;2;");
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background) value += 10u;
size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
if (value >= 100u) {
buffer[index++] = static_cast<Char>('1');
value %= 100u;
}
buffer[index++] = static_cast<Char>('0' + value / 10u);
buffer[index++] = static_cast<Char>('0' + value % 10u);
buffer[index++] = static_cast<Char>('m');
buffer[index++] = static_cast<Char>('\0');
return;
}
for (int i = 0; i < 7; i++) {
buffer[i] = static_cast<Char>(esc[i]);
}
rgb color(text_color.value.rgb_color);
to_esc(color.r, buffer + 7, ';');
to_esc(color.g, buffer + 11, ';');
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
uint8_t em_codes[4] = {};
uint8_t em_bits = static_cast<uint8_t>(em);
if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
em_codes[3] = 9;
size_t index = 0;
for (int i = 0; i < 4; ++i) {
if (!em_codes[i]) continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
buffer[index++] = static_cast<Char>('m');
}
buffer[index++] = static_cast<Char>(0);
}
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
return buffer + std::char_traits<Char>::length(buffer);
}
private:
Char buffer[7u + 3u * 4u + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
char delimiter) FMT_NOEXCEPT {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
};
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
detail::color_type foreground) FMT_NOEXCEPT {
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
detail::color_type background) FMT_NOEXCEPT {
return ansi_color_escape<Char>(background, "\x1b[48;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
return ansi_color_escape<Char>(em);
}
template <typename Char>
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
std::fputs(chars, stream);
}
template <>
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
std::fputws(chars, stream);
}
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
fputs("\x1b[0m", stream);
}
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
fputs(L"\x1b[0m", stream);
}
template <typename Char>
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
auto reset_color = string_view("\x1b[0m");
buffer.append(reset_color.begin(), reset_color.end());
}
template <typename Char>
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
buf.append(emphasis.begin(), emphasis.end());
}
if (ts.has_foreground()) {
has_style = true;
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground());
buf.append(foreground.begin(), foreground.end());
}
if (ts.has_background()) {
has_style = true;
auto background = detail::make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
}
detail::vformat_to(buf, format_str, args, {});
if (has_style) detail::reset_color<Char>(buf);
}
FMT_END_DETAIL_NAMESPACE
template <typename S, typename Char = char_t<S>>
void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
detail::vformat_to(buf, ts, to_string_view(format), args);
buf.push_back(Char(0));
detail::fputs(buf.data(), f);
}
/**
\rst
Formats a string and prints it to the specified file stream using ANSI
escape sequences to specify text formatting.
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
vprint(f, ts, format_str,
fmt::make_args_checked<Args...>(format_str, args...));
}
/**
\rst
Formats a string and prints it to stdout using ANSI escape sequences to
specify text formatting.
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(const text_style& ts, const S& format_str, const Args&... args) {
return print(stdout, ts, format_str, args...);
}
template <typename S, typename Char = char_t<S>>
inline std::basic_string<Char> vformat(
const text_style& ts, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
detail::vformat_to(buf, ts, to_string_view(format_str), args);
return fmt::to_string(buf);
}
/**
\rst
Formats arguments and returns the result as a string using ANSI
escape sequences to specify text formatting.
**Example**::
#include <fmt/color.h>
std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red),
"The answer is {}", 42);
\endrst
*/
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
const Args&... args) {
return fmt::vformat(ts, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
}
/**
Formats a string with the given text_style and writes the output to ``out``.
*/
template <typename OutputIt, typename Char,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
OutputIt vformat_to(
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, ts, format_str, args);
return detail::get_iterator(buf);
}
/**
\rst
Formats arguments with the given text_style, writes the result to the output
iterator ``out`` and returns the iterator past the end of the output range.
**Example**::
std::vector<char> out;
fmt::format_to(std::back_inserter(out),
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&&
detail::is_string<S>::value>
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, ts, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

View file

@ -0,0 +1,639 @@
// Formatting library for C++ - experimental format string compilation
//
// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COMPILE_H_
#define FMT_COMPILE_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace detail {
// An output iterator that counts the number of objects written to it and
// discards them.
class counting_iterator {
private:
size_t count_;
public:
using iterator_category = std::output_iterator_tag;
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = void;
using _Unchecked_type = counting_iterator; // Mark iterator as checked.
struct value_type {
template <typename T> void operator=(const T&) {}
};
counting_iterator() : count_(0) {}
size_t count() const { return count_; }
counting_iterator& operator++() {
++count_;
return *this;
}
counting_iterator operator++(int) {
auto it = *this;
++*this;
return it;
}
friend counting_iterator operator+(counting_iterator it, difference_type n) {
it.count_ += static_cast<size_t>(n);
return it;
}
value_type operator*() const { return {}; }
};
template <typename Char, typename InputIt>
inline counting_iterator copy_str(InputIt begin, InputIt end,
counting_iterator it) {
return it + (end - begin);
}
template <typename OutputIt> class truncating_iterator_base {
protected:
OutputIt out_;
size_t limit_;
size_t count_ = 0;
truncating_iterator_base() : out_(), limit_(0) {}
truncating_iterator_base(OutputIt out, size_t limit)
: out_(out), limit_(limit) {}
public:
using iterator_category = std::output_iterator_tag;
using value_type = typename std::iterator_traits<OutputIt>::value_type;
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = void;
using _Unchecked_type =
truncating_iterator_base; // Mark iterator as checked.
OutputIt base() const { return out_; }
size_t count() const { return count_; }
};
// An output iterator that truncates the output and counts the number of objects
// written to it.
template <typename OutputIt,
typename Enable = typename std::is_void<
typename std::iterator_traits<OutputIt>::value_type>::type>
class truncating_iterator;
template <typename OutputIt>
class truncating_iterator<OutputIt, std::false_type>
: public truncating_iterator_base<OutputIt> {
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
public:
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
truncating_iterator() = default;
truncating_iterator(OutputIt out, size_t limit)
: truncating_iterator_base<OutputIt>(out, limit) {}
truncating_iterator& operator++() {
if (this->count_++ < this->limit_) ++this->out_;
return *this;
}
truncating_iterator operator++(int) {
auto it = *this;
++*this;
return it;
}
value_type& operator*() const {
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
}
};
template <typename OutputIt>
class truncating_iterator<OutputIt, std::true_type>
: public truncating_iterator_base<OutputIt> {
public:
truncating_iterator() = default;
truncating_iterator(OutputIt out, size_t limit)
: truncating_iterator_base<OutputIt>(out, limit) {}
template <typename T> truncating_iterator& operator=(T val) {
if (this->count_++ < this->limit_) *this->out_++ = val;
return *this;
}
truncating_iterator& operator++() { return *this; }
truncating_iterator& operator++(int) { return *this; }
truncating_iterator& operator*() { return *this; }
};
// A compile-time string which is compiled into fast formatting code.
class compiled_string {};
template <typename S>
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
/**
\rst
Converts a string literal *s* into a format string that will be parsed at
compile time and converted into efficient formatting code. Requires C++17
``constexpr if`` compiler support.
**Example**::
// Converts 42 into std::string using the most efficient method and no
// runtime format string processing.
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
\endrst
*/
#ifdef __cpp_if_constexpr
# define FMT_COMPILE(s) \
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
#else
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
template <typename Char, size_t N,
fmt::detail_exported::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
constexpr operator basic_string_view<char_type>() const {
return {Str.data, N - 1};
}
};
#endif
template <typename T, typename... Tail>
const T& first(const T& value, const Tail&...) {
return value;
}
#ifdef __cpp_if_constexpr
template <typename... Args> struct type_list {};
// Returns a reference to the argument at index N from [first, rest...].
template <int N, typename T, typename... Args>
constexpr const auto& get([[maybe_unused]] const T& first,
[[maybe_unused]] const Args&... rest) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
else
return get<N - 1>(rest...);
}
template <typename Char, typename... Args>
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
type_list<Args...>) {
return get_arg_index_by_name<Args...>(name);
}
template <int N, typename> struct get_type_impl;
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
};
template <int N, typename T>
using get_type = typename get_type_impl<N, T>::type;
template <typename T> struct is_compiled_format : std::false_type {};
template <typename Char> struct text {
basic_string_view<Char> data;
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, data);
}
};
template <typename Char>
struct is_compiled_format<text<Char>> : std::true_type {};
template <typename Char>
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
size_t size) {
return {{&s[pos], size}};
}
template <typename Char> struct code_unit {
Char value;
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, value);
}
};
// This ensures that the argument type is convertible to `const T&`.
template <typename T, int N, typename... Args>
constexpr const T& get_arg_checked(const Args&... args) {
const auto& arg = get<N>(args...);
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
return arg.value;
} else {
return arg;
}
}
template <typename Char>
struct is_compiled_format<code_unit<Char>> : std::true_type {};
// A replacement field that refers to argument N.
template <typename Char, typename T, int N> struct field {
using char_type = Char;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
return write<Char>(out, get_arg_checked<T, N>(args...));
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
// A replacement field that refers to argument with name.
template <typename Char> struct runtime_named_field {
using char_type = Char;
basic_string_view<Char> name;
template <typename OutputIt, typename T>
constexpr static bool try_format_argument(
OutputIt& out,
// [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) {
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
if (arg_name == arg.name) {
out = write<Char>(out, arg.value);
return true;
}
}
return false;
}
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
bool found = (try_format_argument(out, name, args) || ...);
if (!found) {
throw format_error("argument with specified name is not found");
}
return out;
}
};
template <typename Char>
struct is_compiled_format<runtime_named_field<Char>> : std::true_type {};
// A replacement field that refers to argument N and has format specifiers.
template <typename Char, typename T, int N> struct spec_field {
using char_type = Char;
formatter<T, Char> fmt;
template <typename OutputIt, typename... Args>
constexpr FMT_INLINE OutputIt format(OutputIt out,
const Args&... args) const {
const auto& vargs =
fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...);
basic_format_context<OutputIt, Char> ctx(out, vargs);
return fmt.format(get_arg_checked<T, N>(args...), ctx);
}
};
template <typename Char, typename T, int N>
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
template <typename L, typename R> struct concat {
L lhs;
R rhs;
using char_type = typename L::char_type;
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
out = lhs.format(out, args...);
return rhs.format(out, args...);
}
};
template <typename L, typename R>
struct is_compiled_format<concat<L, R>> : std::true_type {};
template <typename L, typename R>
constexpr concat<L, R> make_concat(L lhs, R rhs) {
return {lhs, rhs};
}
struct unknown_format {};
template <typename Char>
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
for (size_t size = str.size(); pos != size; ++pos) {
if (str[pos] == '{' || str[pos] == '}') break;
}
return pos;
}
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S format_str);
template <typename Args, size_t POS, int ID, typename T, typename S>
constexpr auto parse_tail(T head, S format_str) {
if constexpr (POS !=
basic_string_view<typename S::char_type>(format_str).size()) {
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
unknown_format>())
return tail;
else
return make_concat(head, tail);
} else {
return head;
}
}
template <typename T, typename Char> struct parse_specs_result {
formatter<T, Char> fmt;
size_t end;
int next_arg_id;
};
constexpr int manual_indexing_id = -1;
template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos, int next_arg_id) {
str.remove_prefix(pos);
auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
}
template <typename Char> struct arg_id_handler {
arg_ref<Char> arg_id;
constexpr int operator()() {
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
return 0;
}
constexpr int operator()(int id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr int operator()(basic_string_view<Char> id) {
arg_id = arg_ref<Char>(id);
return 0;
}
constexpr void on_error(const char* message) { throw format_error(message); }
};
template <typename Char> struct parse_arg_id_result {
arg_ref<Char> arg_id;
const Char* arg_id_end;
};
template <int ID, typename Char>
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
auto arg_id_end = parse_arg_id(begin, end, handler);
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
}
template <typename T, typename Enable = void> struct field_type {
using type = remove_cvref_t<T>;
};
template <typename T>
struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> {
using type = remove_cvref_t<decltype(T::value)>;
};
template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
typename S>
constexpr auto parse_replacement_field_then_tail(S format_str) {
using char_type = typename S::char_type;
constexpr auto str = basic_string_view<char_type>(format_str);
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
if constexpr (c == '}') {
return parse_tail<Args, END_POS + 1, NEXT_ID>(
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
format_str);
} else if constexpr (c == ':') {
constexpr auto result = parse_specs<typename field_type<T>::type>(
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
return parse_tail<Args, result.end, result.next_arg_id>(
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
result.fmt},
format_str);
}
}
// Compiles a non-empty format string and returns the compiled representation
// or unknown_format() on unrecognized input.
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S format_str) {
using char_type = typename S::char_type;
constexpr auto str = basic_string_view<char_type>(format_str);
if constexpr (str[POS] == '{') {
if constexpr (POS + 1 == str.size())
throw format_error("unmatched '{' in format string");
if constexpr (str[POS + 1] == '{') {
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') {
static_assert(ID != manual_indexing_id,
"cannot switch from manual to automatic argument indexing");
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<get_type<ID, Args>, Args,
POS + 1, ID, next_id>(
format_str);
} else {
constexpr auto arg_id_result =
parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size());
constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data();
constexpr char_type c =
arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type();
static_assert(c == '}' || c == ':', "missing '}' in format string");
if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) {
static_assert(
ID == manual_indexing_id || ID == 0,
"cannot switch from automatic to manual argument indexing");
constexpr auto arg_index = arg_id_result.arg_id.val.index;
return parse_replacement_field_then_tail<get_type<arg_index, Args>,
Args, arg_id_end_pos,
arg_index, manual_indexing_id>(
format_str);
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
constexpr auto arg_index =
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
if constexpr (arg_index != invalid_arg_index) {
constexpr auto next_id =
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
return parse_replacement_field_then_tail<
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
arg_index, next_id>(format_str);
} else {
if constexpr (c == '}') {
return parse_tail<Args, arg_id_end_pos + 1, ID>(
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
format_str);
} else if constexpr (c == ':') {
return unknown_format(); // no type info for specs parsing
}
}
}
}
} else if constexpr (str[POS] == '}') {
if constexpr (POS + 1 == str.size())
throw format_error("unmatched '}' in format string");
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else {
constexpr auto end = parse_text(str, POS + 1);
if constexpr (end - POS > 1) {
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
} else {
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
format_str);
}
}
}
template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
constexpr auto compile(S format_str) {
constexpr auto str = basic_string_view<typename S::char_type>(format_str);
if constexpr (str.size() == 0) {
return detail::make_text(str, 0, 0);
} else {
constexpr auto result =
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
format_str);
return result;
}
}
#endif // __cpp_if_constexpr
} // namespace detail
FMT_MODULE_EXPORT_BEGIN
#ifdef __cpp_if_constexpr
template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
const Args&... args) {
auto s = std::basic_string<Char>();
cf.format(std::back_inserter(s), args...);
return s;
}
template <typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
const Args&... args) {
return cf.format(out, args...);
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
const auto& first = detail::first(args...);
if constexpr (detail::is_named_arg<
remove_cvref_t<decltype(first)>>::value) {
return fmt::to_string(first.value);
} else {
return fmt::to_string(first);
}
}
}
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return format(compiled, std::forward<Args>(args)...);
}
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
return format_to(out,
static_cast<basic_string_view<typename S::char_type>>(S()),
std::forward<Args>(args)...);
} else {
return format_to(out, compiled, std::forward<Args>(args)...);
}
}
#endif
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const S& format_str, Args&&... args) {
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
std::forward<Args>(args)...);
return {it.base(), it.count()};
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
size_t formatted_size(const S& format_str, const Args&... args) {
return format_to(detail::counting_iterator(), format_str, args...).count();
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(std::FILE* f, const S& format_str, const Args&... args) {
memory_buffer buffer;
format_to(std::back_inserter(buffer), format_str, args...);
detail::print(f, {buffer.data(), buffer.size()});
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(const S& format_str, const Args&... args) {
print(stdout, format_str, args...);
}
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
inline namespace literals {
template <detail_exported::fixed_string Str>
constexpr detail::udl_compiled_string<
remove_cvref_t<decltype(Str.data[0])>,
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
operator""_cf() {
return {};
}
} // namespace literals
#endif
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_COMPILE_H_

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
#include "xchar.h"
#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead

View file

@ -0,0 +1,515 @@
// Formatting library for C++ - optional OS-specific functionality
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OS_H_
#define FMT_OS_H_
#include <cerrno>
#include <clocale> // locale_t
#include <cstddef>
#include <cstdio>
#include <cstdlib> // strtod_l
#include <system_error> // std::system_error
#if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif
#include "format.h"
// UWP doesn't provide _pipe.
#if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
#endif
#if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
#else
# define FMT_USE_FCNTL 0
#endif
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) ::call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
(result) = (expression); \
} while ((result) == (error_result) && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
/**
\rst
A reference to a null-terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following type aliases for common character types:
+---------------+-----------------------------+
| Type | Definition |
+===============+=============================+
| cstring_view | basic_cstring_view<char> |
+---------------+-----------------------------+
| wcstring_view | basic_cstring_view<wchar_t> |
+---------------+-----------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(cstring_view format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char> class basic_cstring_view {
private:
const Char* data_;
public:
/** Constructs a string reference object from a C string. */
basic_cstring_view(const Char* s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char* c_str() const { return data_; }
};
using cstring_view = basic_cstring_view<char>;
using wcstring_view = basic_cstring_view<wchar_t>;
template <typename Char> struct formatter<std::error_code, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
out = detail::write_bytes(out, ec.category().name(),
basic_format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
}
};
#ifdef _WIN32
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
FMT_BEGIN_DETAIL_NAMESPACE
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
class utf16_to_utf8 {
private:
memory_buffer buffer_;
public:
utf16_to_utf8() {}
FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s);
operator string_view() const { return string_view(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char* c_str() const { return &buffer_[0]; }
std::string str() const { return std::string(&buffer_[0], size()); }
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
FMT_API int convert(basic_string_view<wchar_t> s);
};
FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) FMT_NOEXCEPT;
FMT_END_DETAIL_NAMESPACE
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
format_args args);
/**
\rst
Constructs a :class:`std::system_error` object with the description
of the form
.. parsed-literal::
*<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is the
system message corresponding to the error code.
*error_code* is a Windows error code as given by ``GetLastError``.
If *error_code* is not a valid error code such as -1, the system message
will look like "error -1".
**Example**::
// This throws a system_error with the description
// cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary).
const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR) {
throw fmt::windows_error(GetLastError(),
"cannot open file '{}'", filename);
}
\endrst
*/
template <typename... Args>
std::system_error windows_error(int error_code, string_view message,
const Args&... args) {
return vwindows_error(error_code, message, fmt::make_format_args(args...));
}
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
FMT_API void report_windows_error(int error_code,
const char* message) FMT_NOEXCEPT;
#else
inline const std::error_category& system_category() FMT_NOEXCEPT {
return std::system_category();
}
#endif // _WIN32
// std::system is not available on some platforms such as iOS (#2248).
#ifdef __OSX__
template <typename S, typename... Args, typename Char = char_t<S>>
void say(const S& format_str, Args&&... args) {
std::system(format("say \"{}\"", format(format_str, args...)).c_str());
}
#endif
// A buffered file.
class buffered_file {
private:
FILE* file_;
friend class file;
explicit buffered_file(FILE* f) : file_(f) {}
public:
buffered_file(const buffered_file&) = delete;
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_NOEXCEPT;
public:
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = nullptr;
}
buffered_file& operator=(buffered_file&& other) {
close();
file_ = other.file_;
other.file_ = nullptr;
return *this;
}
// Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file.
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
FILE* get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
FMT_API int(fileno)() const;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
}
template <typename... Args>
inline void print(string_view format_str, const Args&... args) {
vprint(format_str, fmt::make_format_args(args...));
}
};
#if FMT_USE_FCNTL
// A file. Closed file is represented by a file object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class file {
private:
int fd_; // File descriptor.
// Constructs a file object with a given descriptor.
explicit file(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
APPEND = FMT_POSIX(O_APPEND), // Open in append mode.
TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file.
};
// Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag);
public:
file(const file&) = delete;
void operator=(const file&) = delete;
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
// Move assignment is not noexcept because close may throw.
file& operator=(file&& other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
FMT_API void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
FMT_API long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
FMT_API size_t read(void* buffer, size_t count);
// Attempts to write count bytes from the specified buffer to the file.
FMT_API size_t write(const void* buffer, size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
FMT_API static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
FMT_API static void pipe(file& read_end, file& write_end);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
FMT_API buffered_file fdopen(const char* mode);
};
// Returns the memory page size.
long getpagesize();
FMT_BEGIN_DETAIL_NAMESPACE
struct buffer_size {
buffer_size() = default;
size_t value = 0;
buffer_size operator=(size_t val) const {
auto bs = buffer_size();
bs.value = val;
return bs;
}
};
struct ostream_params {
int oflag = file::WRONLY | file::CREATE | file::TRUNC;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
ostream_params() {}
template <typename... T>
ostream_params(T... params, int new_oflag) : ostream_params(params...) {
oflag = new_oflag;
}
template <typename... T>
ostream_params(T... params, detail::buffer_size bs)
: ostream_params(params...) {
this->buffer_size = bs.value;
}
};
FMT_END_DETAIL_NAMESPACE
constexpr detail::buffer_size buffer_size;
/** A fast output stream which is not thread-safe. */
class FMT_API ostream final : private detail::buffer<char> {
private:
file file_;
void flush() {
if (size() == 0) return;
file_.write(data(), size());
clear();
}
void grow(size_t) override;
ostream(cstring_view path, const detail::ostream_params& params)
: file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
public:
ostream(ostream&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.clear();
other.set(nullptr, 0);
}
~ostream() {
flush();
delete[] data();
}
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() {
flush();
file_.close();
}
/**
Formats ``args`` according to specifications in ``fmt`` and writes the
output to the file.
*/
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(detail::buffer_appender<char>(*this), fmt,
fmt::make_format_args(args...));
}
};
/**
\rst
Opens a file for writing. Supported parameters passed in *params*:
* ``<integer>``: Flags passed to `open
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
(``file::WRONLY | file::CREATE`` by default)
* ``buffer_size=<integer>``: Output buffer size
**Example**::
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
\endrst
*/
template <typename... T>
inline ostream output_file(cstring_view path, T... params) {
return {path, detail::ostream_params(params...)};
}
#endif // FMT_USE_FCNTL
#ifdef FMT_LOCALE
// A "C" numeric locale.
class locale {
private:
# ifdef _WIN32
using locale_t = _locale_t;
static void freelocale(locale_t loc) { _free_locale(loc); }
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
return _strtod_l(nptr, endptr, loc);
}
# endif
locale_t locale_;
public:
using type = locale_t;
locale(const locale&) = delete;
void operator=(const locale&) = delete;
locale() {
# ifndef _WIN32
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
# else
locale_ = _create_locale(LC_NUMERIC, "C");
# endif
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
}
~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 = nullptr;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
};
using Locale FMT_DEPRECATED_ALIAS = locale;
#endif // FMT_LOCALE
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_OS_H_

View file

@ -0,0 +1,181 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
#include <ostream>
#include "format.h"
FMT_BEGIN_NAMESPACE
template <typename Char> class basic_printf_parse_context;
template <typename OutputIt, typename Char> class basic_printf_context;
namespace detail {
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
private:
using int_type = typename std::basic_streambuf<Char>::int_type;
using traits_type = typename std::basic_streambuf<Char>::traits_type;
buffer<Char>& buffer_;
public:
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
protected:
// The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call
// to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch));
return ch;
}
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
return count;
}
};
struct converter {
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
};
template <typename Char> struct test_stream : std::basic_ostream<Char> {
private:
void_t<> operator<<(converter);
};
// Hide insertion operators for built-in types.
template <typename Char, typename Traits>
void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char);
template <typename Char, typename Traits>
void_t<> operator<<(std::basic_ostream<Char, Traits>&, char);
template <typename Traits>
void_t<> operator<<(std::basic_ostream<char, Traits>&, char);
template <typename Traits>
void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char);
template <typename Traits>
void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char);
// Checks if T has a user-defined operator<< (e.g. not a member of
// std::ostream).
template <typename T, typename Char> class is_streamable {
private:
template <typename U>
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
<< std::declval<U>()),
void_t<>>::value>
test(int);
template <typename> static std::false_type test(...);
using result = decltype(test<T>(0));
public:
is_streamable() = default;
static const bool value = result::value;
};
// Write the content of buf to os.
template <typename Char>
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
const Char* buf_data = buf.data();
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
unsigned_streamsize size = buf.size();
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
do {
unsigned_streamsize n = size <= max_size ? size : max_size;
os.write(buf_data, static_cast<std::streamsize>(n));
buf_data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
void format_value(buffer<Char>& buf, const T& value,
locale_ref loc = locale_ref()) {
formatbuf<Char> format_buf(buf);
std::basic_ostream<Char> output(&format_buf);
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
if (loc) output.imbue(loc.get<std::locale>());
#endif
output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
buf.try_resize(buf.size());
}
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
: private formatter<basic_string_view<Char>, Char> {
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
return formatter<basic_string_view<Char>, Char>::parse(ctx);
}
template <typename ParseCtx,
FMT_ENABLE_IF(std::is_same<
ParseCtx, basic_printf_parse_context<Char>>::value)>
auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename OutputIt>
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
-> OutputIt {
basic_memory_buffer<Char> buffer;
format_value(buffer, value, ctx.locale());
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
template <typename OutputIt>
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
-> OutputIt {
basic_memory_buffer<Char> buffer;
format_value(buffer, value, ctx.locale());
return std::copy(buffer.begin(), buffer.end(), ctx.out());
}
};
} // namespace detail
FMT_MODULE_EXPORT
template <typename Char>
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buffer;
detail::vformat_to(buffer, format_str, args);
detail::write_buffer(os, buffer);
}
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_MODULE_EXPORT
template <typename S, typename... Args,
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
vprint(os, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
}
FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_

View file

@ -0,0 +1,652 @@
// Formatting library for C++ - legacy printf implementation
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
#include <algorithm> // std::max
#include <limits> // std::numeric_limits
#include <ostream>
#include "format.h"
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
template <typename T> struct printf_formatter { printf_formatter() = delete; };
template <typename Char>
class basic_printf_parse_context : public basic_format_parse_context<Char> {
using basic_format_parse_context<Char>::basic_format_parse_context;
};
template <typename OutputIt, typename Char> class basic_printf_context {
private:
OutputIt out_;
basic_format_args<basic_printf_context> args_;
public:
using char_type = Char;
using format_arg = basic_format_arg<basic_printf_context>;
using parse_context_type = basic_printf_parse_context<Char>;
template <typename T> using formatter_type = printf_formatter<T>;
/**
\rst
Constructs a ``printf_context`` object. References to the arguments are
stored in the context object so make sure they have appropriate lifetimes.
\endrst
*/
basic_printf_context(OutputIt out,
basic_format_args<basic_printf_context> args)
: out_(out), args_(args) {}
OutputIt out() { return out_; }
void advance_to(OutputIt it) { out_ = it; }
detail::locale_ref locale() { return {}; }
format_arg arg(int id) const { return args_.get(id); }
FMT_CONSTEXPR void on_error(const char* message) {
detail::error_handler().on_error(message);
}
};
FMT_BEGIN_DETAIL_NAMESPACE
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned> struct int_checker {
template <typename T> static bool fits_in_int(T value) {
unsigned max = max_value<int>();
return value <= max;
}
static bool fits_in_int(bool) { return true; }
};
template <> struct int_checker<true> {
template <typename T> static bool fits_in_int(T value) {
return value >= (std::numeric_limits<int>::min)() &&
value <= max_value<int>();
}
static bool fits_in_int(int) { return true; }
};
class printf_precision_handler {
public:
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
int operator()(T value) {
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big"));
return (std::max)(static_cast<int>(value), 0);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
int operator()(T) {
FMT_THROW(format_error("precision is not integer"));
return 0;
}
};
// An argument visitor that returns true iff arg is a zero integer.
class is_zero_int {
public:
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
bool operator()(T value) {
return value == 0;
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
bool operator()(T) {
return false;
}
};
template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
template <> struct make_unsigned_or_bool<bool> { using type = bool; };
template <typename T, typename Context> class arg_converter {
private:
using char_type = typename Context::char_type;
basic_format_arg<Context>& arg_;
char_type type_;
public:
arg_converter(basic_format_arg<Context>& arg, char_type type)
: arg_(arg), type_(type) {}
void operator()(bool value) {
if (type_ != 's') operator()<bool>(value);
}
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
void operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = detail::make_arg<Context>(
static_cast<int>(static_cast<target_type>(value)));
} else {
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
arg_ = detail::make_arg<Context>(
static_cast<unsigned>(static_cast<unsigned_type>(value)));
}
} else {
if (is_signed) {
// 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_ = detail::make_arg<Context>(static_cast<long long>(value));
} else {
arg_ = detail::make_arg<Context>(
static_cast<typename make_unsigned_or_bool<U>::type>(value));
}
}
}
template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)>
void operator()(U) {} // No conversion needed for non-integral types.
};
// Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context>& arg, Char type) {
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
}
// Converts an integer argument to char for printf.
template <typename Context> class char_converter {
private:
basic_format_arg<Context>& arg_;
public:
explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
void operator()(T value) {
arg_ = detail::make_arg<Context>(
static_cast<typename Context::char_type>(value));
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
void operator()(T) {} // No conversion needed for non-integral types.
};
// An argument visitor that return a pointer to a C string if argument is a
// string or null otherwise.
template <typename Char> struct get_cstring {
template <typename T> const Char* operator()(T) { return nullptr; }
const Char* operator()(const Char* s) { return s; }
};
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
template <typename Char> class printf_width_handler {
private:
using format_specs = basic_format_specs<Char>;
format_specs& specs_;
public:
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
unsigned operator()(T value) {
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
if (detail::is_negative(value)) {
specs_.align = align::left;
width = 0 - width;
}
unsigned int_max = max_value<int>();
if (width > int_max) FMT_THROW(format_error("number is too big"));
return static_cast<unsigned>(width);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
unsigned operator()(T) {
FMT_THROW(format_error("width is not integer"));
return 0;
}
};
// The ``printf`` argument formatter.
template <typename OutputIt, typename Char>
class printf_arg_formatter : public arg_formatter<Char> {
private:
using base = arg_formatter<Char>;
using context_type = basic_printf_context<OutputIt, Char>;
using format_specs = basic_format_specs<Char>;
context_type& context_;
OutputIt write_null_pointer(bool is_string = false) {
auto s = this->specs;
s.type = 0;
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
}
public:
printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
: base{iter, s, locale_ref()}, context_(ctx) {}
OutputIt operator()(monostate value) { return base::operator()(value); }
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
OutputIt operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (std::is_same<T, Char>::value) {
format_specs fmt_specs = this->specs;
if (fmt_specs.type && fmt_specs.type != 'c')
return (*this)(static_cast<int>(value));
fmt_specs.sign = sign::none;
fmt_specs.alt = false;
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
// align::numeric needs to be overwritten here since the '0' flag is
// ignored for non-numeric types
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
fmt_specs.align = align::right;
return write<Char>(this->out, static_cast<Char>(value), fmt_specs);
}
return base::operator()(value);
}
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
OutputIt operator()(T value) {
return base::operator()(value);
}
/** Formats a null-terminated C string. */
OutputIt operator()(const char* value) {
if (value) return base::operator()(value);
return write_null_pointer(this->specs.type != 'p');
}
/** Formats a null-terminated wide C string. */
OutputIt operator()(const wchar_t* value) {
if (value) return base::operator()(value);
return write_null_pointer(this->specs.type != 'p');
}
OutputIt operator()(basic_string_view<Char> value) {
return base::operator()(value);
}
/** Formats a pointer. */
OutputIt operator()(const void* value) {
return value ? base::operator()(value) : write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
auto parse_ctx =
basic_printf_parse_context<Char>(basic_string_view<Char>());
handle.format(parse_ctx, context_);
return this->out;
}
};
template <typename Char>
void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
specs.align = align::left;
break;
case '+':
specs.sign = sign::plus;
break;
case '0':
specs.fill[0] = '0';
break;
case ' ':
if (specs.sign != sign::plus) {
specs.sign = sign::space;
}
break;
case '#':
specs.alt = true;
break;
default:
return;
}
}
}
template <typename Char, typename GetArg>
int parse_header(const Char*& it, const Char* end,
basic_format_specs<Char>& specs, GetArg get_arg) {
int arg_index = -1;
Char c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
int value = parse_nonnegative_int(it, end, -1);
if (it != end && *it == '$') { // value is an argument index
++it;
arg_index = value != -1 ? value : max_value<int>();
} else {
if (c == '0') specs.fill[0] = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
if (value == -1) FMT_THROW(format_error("number is too big"));
specs.width = value;
return arg_index;
}
}
}
parse_flags(specs, it, end);
// Parse width.
if (it != end) {
if (*it >= '0' && *it <= '9') {
specs.width = parse_nonnegative_int(it, end, -1);
if (specs.width == -1) FMT_THROW(format_error("number is too big"));
} else if (*it == '*') {
++it;
specs.width = static_cast<int>(visit_format_arg(
detail::printf_width_handler<Char>(specs), get_arg(-1)));
}
}
return arg_index;
}
template <typename Char, typename Context>
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
using OutputIt = buffer_appender<Char>;
auto out = OutputIt(buf);
auto context = basic_printf_context<OutputIt, Char>(out, args);
auto parse_ctx = basic_printf_parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
auto get_arg = [&](int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx.next_arg_id();
else
parse_ctx.check_arg_id(--arg_index);
return detail::get_arg(context, arg_index);
};
const Char* start = parse_ctx.begin();
const Char* end = parse_ctx.end();
auto it = start;
while (it != end) {
if (!detail::find<false, Char>(it, end, '%', it)) {
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
break;
}
Char c = *it++;
if (it != end && *it == c) {
out = detail::write(
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
start = ++it;
continue;
}
out = detail::write(out, basic_string_view<Char>(
start, detail::to_unsigned(it - 1 - start)));
basic_format_specs<Char> specs;
specs.align = align::right;
// Parse argument index, flags and width.
int arg_index = parse_header(it, end, specs, get_arg);
if (arg_index == 0) parse_ctx.on_error("argument not found");
// Parse precision.
if (it != end && *it == '.') {
++it;
c = it != end ? *it : 0;
if ('0' <= c && c <= '9') {
specs.precision = parse_nonnegative_int(it, end, 0);
} else if (c == '*') {
++it;
specs.precision = static_cast<int>(
visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
} else {
specs.precision = 0;
}
}
auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral())
specs.fill[0] =
' '; // Ignore '0' flag for non-numeric types or if '-' present.
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
auto str_end = str + specs.precision;
auto nul = std::find(str, str_end, Char());
arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
basic_string_view<Char>(
str, detail::to_unsigned(nul != str_end ? nul - str
: specs.precision)));
}
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
specs.alt = false;
if (specs.fill[0] == '0') {
if (arg.is_arithmetic() && specs.align != align::left)
specs.align = align::numeric;
else
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
// flag is also present.
}
// Parse length and convert the argument to the required type.
c = it != end ? *it++ : 0;
Char t = it != end ? *it : 0;
using detail::convert_arg;
switch (c) {
case 'h':
if (t == 'h') {
++it;
t = it != end ? *it : 0;
convert_arg<signed char>(arg, t);
} else {
convert_arg<short>(arg, t);
}
break;
case 'l':
if (t == 'l') {
++it;
t = it != end ? *it : 0;
convert_arg<long long>(arg, t);
} else {
convert_arg<long>(arg, t);
}
break;
case 'j':
convert_arg<intmax_t>(arg, t);
break;
case 'z':
convert_arg<size_t>(arg, t);
break;
case 't':
convert_arg<std::ptrdiff_t>(arg, t);
break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--it;
convert_arg<void>(arg, c);
}
// Parse type.
if (it == end) FMT_THROW(format_error("invalid format string"));
specs.type = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (specs.type) {
case 'i':
case 'u':
specs.type = 'd';
break;
case 'c':
visit_format_arg(
detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
arg);
break;
}
}
start = it;
// Format argument.
out = visit_format_arg(
detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
}
detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
}
FMT_END_DETAIL_NAMESPACE
template <typename Char>
using basic_printf_context_t =
basic_printf_context<detail::buffer_appender<Char>, Char>;
using printf_context = basic_printf_context_t<char>;
using wprintf_context = basic_printf_context_t<wchar_t>;
using printf_args = basic_format_args<printf_context>;
using wprintf_args = basic_format_args<wprintf_context>;
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
template <typename... T>
inline auto make_printf_args(const T&... args)
-> format_arg_store<printf_context, T...> {
return {args...};
}
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
template <typename... T>
inline auto make_wprintf_args(const T&... args)
-> format_arg_store<wprintf_context, T...> {
return {args...};
}
template <typename S, typename Char = char_t<S>>
inline auto vsprintf(
const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
vprintf(buffer, to_string_view(fmt), args);
return to_string(buffer);
}
/**
\rst
Formats arguments and returns the result as a string.
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename S, typename... T,
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
using context = basic_printf_context_t<Char>;
return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
inline auto vfprintf(
std::FILE* f, const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
basic_memory_buffer<Char> buffer;
vprintf(buffer, to_string_view(fmt), args);
size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
? -1
: static_cast<int>(size);
}
/**
\rst
Prints formatted data to the file *f*.
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename S, typename... T, typename Char = char_t<S>>
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
using context = basic_printf_context_t<Char>;
return vfprintf(f, to_string_view(fmt),
fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
inline auto vprintf(
const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
return vfprintf(stdout, to_string_view(fmt), args);
}
/**
\rst
Prints formatted data to ``stdout``.
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
inline auto printf(const S& fmt, const T&... args) -> int {
return vprintf(
to_string_view(fmt),
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
}
template <typename S, typename Char = char_t<S>>
FMT_DEPRECATED auto vfprintf(
std::basic_ostream<Char>& os, const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
basic_memory_buffer<Char> buffer;
vprintf(buffer, to_string_view(fmt), args);
os.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
return static_cast<int>(buffer.size());
}
template <typename S, typename... T, typename Char = char_t<S>>
FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt,
const T&... args) -> int {
return vfprintf(os, to_string_view(fmt),
fmt::make_format_args<basic_printf_context_t<Char>>(args...));
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_

View file

@ -0,0 +1,468 @@
// Formatting library for C++ - experimental range support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for ranges, containers and types tuple interface.
#ifndef FMT_RANGES_H_
#define FMT_RANGES_H_
#include <initializer_list>
#include <type_traits>
#include "format.h"
FMT_BEGIN_NAMESPACE
template <typename Char, typename Enable = void> struct formatting_range {
#ifdef FMT_DEPRECATED_BRACED_RANGES
Char prefix = '{';
Char postfix = '}';
#else
Char prefix = '[';
Char postfix = ']';
#endif
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
template <typename Char, typename Enable = void> struct formatting_tuple {
Char prefix = '(';
Char postfix = ')';
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
};
namespace detail {
template <typename RangeT, typename OutputIterator>
OutputIterator copy(const RangeT& range, OutputIterator out) {
for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it;
return out;
}
template <typename OutputIterator>
OutputIterator copy(const char* str, OutputIterator out) {
while (*str) *out++ = *str++;
return out;
}
template <typename OutputIterator>
OutputIterator copy(char ch, OutputIterator out) {
*out++ = ch;
return out;
}
template <typename OutputIterator>
OutputIterator copy(wchar_t ch, OutputIterator out) {
*out++ = ch;
return out;
}
/// Return true value if T has std::string interface, like std::string_view.
template <typename T> class is_std_string_like {
template <typename U>
static auto check(U* p)
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename Char>
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
template <typename... Ts> struct conditional_helper {};
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
# define FMT_DECLTYPE_RETURN(val) \
->decltype(val) { return val; } \
static_assert( \
true, "") // This makes it so that a semicolon is required after the
// macro, which helps clang-format handle the formatting.
// C array overload
template <typename T, std::size_t N>
auto range_begin(const T (&arr)[N]) -> const T* {
return arr;
}
template <typename T, std::size_t N>
auto range_end(const T (&arr)[N]) -> const T* {
return arr + N;
}
template <typename T, typename Enable = void>
struct has_member_fn_begin_end_t : std::false_type {};
template <typename T>
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>>
: std::true_type {};
// Member function overload
template <typename T>
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
template <typename T>
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
// ADL overload. Only participates in overload resolution if member functions
// are not found.
template <typename T>
auto range_begin(T&& rng)
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(begin(static_cast<T&&>(rng)))> {
return begin(static_cast<T&&>(rng));
}
template <typename T>
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
decltype(end(static_cast<T&&>(rng)))> {
return end(static_cast<T&&>(rng));
}
template <typename T, typename Enable = void>
struct has_const_begin_end : std::false_type {};
template <typename T, typename Enable = void>
struct has_mutable_begin_end : std::false_type {};
template <typename T>
struct has_const_begin_end<
T, void_t<decltype(detail::range_begin(
std::declval<const remove_cvref_t<T>&>())),
decltype(detail::range_begin(
std::declval<const remove_cvref_t<T>&>()))>>
: std::true_type {};
template <typename T>
struct has_mutable_begin_end<
T, void_t<decltype(detail::range_begin(std::declval<T>())),
decltype(detail::range_begin(std::declval<T>())),
enable_if_t<std::is_copy_constructible<T>::value>>>
: std::true_type {};
template <typename T>
struct is_range_<T, void>
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
has_mutable_begin_end<T>::value)> {};
template <typename T, typename Enable = void> struct range_to_view;
template <typename T>
struct range_to_view<T, enable_if_t<has_const_begin_end<T>::value>> {
struct view_t {
const T* m_range_ptr;
auto begin() const FMT_DECLTYPE_RETURN(detail::range_begin(*m_range_ptr));
auto end() const FMT_DECLTYPE_RETURN(detail::range_end(*m_range_ptr));
};
static auto view(const T& range) -> view_t { return {&range}; }
};
template <typename T>
struct range_to_view<T, enable_if_t<!has_const_begin_end<T>::value &&
has_mutable_begin_end<T>::value>> {
struct view_t {
T m_range_copy;
auto begin() FMT_DECLTYPE_RETURN(detail::range_begin(m_range_copy));
auto end() FMT_DECLTYPE_RETURN(detail::range_end(m_range_copy));
};
static auto view(const T& range) -> view_t { return {range}; }
};
# undef FMT_DECLTYPE_RETURN
#endif
/// tuple_size and tuple_element check.
template <typename T> class is_tuple_like_ {
template <typename U>
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
template <typename> static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(nullptr))>::value;
};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>;
template <size_t... N> using index_sequence = std::index_sequence<N...>;
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
#else
template <typename T, T... N> struct integer_sequence {
using value_type = T;
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
};
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
template <typename T, size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
template <typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template <size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
#endif
template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
using std::get;
// using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
(void)_; // blocks warnings
}
template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
T const&) {
return {};
}
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
template <typename Range>
using value_type =
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
*out++ = ',';
*out++ = ' ';
return out;
}
template <
typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(is_std_string_like<typename std::decay<Arg>::type>::value)>
OutputIt write_range_entry(OutputIt out, const Arg& v) {
*out++ = '"';
out = write<Char>(out, v);
*out++ = '"';
return out;
}
template <typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
OutputIt write_range_entry(OutputIt out, const Arg v) {
*out++ = '\'';
*out++ = v;
*out++ = '\'';
return out;
}
template <
typename Char, typename OutputIt, typename Arg,
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
!std::is_same<Arg, Char>::value)>
OutputIt write_range_entry(OutputIt out, const Arg& v) {
return write<Char>(out, v);
}
} // namespace detail
template <typename T> struct is_tuple_like {
static FMT_CONSTEXPR_DECL const bool value =
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
};
template <typename TupleT, typename Char>
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
private:
// C++11 generic lambda for format()
template <typename FormatContext> struct format_each {
template <typename T> void operator()(const T& v) {
if (i > 0) out = detail::write_delimiter(out);
out = detail::write_range_entry<Char>(out, v);
++i;
}
formatting_tuple<Char>& formatting;
size_t& i;
typename std::add_lvalue_reference<
decltype(std::declval<FormatContext>().out())>::type out;
};
public:
formatting_tuple<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext = format_context>
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
size_t i = 0;
detail::copy(formatting.prefix, out);
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
detail::copy(formatting.postfix, out);
return ctx.out();
}
};
template <typename T, typename Char> struct is_range {
static FMT_CONSTEXPR_DECL const bool value =
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
!std::is_convertible<T, std::basic_string<Char>>::value &&
!std::is_constructible<detail::std_string_view<Char>, T>::value;
};
template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<
fmt::is_range<T, Char>::value
// Workaround a bug in MSVC 2017 and earlier.
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
&& (has_formatter<detail::value_type<T>, format_context>::value ||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
#endif
>> {
formatting_range<Char> formatting;
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return formatting.parse(ctx);
}
template <typename FormatContext>
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
auto out = detail::copy(formatting.prefix, ctx.out());
size_t i = 0;
auto view = detail::range_to_view<T>::view(values);
auto it = view.begin();
auto end = view.end();
for (; it != end; ++it) {
if (i > 0) out = detail::write_delimiter(out);
out = detail::write_range_entry<Char>(out, *it);
++i;
}
return detail::copy(formatting.postfix, out);
}
};
template <typename Char, typename... T> struct tuple_join_view : detail::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
template <typename Char, typename... T>
using tuple_arg_join = tuple_join_view<Char, T...>;
template <typename Char, typename... T>
struct formatter<tuple_join_view<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) ->
typename FormatContext::iterator {
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
}
private:
template <typename FormatContext, size_t... N>
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
detail::index_sequence<N...>) ->
typename FormatContext::iterator {
using std::get;
return format_args(value, ctx, get<N>(value.tuple)...);
}
template <typename FormatContext>
auto format_args(const tuple_join_view<Char, T...>&, FormatContext& ctx) ->
typename FormatContext::iterator {
// NOTE: for compilers that support C++17, this empty function instantiation
// can be replaced with a constexpr branch in the variadic overload.
return ctx.out();
}
template <typename FormatContext, typename Arg, typename... Args>
auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
const Arg& arg, const Args&... args) ->
typename FormatContext::iterator {
using base = formatter<typename std::decay<Arg>::type, Char>;
auto out = base().format(arg, ctx);
if (sizeof...(Args) > 0) {
out = std::copy(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
return format_args(value, ctx, args...);
}
return out;
}
};
FMT_MODULE_EXPORT_BEGIN
/**
\rst
Returns an object that formats `tuple` with elements separated by `sep`.
**Example**::
std::tuple<int, char> t = {1, 'a'};
fmt::print("{}", fmt::join(t, ", "));
// Output: "1, a"
\endrst
*/
template <typename... T>
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
-> tuple_join_view<char, T...> {
return {tuple, sep};
}
template <typename... T>
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
basic_string_view<wchar_t> sep)
-> tuple_join_view<wchar_t, T...> {
return {tuple, sep};
}
/**
\rst
Returns an object that formats `initializer_list` with elements separated by
`sep`.
**Example**::
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
// Output: "1, 2, 3"
\endrst
*/
template <typename T>
auto join(std::initializer_list<T> list, string_view sep)
-> join_view<const T*, const T*> {
return join(std::begin(list), std::end(list), sep);
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_RANGES_H_

View file

@ -0,0 +1,236 @@
// Formatting library for C++ - optional wchar_t and exotic character support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_WCHAR_H_
#define FMT_WCHAR_H_
#include <cwchar>
#include <tuple>
#include "format.h"
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename T>
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
}
FMT_MODULE_EXPORT_BEGIN
using wstring_view = basic_string_view<wchar_t>;
using wformat_parse_context = basic_format_parse_context<wchar_t>;
using wformat_context = buffer_context<wchar_t>;
using wformat_args = basic_format_args<wformat_context>;
using wmemory_buffer = basic_memory_buffer<wchar_t>;
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename... Args> using wformat_string = wstring_view;
#else
template <typename... Args>
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
#endif
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<detail::char8_type> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};
template <typename... Args>
constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
const Args&... args) {
return {args...};
}
inline namespace literals {
constexpr auto operator"" _format(const wchar_t* s, size_t n)
-> detail::udl_formatter<wchar_t> {
return {{s, n}};
}
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
return {s};
}
#endif
} // namespace literals
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, wstring_view sep)
-> join_view<It, Sentinel, wchar_t> {
return {begin, end, sep};
}
template <typename Range>
auto join(Range&& range, wstring_view sep)
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
wchar_t> {
return join(std::begin(range), std::end(range), sep);
}
template <typename T>
auto join(std::initializer_list<T> list, wstring_view sep)
-> join_view<const T*, const T*, wchar_t> {
return join(std::begin(list), std::end(list), sep);
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
detail::vformat_to(buffer, format_str, args);
return to_string(buffer);
}
// Pass char_t as a default template parameter instead of using
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat(to_string_view(format_str), vargs);
}
template <typename Locale, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat(
const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
return detail::vformat(loc, to_string_view(format_str), args);
}
template <typename Locale, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
-> std::basic_string<Char> {
return detail::vformat(loc, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
}
template <typename OutputIt, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
auto vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, to_string_view(format_str), args);
return detail::get_iterator(buf);
}
template <typename OutputIt, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
return vformat_to(out, to_string_view(fmt), vargs);
}
template <typename S, typename... Args, typename Char, size_t SIZE,
typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)>
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
const S& format_str, Args&&... args) ->
typename buffer_context<Char>::iterator {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
detail::vformat_to(buf, to_string_view(format_str), vargs, {});
return detail::buffer_appender<Char>(buf);
}
template <typename Locale, typename S, typename OutputIt, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to(
OutputIt out, const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
return detail::get_iterator(buf);
}
template <
typename OutputIt, typename Locale, typename S, typename... Args,
typename Char = char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to(out, loc, to_string_view(format_str), vargs);
}
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> format_to_n_result<OutputIt> {
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
template <typename OutputIt, typename S, typename... Args,
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
const Args&... args) -> format_to_n_result<OutputIt> {
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
return vformat_to_n(out, n, to_string_view(fmt), vargs);
}
template <typename S, typename... Args, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
detail::counting_buffer<Char> buf;
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
detail::vformat_to(buf, to_string_view(fmt), vargs);
return buf.count();
}
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
wmemory_buffer buffer;
detail::vformat_to(buffer, fmt, args);
buffer.push_back(L'\0');
if (std::fputws(buffer.data(), f) == -1)
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
}
inline void vprint(wstring_view fmt, wformat_args args) {
vprint(stdout, fmt, args);
}
template <typename... T>
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
return vprint(f, wstring_view(fmt), make_wformat_args(args...));
}
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
return vprint(wstring_view(fmt), make_wformat_args(args...));
}
/**
Converts *value* to ``std::wstring`` using the default format for type *T*.
*/
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
return format(FMT_STRING(L"{}"), value);
}
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_WCHAR_H_

20
Libs/spdlog/fmt/chrono.h Normal file
View file

@ -0,0 +1,20 @@
//
// Copyright(c) 2016 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// include bundled or external copy of fmtlib's chrono support
//
#if !defined(SPDLOG_FMT_EXTERNAL)
# ifdef SPDLOG_HEADER_ONLY
# ifndef FMT_HEADER_ONLY
# define FMT_HEADER_ONLY
# endif
# endif
# include <spdlog/fmt/bundled/chrono.h>
#else
# include <fmt/chrono.h>
#endif

20
Libs/spdlog/fmt/compile.h Normal file
View file

@ -0,0 +1,20 @@
//
// Copyright(c) 2016 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// include bundled or external copy of fmtlib's ostream support
//
#if !defined(SPDLOG_FMT_EXTERNAL)
# ifdef SPDLOG_HEADER_ONLY
# ifndef FMT_HEADER_ONLY
# define FMT_HEADER_ONLY
# endif
# endif
# include <spdlog/fmt/bundled/compile.h>
#else
# include <fmt/compile.h>
#endif

27
Libs/spdlog/fmt/fmt.h Normal file
View file

@ -0,0 +1,27 @@
//
// Copyright(c) 2016-2018 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// Include a bundled header-only copy of fmtlib or an external one.
// By default spdlog include its own copy.
//
#if !defined(SPDLOG_FMT_EXTERNAL)
# if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY)
# define FMT_HEADER_ONLY
# endif
# ifndef FMT_USE_WINDOWS_H
# define FMT_USE_WINDOWS_H 0
# endif
// enable the 'n' flag in for backward compatibility with fmt 6.x
# define FMT_DEPRECATED_N_SPECIFIER
# include <spdlog/fmt/bundled/core.h>
# include <spdlog/fmt/bundled/format.h>
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
# include <fmt/core.h>
# include <fmt/format.h>
#endif

20
Libs/spdlog/fmt/ostr.h Normal file
View file

@ -0,0 +1,20 @@
//
// Copyright(c) 2016 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// include bundled or external copy of fmtlib's ostream support
//
#if !defined(SPDLOG_FMT_EXTERNAL)
# ifdef SPDLOG_HEADER_ONLY
# ifndef FMT_HEADER_ONLY
# define FMT_HEADER_ONLY
# endif
# endif
# include <spdlog/fmt/bundled/ostream.h>
#else
# include <fmt/ostream.h>
#endif

20
Libs/spdlog/fmt/xchar.h Normal file
View file

@ -0,0 +1,20 @@
//
// Copyright(c) 2016 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// include bundled or external copy of fmtlib's ostream support
//
#if !defined(SPDLOG_FMT_EXTERNAL)
# ifdef SPDLOG_HEADER_ONLY
# ifndef FMT_HEADER_ONLY
# define FMT_HEADER_ONLY
# endif
# endif
# include <spdlog/fmt/bundled/xchar.h>
#else
# include <fmt/xchar.h>
#endif

18
Libs/spdlog/formatter.h Normal file
View file

@ -0,0 +1,18 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/fmt/fmt.h>
#include <spdlog/details/log_msg.h>
namespace spdlog {
class formatter
{
public:
virtual ~formatter() = default;
virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0;
virtual std::unique_ptr<formatter> clone() const = 0;
};
} // namespace spdlog

14
Libs/spdlog/fwd.h Normal file
View file

@ -0,0 +1,14 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
namespace spdlog {
class logger;
class formatter;
namespace sinks {
class sink;
}
} // namespace spdlog

257
Libs/spdlog/logger-inl.h Normal file
View file

@ -0,0 +1,257 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/logger.h>
#endif
#include <spdlog/sinks/sink.h>
#include <spdlog/details/backtracer.h>
#include <spdlog/pattern_formatter.h>
#include <cstdio>
namespace spdlog {
// public methods
SPDLOG_INLINE logger::logger(const logger &other)
: name_(other.name_)
, sinks_(other.sinks_)
, level_(other.level_.load(std::memory_order_relaxed))
, flush_level_(other.flush_level_.load(std::memory_order_relaxed))
, custom_err_handler_(other.custom_err_handler_)
, tracer_(other.tracer_)
{}
SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)),
sinks_(std::move(other.sinks_)),
level_(other.level_.load(std::memory_order_relaxed)),
flush_level_(other.flush_level_.load(std::memory_order_relaxed)),
custom_err_handler_(std::move(other.custom_err_handler_)),
tracer_(std::move(other.tracer_))
{}
SPDLOG_INLINE logger &logger::operator=(logger other) SPDLOG_NOEXCEPT
{
this->swap(other);
return *this;
}
SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT
{
name_.swap(other.name_);
sinks_.swap(other.sinks_);
// swap level_
auto other_level = other.level_.load();
auto my_level = level_.exchange(other_level);
other.level_.store(my_level);
// swap flush level_
other_level = other.flush_level_.load();
my_level = flush_level_.exchange(other_level);
other.flush_level_.store(my_level);
custom_err_handler_.swap(other.custom_err_handler_);
std::swap(tracer_, other.tracer_);
}
SPDLOG_INLINE void swap(logger &a, logger &b)
{
a.swap(b);
}
SPDLOG_INLINE void logger::set_level(level::level_enum log_level)
{
level_.store(log_level);
}
SPDLOG_INLINE level::level_enum logger::level() const
{
return static_cast<level::level_enum>(level_.load(std::memory_order_relaxed));
}
SPDLOG_INLINE const std::string &logger::name() const
{
return name_;
}
// set formatting for the sinks in this logger.
// each sink will get a separate instance of the formatter object.
SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
{
for (auto it = sinks_.begin(); it != sinks_.end(); ++it)
{
if (std::next(it) == sinks_.end())
{
// last element - we can be move it.
(*it)->set_formatter(std::move(f));
break; // to prevent clang-tidy warning
}
else
{
(*it)->set_formatter(f->clone());
}
}
}
SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type)
{
auto new_formatter = details::make_unique<pattern_formatter>(std::move(pattern), time_type);
set_formatter(std::move(new_formatter));
}
// create new backtrace sink and move to it all our child sinks
SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages)
{
tracer_.enable(n_messages);
}
// restore orig sinks and level and delete the backtrace sink
SPDLOG_INLINE void logger::disable_backtrace()
{
tracer_.disable();
}
SPDLOG_INLINE void logger::dump_backtrace()
{
dump_backtrace_();
}
// flush functions
SPDLOG_INLINE void logger::flush()
{
flush_();
}
SPDLOG_INLINE void logger::flush_on(level::level_enum log_level)
{
flush_level_.store(log_level);
}
SPDLOG_INLINE level::level_enum logger::flush_level() const
{
return static_cast<level::level_enum>(flush_level_.load(std::memory_order_relaxed));
}
// sinks
SPDLOG_INLINE const std::vector<sink_ptr> &logger::sinks() const
{
return sinks_;
}
SPDLOG_INLINE std::vector<sink_ptr> &logger::sinks()
{
return sinks_;
}
// error handler
SPDLOG_INLINE void logger::set_error_handler(err_handler handler)
{
custom_err_handler_ = std::move(handler);
}
// create new logger with same sinks and configuration.
SPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_name)
{
auto cloned = std::make_shared<logger>(*this);
cloned->name_ = std::move(logger_name);
return cloned;
}
// protected methods
SPDLOG_INLINE void logger::log_it_(const spdlog::details::log_msg &log_msg, bool log_enabled, bool traceback_enabled)
{
if (log_enabled)
{
sink_it_(log_msg);
}
if (traceback_enabled)
{
tracer_.push_back(log_msg);
}
}
SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg)
{
for (auto &sink : sinks_)
{
if (sink->should_log(msg.level))
{
SPDLOG_TRY
{
sink->log(msg);
}
SPDLOG_LOGGER_CATCH()
}
}
if (should_flush_(msg))
{
flush_();
}
}
SPDLOG_INLINE void logger::flush_()
{
for (auto &sink : sinks_)
{
SPDLOG_TRY
{
sink->flush();
}
SPDLOG_LOGGER_CATCH()
}
}
SPDLOG_INLINE void logger::dump_backtrace_()
{
using details::log_msg;
if (tracer_.enabled())
{
sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"});
tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); });
sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"});
}
}
SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg)
{
auto flush_level = flush_level_.load(std::memory_order_relaxed);
return (msg.level >= flush_level) && (msg.level != level::off);
}
SPDLOG_INLINE void logger::err_handler_(const std::string &msg)
{
if (custom_err_handler_)
{
custom_err_handler_(msg);
}
else
{
using std::chrono::system_clock;
static std::mutex mutex;
static std::chrono::system_clock::time_point last_report_time;
static size_t err_counter = 0;
std::lock_guard<std::mutex> lk{mutex};
auto now = system_clock::now();
err_counter++;
if (now - last_report_time < std::chrono::seconds(1))
{
return;
}
last_report_time = now;
auto tm_time = details::os::localtime(system_clock::to_time_t(now));
char date_buf[64];
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
#if defined(USING_R) && defined(R_R_H) // if in R environment
REprintf("[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str());
#else
std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str());
#endif
}
}
} // namespace spdlog

405
Libs/spdlog/logger.h Normal file
View file

@ -0,0 +1,405 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Thread safe logger (except for set_error_handler())
// Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message and if yes:
// 2. Call the underlying sinks to do the job.
// 3. Each sink use its own private copy of a formatter to format the message
// and send to its destination.
//
// The use of private formatter per sink provides the opportunity to cache some
// formatted data, and support for different format per sink.
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/backtracer.h>
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
# ifndef _WIN32
# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
# endif
# include <spdlog/details/os.h>
#endif
#include <vector>
#ifndef SPDLOG_NO_EXCEPTIONS
# define SPDLOG_LOGGER_CATCH() \
catch (const std::exception &ex) \
{ \
err_handler_(ex.what()); \
} \
catch (...) \
{ \
err_handler_("Rethrowing unknown exception in logger"); \
throw; \
}
#else
# define SPDLOG_LOGGER_CATCH()
#endif
namespace spdlog {
class SPDLOG_API logger
{
public:
// Empty logger
explicit logger(std::string name)
: name_(std::move(name))
, sinks_()
{}
// Logger with range on sinks
template<typename It>
logger(std::string name, It begin, It end)
: name_(std::move(name))
, sinks_(begin, end)
{}
// Logger with single sink
logger(std::string name, sink_ptr single_sink)
: logger(std::move(name), {std::move(single_sink)})
{}
// Logger with sinks init list
logger(std::string name, sinks_init_list sinks)
: logger(std::move(name), sinks.begin(), sinks.end())
{}
virtual ~logger() = default;
logger(const logger &other);
logger(logger &&other) SPDLOG_NOEXCEPT;
logger &operator=(logger other) SPDLOG_NOEXCEPT;
void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
template<typename... Args>
void log(source_loc loc, level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
{
log_(loc, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void log(level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
{
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
}
template<typename T>
void log(level::level_enum lvl, const T &msg)
{
log(source_loc{}, lvl, msg);
}
// T can be statically converted to string_view
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, int>::type = 0>
void log(source_loc loc, level::level_enum lvl, const T &msg)
{
log(loc, lvl, string_view_t{msg});
}
// T cannot be statically converted to neither string_view, nor wstring_view and nor format string
template<class T, typename std::enable_if<!std::is_convertible<const T &, spdlog::string_view_t>::value &&
!is_convertible_to_basic_format_string<const T &>::value,
int>::type = 0>
void log(source_loc loc, level::level_enum lvl, const T &msg)
{
log(loc, lvl, "{}", msg);
}
void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg)
{
bool log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{
return;
}
details::log_msg log_msg(log_time, loc, name_, lvl, msg);
log_it_(log_msg, log_enabled, traceback_enabled);
}
void log(source_loc loc, level::level_enum lvl, string_view_t msg)
{
bool log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{
return;
}
details::log_msg log_msg(loc, name_, lvl, msg);
log_it_(log_msg, log_enabled, traceback_enabled);
}
void log(level::level_enum lvl, string_view_t msg)
{
log(source_loc{}, lvl, msg);
}
template<typename... Args>
void trace(fmt::format_string<Args...> fmt, Args &&...args)
{
log(level::trace, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void debug(fmt::format_string<Args...> fmt, Args &&...args)
{
log(level::debug, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void info(fmt::format_string<Args...> fmt, Args &&...args)
{
log(level::info, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void warn(fmt::format_string<Args...> fmt, Args &&...args)
{
log(level::warn, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void error(fmt::format_string<Args...> fmt, Args &&...args)
{
log(level::err, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void critical(fmt::format_string<Args...> fmt, Args &&...args)
{
log(level::critical, fmt, std::forward<Args>(args)...);
}
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args>
void log(level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void log(source_loc loc, level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
{
log_(loc, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void trace(fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(level::trace, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void debug(fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(level::debug, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void info(fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(level::info, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void warn(fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(level::warn, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void error(fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(level::err, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
void critical(fmt::wformat_string<Args...> fmt, Args &&...args)
{
log(level::critical, fmt, std::forward<Args>(args)...);
}
#endif
template<typename T>
void trace(const T &msg)
{
log(level::trace, msg);
}
template<typename T>
void debug(const T &msg)
{
log(level::debug, msg);
}
template<typename T>
void info(const T &msg)
{
log(level::info, msg);
}
template<typename T>
void warn(const T &msg)
{
log(level::warn, msg);
}
template<typename T>
void error(const T &msg)
{
log(level::err, msg);
}
template<typename T>
void critical(const T &msg)
{
log(level::critical, msg);
}
// return true logging is enabled for the given level.
bool should_log(level::level_enum msg_level) const
{
return msg_level >= level_.load(std::memory_order_relaxed);
}
// return true if backtrace logging is enabled.
bool should_backtrace() const
{
return tracer_.enabled();
}
void set_level(level::level_enum log_level);
level::level_enum level() const;
const std::string &name() const;
// set formatting for the sinks in this logger.
// each sink will get a separate instance of the formatter object.
void set_formatter(std::unique_ptr<formatter> f);
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
// backtrace support.
// efficiently store all debug/trace messages in a circular buffer until needed for debugging.
void enable_backtrace(size_t n_messages);
void disable_backtrace();
void dump_backtrace();
// flush functions
void flush();
void flush_on(level::level_enum log_level);
level::level_enum flush_level() const;
// sinks
const std::vector<sink_ptr> &sinks() const;
std::vector<sink_ptr> &sinks();
// error handler
void set_error_handler(err_handler);
// create new logger with same sinks and configuration.
virtual std::shared_ptr<logger> clone(std::string logger_name);
protected:
std::string name_;
std::vector<sink_ptr> sinks_;
spdlog::level_t level_{level::info};
spdlog::level_t flush_level_{level::off};
err_handler custom_err_handler_{nullptr};
details::backtracer tracer_;
// common implementation for after templated public api has been resolved
template<typename... Args>
void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args)
{
bool log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{
return;
}
SPDLOG_TRY
{
memory_buf_t buf;
fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(args...));
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_it_(log_msg, log_enabled, traceback_enabled);
}
SPDLOG_LOGGER_CATCH()
}
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args>
void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args)
{
bool log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{
return;
}
SPDLOG_TRY
{
// format to wmemory_buffer and convert to utf8
fmt::wmemory_buffer wbuf;
fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(args...));
memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_it_(log_msg, log_enabled, traceback_enabled);
}
SPDLOG_LOGGER_CATCH()
}
// T can be statically converted to wstring_view, and no formatting needed.
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::wstring_view_t>::value, int>::type = 0>
void log_(source_loc loc, level::level_enum lvl, const T &msg)
{
bool log_enabled = should_log(lvl);
bool traceback_enabled = tracer_.enabled();
if (!log_enabled && !traceback_enabled)
{
return;
}
SPDLOG_TRY
{
memory_buf_t buf;
details::os::wstr_to_utf8buf(msg, buf);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_it_(log_msg, log_enabled, traceback_enabled);
}
SPDLOG_LOGGER_CATCH()
}
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
// log the given message (if the given log level is high enough),
// and save backtrace (if backtrace is enabled).
void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
virtual void sink_it_(const details::log_msg &msg);
virtual void flush_();
void dump_backtrace_();
bool should_flush_(const details::log_msg &msg);
// handle errors during logging.
// default handler prints the error to stderr at max rate of 1 message/sec.
void err_handler_(const std::string &msg);
};
void swap(logger &a, logger &b);
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "logger-inl.h"
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,126 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/formatter.h>
#include <chrono>
#include <ctime>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
namespace spdlog {
namespace details {
// padding information.
struct padding_info
{
enum class pad_side
{
left,
right,
center
};
padding_info() = default;
padding_info(size_t width, padding_info::pad_side side, bool truncate)
: width_(width)
, side_(side)
, truncate_(truncate)
, enabled_(true)
{}
bool enabled() const
{
return enabled_;
}
size_t width_ = 0;
pad_side side_ = pad_side::left;
bool truncate_ = false;
bool enabled_ = false;
};
class SPDLOG_API flag_formatter
{
public:
explicit flag_formatter(padding_info padinfo)
: padinfo_(padinfo)
{}
flag_formatter() = default;
virtual ~flag_formatter() = default;
virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0;
protected:
padding_info padinfo_;
};
} // namespace details
class SPDLOG_API custom_flag_formatter : public details::flag_formatter
{
public:
virtual std::unique_ptr<custom_flag_formatter> clone() const = 0;
void set_padding_info(details::padding_info padding)
{
flag_formatter::padinfo_ = padding;
}
};
class SPDLOG_API pattern_formatter final : public formatter
{
public:
using custom_flags = std::unordered_map<char, std::unique_ptr<custom_flag_formatter>>;
explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local,
std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags());
// use default pattern is not given
explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
pattern_formatter(const pattern_formatter &other) = delete;
pattern_formatter &operator=(const pattern_formatter &other) = delete;
std::unique_ptr<formatter> clone() const override;
void format(const details::log_msg &msg, memory_buf_t &dest) override;
template<typename T, typename... Args>
pattern_formatter &add_flag(char flag, Args &&...args)
{
custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...);
return *this;
}
void set_pattern(std::string pattern);
private:
std::string pattern_;
std::string eol_;
pattern_time_type pattern_time_type_;
std::tm cached_tm_;
std::chrono::seconds last_log_secs_;
std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
custom_flags custom_handlers_;
std::tm get_time_(const details::log_msg &msg);
template<typename Padder>
void handle_flag_(char flag, details::padding_info padding);
// Extract given pad spec (e.g. %8X)
// Advance the given it pass the end of the padding spec found (if any)
// Return padding.
static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
void compile_pattern_(const std::string &pattern);
};
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "pattern_formatter-inl.h"
#endif

View file

@ -0,0 +1,119 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifdef __ANDROID__
# include <spdlog/details/fmt_helper.h>
# include <spdlog/details/null_mutex.h>
# include <spdlog/details/os.h>
# include <spdlog/sinks/base_sink.h>
# include <spdlog/details/synchronous_factory.h>
# include <android/log.h>
# include <chrono>
# include <mutex>
# include <string>
# include <thread>
# if !defined(SPDLOG_ANDROID_RETRIES)
# define SPDLOG_ANDROID_RETRIES 2
# endif
namespace spdlog {
namespace sinks {
/*
* Android sink (logging using __android_log_write)
*/
template<typename Mutex>
class android_sink final : public base_sink<Mutex>
{
public:
explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false)
: tag_(std::move(tag))
, use_raw_msg_(use_raw_msg)
{}
protected:
void sink_it_(const details::log_msg &msg) override
{
const android_LogPriority priority = convert_to_android_(msg.level);
memory_buf_t formatted;
if (use_raw_msg_)
{
details::fmt_helper::append_string_view(msg.payload, formatted);
}
else
{
base_sink<Mutex>::formatter_->format(msg, formatted);
}
formatted.push_back('\0');
const char *msg_output = formatted.data();
// See system/core/liblog/logger_write.c for explanation of return value
int ret = __android_log_write(priority, tag_.c_str(), msg_output);
int retry_count = 0;
while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))
{
details::os::sleep_for_millis(5);
ret = __android_log_write(priority, tag_.c_str(), msg_output);
retry_count++;
}
if (ret < 0)
{
throw_spdlog_ex("__android_log_write() failed", ret);
}
}
void flush_() override {}
private:
static android_LogPriority convert_to_android_(spdlog::level::level_enum level)
{
switch (level)
{
case spdlog::level::trace:
return ANDROID_LOG_VERBOSE;
case spdlog::level::debug:
return ANDROID_LOG_DEBUG;
case spdlog::level::info:
return ANDROID_LOG_INFO;
case spdlog::level::warn:
return ANDROID_LOG_WARN;
case spdlog::level::err:
return ANDROID_LOG_ERROR;
case spdlog::level::critical:
return ANDROID_LOG_FATAL;
default:
return ANDROID_LOG_DEFAULT;
}
}
std::string tag_;
bool use_raw_msg_;
};
using android_sink_mt = android_sink<std::mutex>;
using android_sink_st = android_sink<details::null_mutex>;
} // namespace sinks
// Create and register android syslog logger
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog")
{
return Factory::template create<sinks::android_sink_mt>(logger_name, tag);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog")
{
return Factory::template create<sinks::android_sink_st>(logger_name, tag);
}
} // namespace spdlog
#endif // __ANDROID__

View file

@ -0,0 +1,145 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/sinks/ansicolor_sink.h>
#endif
#include <spdlog/pattern_formatter.h>
#include <spdlog/details/os.h>
namespace spdlog {
namespace sinks {
template<typename ConsoleMutex>
SPDLOG_INLINE ansicolor_sink<ConsoleMutex>::ansicolor_sink(FILE *target_file, color_mode mode)
: target_file_(target_file)
, mutex_(ConsoleMutex::mutex())
, formatter_(details::make_unique<spdlog::pattern_formatter>())
{
set_color_mode(mode);
colors_[level::trace] = to_string_(white);
colors_[level::debug] = to_string_(cyan);
colors_[level::info] = to_string_(green);
colors_[level::warn] = to_string_(yellow_bold);
colors_[level::err] = to_string_(red_bold);
colors_[level::critical] = to_string_(bold_on_red);
colors_[level::off] = to_string_(reset);
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color)
{
std::lock_guard<mutex_t> lock(mutex_);
colors_[color_level] = to_string_(color);
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg)
{
// Wrap the originally formatted message in color codes.
// If color is not supported in the terminal, log as is instead.
std::lock_guard<mutex_t> lock(mutex_);
msg.color_range_start = 0;
msg.color_range_end = 0;
memory_buf_t formatted;
formatter_->format(msg, formatted);
if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
{
// before color range
print_range_(formatted, 0, msg.color_range_start);
// in color range
print_ccode_(colors_[msg.level]);
print_range_(formatted, msg.color_range_start, msg.color_range_end);
print_ccode_(reset);
// after color range
print_range_(formatted, msg.color_range_end, formatted.size());
}
else // no color
{
print_range_(formatted, 0, formatted.size());
}
fflush(target_file_);
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::flush()
{
std::lock_guard<mutex_t> lock(mutex_);
fflush(target_file_);
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_pattern(const std::string &pattern)
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)
{
std::lock_guard<mutex_t> lock(mutex_);
formatter_ = std::move(sink_formatter);
}
template<typename ConsoleMutex>
SPDLOG_INLINE bool ansicolor_sink<ConsoleMutex>::should_color()
{
return should_do_colors_;
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)
{
switch (mode)
{
case color_mode::always:
should_do_colors_ = true;
return;
case color_mode::automatic:
should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();
return;
case color_mode::never:
should_do_colors_ = false;
return;
default:
should_do_colors_ = false;
}
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code)
{
fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
}
template<typename ConsoleMutex>
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted, size_t start, size_t end)
{
fwrite(formatted.data() + start, sizeof(char), end - start, target_file_);
}
template<typename ConsoleMutex>
SPDLOG_INLINE std::string ansicolor_sink<ConsoleMutex>::to_string_(const string_view_t &sv)
{
return std::string(sv.data(), sv.size());
}
// ansicolor_stdout_sink
template<typename ConsoleMutex>
SPDLOG_INLINE ansicolor_stdout_sink<ConsoleMutex>::ansicolor_stdout_sink(color_mode mode)
: ansicolor_sink<ConsoleMutex>(stdout, mode)
{}
// ansicolor_stderr_sink
template<typename ConsoleMutex>
SPDLOG_INLINE ansicolor_stderr_sink<ConsoleMutex>::ansicolor_stderr_sink(color_mode mode)
: ansicolor_sink<ConsoleMutex>(stderr, mode)
{}
} // namespace sinks
} // namespace spdlog

View file

@ -0,0 +1,118 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/console_globals.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/sink.h>
#include <memory>
#include <mutex>
#include <string>
#include <array>
namespace spdlog {
namespace sinks {
/**
* This sink prefixes the output with an ANSI escape sequence color code
* depending on the severity
* of the message.
* If no color terminal detected, omit the escape codes.
*/
template<typename ConsoleMutex>
class ansicolor_sink : public sink
{
public:
using mutex_t = typename ConsoleMutex::mutex_t;
ansicolor_sink(FILE *target_file, color_mode mode);
~ansicolor_sink() override = default;
ansicolor_sink(const ansicolor_sink &other) = delete;
ansicolor_sink(ansicolor_sink &&other) = delete;
ansicolor_sink &operator=(const ansicolor_sink &other) = delete;
ansicolor_sink &operator=(ansicolor_sink &&other) = delete;
void set_color(level::level_enum color_level, string_view_t color);
void set_color_mode(color_mode mode);
bool should_color();
void log(const details::log_msg &msg) override;
void flush() override;
void set_pattern(const std::string &pattern) final;
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override;
// Formatting codes
const string_view_t reset = "\033[m";
const string_view_t bold = "\033[1m";
const string_view_t dark = "\033[2m";
const string_view_t underline = "\033[4m";
const string_view_t blink = "\033[5m";
const string_view_t reverse = "\033[7m";
const string_view_t concealed = "\033[8m";
const string_view_t clear_line = "\033[K";
// Foreground colors
const string_view_t black = "\033[30m";
const string_view_t red = "\033[31m";
const string_view_t green = "\033[32m";
const string_view_t yellow = "\033[33m";
const string_view_t blue = "\033[34m";
const string_view_t magenta = "\033[35m";
const string_view_t cyan = "\033[36m";
const string_view_t white = "\033[37m";
/// Background colors
const string_view_t on_black = "\033[40m";
const string_view_t on_red = "\033[41m";
const string_view_t on_green = "\033[42m";
const string_view_t on_yellow = "\033[43m";
const string_view_t on_blue = "\033[44m";
const string_view_t on_magenta = "\033[45m";
const string_view_t on_cyan = "\033[46m";
const string_view_t on_white = "\033[47m";
/// Bold colors
const string_view_t yellow_bold = "\033[33m\033[1m";
const string_view_t red_bold = "\033[31m\033[1m";
const string_view_t bold_on_red = "\033[1m\033[41m";
private:
FILE *target_file_;
mutex_t &mutex_;
bool should_do_colors_;
std::unique_ptr<spdlog::formatter> formatter_;
std::array<std::string, level::n_levels> colors_;
void print_ccode_(const string_view_t &color_code);
void print_range_(const memory_buf_t &formatted, size_t start, size_t end);
static std::string to_string_(const string_view_t &sv);
};
template<typename ConsoleMutex>
class ansicolor_stdout_sink : public ansicolor_sink<ConsoleMutex>
{
public:
explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic);
};
template<typename ConsoleMutex>
class ansicolor_stderr_sink : public ansicolor_sink<ConsoleMutex>
{
public:
explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic);
};
using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<details::console_mutex>;
using ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::console_nullmutex>;
using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<details::console_mutex>;
using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::console_nullmutex>;
} // namespace sinks
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "ansicolor_sink-inl.h"
#endif

View file

@ -0,0 +1,63 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/sinks/base_sink.h>
#endif
#include <spdlog/common.h>
#include <spdlog/pattern_formatter.h>
#include <memory>
template<typename Mutex>
SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink()
: formatter_{details::make_unique<spdlog::pattern_formatter>()}
{}
template<typename Mutex>
SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink(std::unique_ptr<spdlog::formatter> formatter)
: formatter_{std::move(formatter)}
{}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg)
{
std::lock_guard<Mutex> lock(mutex_);
sink_it_(msg);
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::flush()
{
std::lock_guard<Mutex> lock(mutex_);
flush_();
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern(const std::string &pattern)
{
std::lock_guard<Mutex> lock(mutex_);
set_pattern_(pattern);
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)
{
std::lock_guard<Mutex> lock(mutex_);
set_formatter_(std::move(sink_formatter));
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern)
{
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter)
{
formatter_ = std::move(sink_formatter);
}

View file

@ -0,0 +1,52 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
//
// base sink templated over a mutex (either dummy or real)
// concrete implementation should override the sink_it_() and flush_() methods.
// locking is taken care of in this class - no locking needed by the
// implementers..
//
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/sinks/sink.h>
namespace spdlog {
namespace sinks {
template<typename Mutex>
class base_sink : public sink
{
public:
base_sink();
explicit base_sink(std::unique_ptr<spdlog::formatter> formatter);
~base_sink() override = default;
base_sink(const base_sink &) = delete;
base_sink(base_sink &&) = delete;
base_sink &operator=(const base_sink &) = delete;
base_sink &operator=(base_sink &&) = delete;
void log(const details::log_msg &msg) final;
void flush() final;
void set_pattern(const std::string &pattern) final;
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final;
protected:
// sink formatter
std::unique_ptr<spdlog::formatter> formatter_;
mutable Mutex mutex_;
virtual void sink_it_(const details::log_msg &msg) = 0;
virtual void flush_() = 0;
virtual void set_pattern_(const std::string &pattern);
virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter);
};
} // namespace sinks
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "base_sink-inl.h"
#endif

View file

@ -0,0 +1,43 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
# include <spdlog/sinks/basic_file_sink.h>
#endif
#include <spdlog/common.h>
#include <spdlog/details/os.h>
namespace spdlog {
namespace sinks {
template<typename Mutex>
SPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(const filename_t &filename, bool truncate)
{
file_helper_.open(filename, truncate);
}
template<typename Mutex>
SPDLOG_INLINE const filename_t &basic_file_sink<Mutex>::filename() const
{
return file_helper_.filename();
}
template<typename Mutex>
SPDLOG_INLINE void basic_file_sink<Mutex>::sink_it_(const details::log_msg &msg)
{
memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted);
file_helper_.write(formatted);
}
template<typename Mutex>
SPDLOG_INLINE void basic_file_sink<Mutex>::flush_()
{
file_helper_.flush();
}
} // namespace sinks
} // namespace spdlog

View file

@ -0,0 +1,58 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/details/file_helper.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/synchronous_factory.h>
#include <mutex>
#include <string>
namespace spdlog {
namespace sinks {
/*
* Trivial file sink with single file as target
*/
template<typename Mutex>
class basic_file_sink final : public base_sink<Mutex>
{
public:
explicit basic_file_sink(const filename_t &filename, bool truncate = false);
const filename_t &filename() const;
protected:
void sink_it_(const details::log_msg &msg) override;
void flush_() override;
private:
details::file_helper file_helper_;
};
using basic_file_sink_mt = basic_file_sink<std::mutex>;
using basic_file_sink_st = basic_file_sink<details::null_mutex>;
} // namespace sinks
//
// factory functions
//
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)
{
return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)
{
return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate);
}
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "basic_file_sink-inl.h"
#endif

View file

@ -0,0 +1,242 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/file_helper.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/fmt/chrono.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/os.h>
#include <spdlog/details/circular_q.h>
#include <spdlog/details/synchronous_factory.h>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
namespace spdlog {
namespace sinks {
/*
* Generator of daily log file names in format basename.YYYY-MM-DD.ext
*/
struct daily_filename_calculator
{
// Create filename for the form basename.YYYY-MM-DD
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
return fmt::format(
SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);
}
};
/*
* Generator of daily log file names with strftime format.
* Usages:
* auto sink = std::make_shared<spdlog::sinks::daily_file_format_sink_mt>("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);"
* auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour, minute)"
*
*/
struct daily_filename_format_calculator
{
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
// generate fmt datetime format string, e.g. {:%Y-%m-%d}.
filename_t fmt_filename = fmt::format(SPDLOG_FILENAME_T("{{:{}}}"), filename);
#if defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesnt allow fmt::runtime(..) with wchar here
return fmt::format(fmt_filename, now_tm);
#else
return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm);
#endif
}
};
/*
* Rotating file sink based on date.
* If truncate != false , the created file will be truncated.
* If max_files > 0, retain only the last max_files and delete previous.
*/
template<typename Mutex, typename FileNameCalc = daily_filename_calculator>
class daily_file_sink final : public base_sink<Mutex>
{
public:
// create daily file sink which rotates on given time
daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0)
: base_filename_(std::move(base_filename))
, rotation_h_(rotation_hour)
, rotation_m_(rotation_minute)
, truncate_(truncate)
, max_files_(max_files)
, filenames_q_()
{
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
{
throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
}
auto now = log_clock::now();
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
file_helper_.open(filename, truncate_);
rotation_tp_ = next_rotation_tp_();
if (max_files_ > 0)
{
init_filenames_q_();
}
}
filename_t filename()
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
return file_helper_.filename();
}
protected:
void sink_it_(const details::log_msg &msg) override
{
auto time = msg.time;
bool should_rotate = time >= rotation_tp_;
if (should_rotate)
{
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time));
file_helper_.open(filename, truncate_);
rotation_tp_ = next_rotation_tp_();
}
memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted);
file_helper_.write(formatted);
// Do the cleaning only at the end because it might throw on failure.
if (should_rotate && max_files_ > 0)
{
delete_old_();
}
}
void flush_() override
{
file_helper_.flush();
}
private:
void init_filenames_q_()
{
using details::os::path_exists;
filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_));
std::vector<filename_t> filenames;
auto now = log_clock::now();
while (filenames.size() < max_files_)
{
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
if (!path_exists(filename))
{
break;
}
filenames.emplace_back(filename);
now -= std::chrono::hours(24);
}
for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter)
{
filenames_q_.push_back(std::move(*iter));
}
}
tm now_tm(log_clock::time_point tp)
{
time_t tnow = log_clock::to_time_t(tp);
return spdlog::details::os::localtime(tnow);
}
log_clock::time_point next_rotation_tp_()
{
auto now = log_clock::now();
tm date = now_tm(now);
date.tm_hour = rotation_h_;
date.tm_min = rotation_m_;
date.tm_sec = 0;
auto rotation_time = log_clock::from_time_t(std::mktime(&date));
if (rotation_time > now)
{
return rotation_time;
}
return {rotation_time + std::chrono::hours(24)};
}
// Delete the file N rotations ago.
// Throw spdlog_ex on failure to delete the old file.
void delete_old_()
{
using details::os::filename_to_str;
using details::os::remove_if_exists;
filename_t current_file = file_helper_.filename();
if (filenames_q_.full())
{
auto old_filename = std::move(filenames_q_.front());
filenames_q_.pop_front();
bool ok = remove_if_exists(old_filename) == 0;
if (!ok)
{
filenames_q_.push_back(std::move(current_file));
throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno);
}
}
filenames_q_.push_back(std::move(current_file));
}
filename_t base_filename_;
int rotation_h_;
int rotation_m_;
log_clock::time_point rotation_tp_;
details::file_helper file_helper_;
bool truncate_;
uint16_t max_files_;
details::circular_q<filename_t> filenames_q_;
};
using daily_file_sink_mt = daily_file_sink<std::mutex>;
using daily_file_sink_st = daily_file_sink<details::null_mutex>;
using daily_file_format_sink_mt = daily_file_sink<std::mutex, daily_filename_format_calculator>;
using daily_file_format_sink_st = daily_file_sink<details::null_mutex, daily_filename_format_calculator>;
} // namespace sinks
//
// factory functions
//
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_mt(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_format_mt(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::daily_file_format_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_st(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> daily_logger_format_st(
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
{
return Factory::template create<sinks::daily_file_format_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
}
} // namespace spdlog

View file

@ -0,0 +1,97 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#include "base_sink.h"
#include <spdlog/details/log_msg.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/pattern_formatter.h>
#include <algorithm>
#include <memory>
#include <mutex>
#include <vector>
// Distribution sink (mux). Stores a vector of sinks which get called when log
// is called
namespace spdlog {
namespace sinks {
template<typename Mutex>
class dist_sink : public base_sink<Mutex>
{
public:
dist_sink() = default;
explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks)
: sinks_(sinks)
{}
dist_sink(const dist_sink &) = delete;
dist_sink &operator=(const dist_sink &) = delete;
void add_sink(std::shared_ptr<sink> sink)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_.push_back(sink);
}
void remove_sink(std::shared_ptr<sink> sink)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());
}
void set_sinks(std::vector<std::shared_ptr<sink>> sinks)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
sinks_ = std::move(sinks);
}
std::vector<std::shared_ptr<sink>> &sinks()
{
return sinks_;
}
protected:
void sink_it_(const details::log_msg &msg) override
{
for (auto &sink : sinks_)
{
if (sink->should_log(msg.level))
{
sink->log(msg);
}
}
}
void flush_() override
{
for (auto &sink : sinks_)
{
sink->flush();
}
}
void set_pattern_(const std::string &pattern) override
{
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
}
void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override
{
base_sink<Mutex>::formatter_ = std::move(sink_formatter);
for (auto &sink : sinks_)
{
sink->set_formatter(base_sink<Mutex>::formatter_->clone());
}
}
std::vector<std::shared_ptr<sink>> sinks_;
};
using dist_sink_mt = dist_sink<std::mutex>;
using dist_sink_st = dist_sink<details::null_mutex>;
} // namespace sinks
} // namespace spdlog

Some files were not shown because too many files have changed in this diff Show more