僅考慮 UTF8
僅考慮從 string 轉 value,或從 value 轉 string。不考慮 io stream。
fon9/StrView.hpp
雖然 C++17 已納入 std::string_view
,但不符合我的需求。例如,沒有提供最常用的建構:
template <size_t sz> StrView(const char (&cstr)[sz])
template <class AuxT >
const char * StrToNum (StrView str, AuxT& aux, typename AuxT::ResultT& out);
template <typename NumT, class AuxT = AutoStrToAux<NumT>>
NumT StrTo (const StrView& str, NumT value = NumT{}, const char ** endptr = nullptr );
額外提供 fon9::isspace()
, fon9::isalpha()
... fon9/StrTools.hpp
,因為標準函式庫的速度太慢。
而 fon9 只考慮 UTF-8(ASCII) 所以速度可以更快。
底下是使用 fon9/StrTo_UT.cpp
測試的部分結果
Hardware: HP ProLiant DL380p Gen8 / E5-2680 v2 @ 2.80GHz
OS: ESXi 6.5.0 Update 1 (Build 5969303) / VM: Windows server 2016(1607)
Compiler: MSVC 2015(VC 19.00.24215.1)
::isspace() : 0.046315328 secs / 1,000,000 times = 46.315328000 ns
std::isspace() : 0.045184748 secs / 1,000,000 times = 45.184748000 ns
fon9::isspace() : 0.001268421 secs / 1,000,000 times = 1.268421000 ns
--- int64/imax ---
NaiveStrToSInt() : 0.009116134 secs / 1,000,000 times = 9.116134000 ns
StrToNum(int64) : 0.023595196 secs / 1,000,000 times = 23.595196000 ns
strtoimax() : 0.080947254 secs / 1,000,000 times = 80.947254000 ns
OS: ESXi 6.5.0 Update 1 (Build 5969303) / VM: ubuntu16 4.4.0-62-generic
Compiler: g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
::isspace() : 0.002872489 secs / 1,000,000 times = 2.872489000 ns
std::isspace() : 0.003229382 secs / 1,000,000 times = 3.229382000 ns
fon9::isspace() : 0.000490955 secs / 1,000,000 times = 0.490955000 ns
--- int64/imax ---
NaiveStrToSInt() : 0.009790892 secs / 1,000,000 times = 9.790892000 ns
StrToNum(int64) : 0.014731447 secs / 1,000,000 times = 14.731447000 ns
strtoimax() : 0.039363580 secs / 1,000,000 times = 39.363580000 ns
// / 建立 value 的 10 進位字串.
// / - 從 (*--pout) 往前填入.
// / - 傳回最後一次 pout 位置: 字串開始位置.
template <typename IntT>
char * ToStrRev (char * pout, IntT value);
如果不確定要多少 buffer,則使用 fon9::NumOutBuf
會是比較保險的做法
fon9::NumOutBuf nbuf;
nbuf.SetEOS();
std::cout << fon9::ToStrRev(nbuf.end(), value);
template <typename IntT>
char * ToStrRev (char * pout, IntT value, const FmtDef& fmt);
底下是使用 fon9/ToStr_UT.cpp
測試的部分結果
Hardware: HP ProLiant DL380p Gen8 / E5-2680 v2 @ 2.80GHz
OS: ESXi 6.5.0 Update 1 (Build 5969303) / VM: Windows server 2016(1607)
ToStrRev(long) : 0.006805115 secs / 1,000,000 times = 6.805115000 ns
_ltoa(long) : 0.020169359 secs / 1,000,000 times = 20.169359000 ns
to_string(long) : 0.023836049 secs / 1,000,000 times = 23.836049000 ns
sprintf(long) : 0.159748090 secs / 1,000,000 times = 159.748090000 ns
RevFormat() : 0.031855329 secs / 1,000,000 times = 31.855329000 ns
ToStrRev(Fmt) : 0.016562426 secs / 1,000,000 times = 16.562426000 ns
OS: ESXi 6.5.0 Update 1 (Build 5969303) / VM: ubuntu16 4.4.0-62-generic
ToStrRev(long) : 0.005728993 secs / 1,000,000 times = 5.728993000 ns
to_string(long) : 0.086369344 secs / 1,000,000 times = 86.369344000 ns
sprintf(long) : 0.075958616 secs / 1,000,000 times = 75.958616000 ns
RevFormat() : 0.026977021 secs / 1,000,000 times = 26.977021000 ns
ToStrRev(Fmt) : 0.015506810 secs / 1,000,000 times = 15.506810000 ns
Decimal:使用「整數 + 小數長度」的型式來表達浮點數
fon9/Decimal.hpp
因交易系統對小數精確度的要求,無法使用 double,即使 long double 仍有精確度問題,
所以必須自行設計一個「可確定精確度」的型別。
例: Decimal<int64_t, 6> v;
使用 int64_t 儲存數值,小數 6 位。
如果 v.GetOrigValue() == 987654321
則表示的數字是: 987.654321
轉字串依然使用 ToStrRev()
。
字串轉 Decimal: 依然使用 ResultT StrTo(const StrView& str, ResultT value = ResultT::Null(), const char** endptr = nullptr)
,
其中的 ResultT
為 Decimal<>
型別。
時間間隔 fon9/TimeInterval.hpp
時間戳、時區 fon9/TimeStamp.hpp
取得現在 UTC 時間:fon9::UtcNow();
取得現在 本地時間:fon9::TimeStamp lo = fon9::UtcNow() + fon9::GetLocalTimeZoneOffset();
轉字串: char* ToStrRev(char* pout, TimeStamp ts, const FmtTS& fmt);
其中的 FmtTS
如果使用字串建構 FmtTS(StrView fmtstr)
:
fmtstr: [TsFmtItemChar[ch]][[+-TimeZoneOffset(spc)][width][.precision]]
TimeZoneOffset
若使用 TimeZoneName
則必須加上「'」單引號,例如: 'TW'
如果尾端有 "." 或 ".0" 則自動小數位, 如果尾端沒有 ".precision" 則不顯示小數位
其中的 TsFmtItemChar
:
enum class TsFmtItemChar : char {
YYYYMMDDHHMMSS = ' L' ,
YYYYMMDD = ' f' ,
YYYY_MM_DD = ' F' ,
YYYYsMMsDD = ' K' ,
HHMMSS = ' t' ,
HH_MM_SS = ' T' ,
Year4 = ' Y' ,
Month02 = ' m' ,
Day02 = ' d' ,
Hour02 = ' H' ,
Minute02 = ' M' ,
Second02 = ' S' ,
};
ch: 除了 TsFmtItemChar
之外的字元,保留不變,原樣輸出。
範例:
"L" 輸出 "20180412144156"
"f" 輸出 "20180412"
"F" 輸出 "2018-04-12"
"K" 輸出 "2018/04/12"
"K-T" 輸出 "2018/04/12-14:41:56"
fon9/RevPrint.hpp
基本格式化字串: RevPrint(RevBuffer& rbuf, value1, value2, fmt2, ...);
value1 無格式化,轉呼叫 ToStrRev(pout, value1);
value2 使用 fmt2 格式化,轉呼叫 ToStrRev(pout, value2, fmt2);
格式化字串傳回 StrT
可以是 std::string
template <class StrT, class... ArgsT> StrT& RevPrintAppendTo(StrT& dst, ArgsT&&... args);
template <class StrT, class... ArgsT> StrT RevPrintTo(ArgsT&&... args);
fon9/RevFormat.hpp
類似的 library: {fmt} library
格式化字串, 類似 sprintf();
, fmt::format()
RevFormat(rbuf, format, value...);
format: "{0:fmt0} {1:fmt1} {3}..."
其中大括號裡面的參數Id從0開始,不可省略。
一般數字、字串的 fmt 參數格式 [flags][width][.precision]
定義, 與 printf
的 format 完全一樣
例如:
// output: "/abc/def/123"
void test (fon9::RevBuffer& rbuf) {
fon9::RevFormat (rbuf, " {0}" , 123 );
fon9::RevFormat (rbuf, " /{0:x}/{1}/" , 0xabc , fon9::ToHex{0xdef });
}
預先格式化,如果某個格式很常用到,可預先將格式解析好:
static FmtPre msgfmt{" {0} {1} {2}" };
msgfmt (rbuf, " Hello" , " World" , ' !' );