diff --git a/Editor/Source/ImGUIConsoleSink.h b/Editor/Source/ImGUIConsoleSink.h index d5bc8b2ca..878c89538 100644 --- a/Editor/Source/ImGUIConsoleSink.h +++ b/Editor/Source/ImGUIConsoleSink.h @@ -22,7 +22,7 @@ namespace Lumos spdlog::memory_buf_t formatted; spdlog::sinks::base_sink::formatter_->format(msg, formatted); std::string source = fmt::format("File : {0} | Function : {1} | Line : {2}", msg.source.filename, msg.source.funcname, msg.source.line); - const auto time = fmt::localtime(msg.time); + const auto time = fmt::localtime(std::chrono::system_clock::to_time_t(msg.time)); auto processed = fmt::format("{:%H:%M:%S}", time); auto message = CreateSharedPtr(fmt::to_string(formatted), GetMessageLevel(msg.level), source, static_cast(msg.thread_id), processed); diff --git a/Editor/Source/InspectorPanel.cpp b/Editor/Source/InspectorPanel.cpp index 204b0603f..df1c59886 100644 --- a/Editor/Source/InspectorPanel.cpp +++ b/Editor/Source/InspectorPanel.cpp @@ -794,13 +794,13 @@ end if(ImGuiUtilities::Property("Fov", fov, 1.0f, 120.0f)) camera.SetFOV(fov); - float near = camera.GetNear(); - if(ImGuiUtilities::Property("Near", near, 0.0f, 10.0f)) - camera.SetNear(near); + float n = camera.GetNear(); + if(ImGuiUtilities::Property("Near", n, 0.0f, 10.0f)) + camera.SetNear(n); - float far = camera.GetFar(); - if(ImGuiUtilities::Property("Far", far, 10.0f, 10000.0f)) - camera.SetFar(far); + float f = camera.GetFar(); + if(ImGuiUtilities::Property("Far", f, 10.0f, 10000.0f)) + camera.SetFar(f); float scale = camera.GetScale(); if(ImGuiUtilities::Property("Scale", scale, 0.0f, 1000.0f)) diff --git a/Lumos/Assets/Shaders/CompiledSPV/ForwardPBR.frag.spv b/Lumos/Assets/Shaders/CompiledSPV/ForwardPBR.frag.spv index a7e206bd8..40eeb66cd 100644 Binary files a/Lumos/Assets/Shaders/CompiledSPV/ForwardPBR.frag.spv and b/Lumos/Assets/Shaders/CompiledSPV/ForwardPBR.frag.spv differ diff --git a/Lumos/Assets/Shaders/CompiledSPV/Headers/ForwardPBRfragspv.hpp b/Lumos/Assets/Shaders/CompiledSPV/Headers/ForwardPBRfragspv.hpp index 5eb8c4fa8..c8c89c0b4 100644 --- a/Lumos/Assets/Shaders/CompiledSPV/Headers/ForwardPBRfragspv.hpp +++ b/Lumos/Assets/Shaders/CompiledSPV/Headers/ForwardPBRfragspv.hpp @@ -3,11 +3,11 @@ #include #include -constexpr uint32_t spirv_ForwardPBRfragspv_size = 48476; -constexpr std::array spirv_ForwardPBRfragspv = { - 0x07230203, 0x00010000, 0x000D000A, 0x000007C3, 0x00000000, 0x00020011, 0x00000001, 0x0006000B, +constexpr uint32_t spirv_ForwardPBRfragspv_size = 48640; +constexpr std::array spirv_ForwardPBRfragspv = { + 0x07230203, 0x00010000, 0x000D000A, 0x000007C8, 0x00000000, 0x00020011, 0x00000001, 0x0006000B, 0x00000001, 0x4C534C47, 0x6474732E, 0x3035342E, 0x00000000, 0x0003000E, 0x00000000, 0x00000001, -0x0008000F, 0x00000004, 0x00000004, 0x6E69616D, 0x00000000, 0x000001FE, 0x0000059F, 0x00000666, +0x0008000F, 0x00000004, 0x00000004, 0x6E69616D, 0x00000000, 0x000001FC, 0x000005A0, 0x0000066C, 0x00030010, 0x00000004, 0x00000007, 0x00030003, 0x00000002, 0x000001C2, 0x00090004, 0x415F4C47, 0x735F4252, 0x72617065, 0x5F657461, 0x64616873, 0x6F5F7265, 0x63656A62, 0x00007374, 0x00090004, 0x415F4C47, 0x735F4252, 0x69646168, 0x6C5F676E, 0x75676E61, 0x5F656761, 0x70303234, 0x006B6361, @@ -59,1465 +59,1471 @@ constexpr std::array spirv_ForwardPBRfragspv = { 0x6465626C, 0x0000286F, 0x00060005, 0x00000073, 0x4D746547, 0x6C617465, 0x2863696C, 0x00000000, 0x00060005, 0x00000076, 0x52746547, 0x6867756F, 0x7373656E, 0x00000028, 0x00040005, 0x00000078, 0x41746547, 0x0000284F, 0x00070005, 0x0000007B, 0x45746547, 0x7373696D, 0x28657669, 0x3B336676, -0x00000000, 0x00040005, 0x0000007A, 0x65626C61, 0x00006F64, 0x00070005, 0x0000007D, 0x4E746547, -0x616D726F, 0x6F72466C, 0x70614D6D, 0x00000028, 0x00050005, 0x00000083, 0x73696F4E, 0x66762865, -0x00003B32, 0x00030005, 0x00000082, 0x00006F63, 0x00090005, 0x0000008B, 0x65676F56, 0x7369446C, -0x6D61536B, 0x28656C70, 0x693B3169, 0x31663B31, 0x0000003B, 0x00050005, 0x00000088, 0x706D6173, -0x6E49656C, 0x00786564, 0x00060005, 0x00000089, 0x706D6173, 0x4373656C, 0x746E756F, 0x00000000, -0x00030005, 0x0000008A, 0x00696870, 0x00090005, 0x00000091, 0x53746547, 0x6F646168, 0x61694277, -0x66762873, 0x66763B33, 0x31693B33, 0x0000003B, 0x00060005, 0x0000008E, 0x6867696C, 0x72694474, -0x69746365, 0x00006E6F, 0x00040005, 0x0000008F, 0x6D726F6E, 0x00006C61, 0x00050005, 0x00000090, -0x64616873, 0x6E49776F, 0x00786564, 0x00100005, 0x0000009E, 0x53464350, 0x6F646168, 0x72694477, -0x69746365, 0x6C616E6F, 0x6867694C, 0x41732874, 0x763B3132, 0x663B3466, 0x66763B31, 0x66763B33, -0x66763B33, 0x31693B33, 0x0000003B, 0x00050005, 0x00000097, 0x64616873, 0x614D776F, 0x00000070, -0x00060005, 0x00000098, 0x64616873, 0x6F43776F, 0x7364726F, 0x00000000, 0x00050005, 0x00000099, -0x61527675, 0x73756964, 0x00000000, 0x00060005, 0x0000009A, 0x6867696C, 0x72694474, 0x69746365, -0x00006E6F, 0x00040005, 0x0000009B, 0x6D726F6E, 0x00006C61, 0x00040005, 0x0000009C, 0x6F507377, -0x00000073, 0x00060005, 0x0000009D, 0x63736163, 0x49656461, 0x7865646E, 0x00000000, 0x00090005, -0x000000A2, 0x636C6143, 0x74616C75, 0x73614365, 0x65646163, 0x65646E49, 0x66762878, 0x00003B33, -0x00040005, 0x000000A1, 0x6F507377, 0x00000073, 0x000A0005, 0x000000A9, 0x636C6143, 0x74616C75, -0x61685365, 0x28776F64, 0x3B336676, 0x763B3169, 0x763B3366, 0x003B3366, 0x00040005, 0x000000A5, -0x6F507377, 0x00000073, 0x00060005, 0x000000A6, 0x63736163, 0x49656461, 0x7865646E, 0x00000000, -0x00060005, 0x000000A7, 0x6867696C, 0x72694474, 0x69746365, 0x00006E6F, 0x00040005, 0x000000A8, -0x6D726F6E, 0x00006C61, 0x00050005, 0x000000AB, 0x6574614D, 0x6C616972, 0x00000000, 0x00050006, -0x000000AB, 0x00000000, 0x65626C41, 0x00006F64, 0x00060006, 0x000000AB, 0x00000001, 0x6174654D, -0x63696C6C, 0x00000000, 0x00060006, 0x000000AB, 0x00000002, 0x67756F52, 0x73656E68, 0x00000073, -0x00080006, 0x000000AB, 0x00000003, 0x63726550, 0x75747065, 0x6F526C61, 0x6E686775, 0x00737365, -0x00060006, 0x000000AB, 0x00000004, 0x6C666552, 0x61746365, 0x0065636E, 0x00060006, 0x000000AB, -0x00000005, 0x73696D45, 0x65766973, 0x00000000, 0x00050006, 0x000000AB, 0x00000006, 0x6D726F4E, -0x00006C61, 0x00040006, 0x000000AB, 0x00000007, 0x00004F41, 0x00050006, 0x000000AB, 0x00000008, -0x77656956, 0x00000000, 0x00050006, 0x000000AB, 0x00000009, 0x746F444E, 0x00000056, 0x00040006, -0x000000AB, 0x0000000A, 0x00003046, 0x00080006, 0x000000AB, 0x0000000B, 0x72656E45, 0x6F437967, -0x6E65706D, 0x69746173, 0x00006E6F, 0x00040006, 0x000000AB, 0x0000000C, 0x00676664, 0x00040005, -0x000000AC, 0x6867694C, 0x00000074, 0x00050006, 0x000000AC, 0x00000000, 0x6F6C6F63, 0x00007275, -0x00060006, 0x000000AC, 0x00000001, 0x69736F70, 0x6E6F6974, 0x00000000, 0x00060006, 0x000000AC, -0x00000002, 0x65726964, 0x6F697463, 0x0000006E, 0x00060006, 0x000000AC, 0x00000003, 0x65746E69, -0x7469736E, 0x00000079, 0x00050006, 0x000000AC, 0x00000004, 0x69646172, 0x00007375, 0x00050006, -0x000000AC, 0x00000005, 0x65707974, 0x00000000, 0x00050006, 0x000000AC, 0x00000006, 0x6C676E61, -0x00000065, 0x00230005, 0x000000B5, 0x746F7349, 0x69706F72, 0x626F4C63, 0x74732865, 0x74637572, -0x74614D2D, 0x61697265, 0x66762D6C, 0x31662D34, 0x2D31662D, 0x662D3166, 0x66762D31, 0x66762D33, -0x31662D33, 0x3366762D, 0x2D31662D, 0x2D336676, 0x2D336676, 0x31326676, 0x7274733B, 0x2D746375, -0x6867694C, 0x66762D74, 0x66762D34, 0x66762D34, 0x31662D34, 0x2D31662D, 0x662D3166, 0x763B3131, -0x663B3366, 0x31663B31, 0x3B31663B, 0x003B3166, 0x00050005, 0x000000AE, 0x6574616D, 0x6C616972, -0x00000000, 0x00040005, 0x000000AF, 0x6867696C, 0x00000074, 0x00030005, 0x000000B0, 0x00000068, -0x00030005, 0x000000B1, 0x00566F4E, 0x00030005, 0x000000B2, 0x004C6F4E, 0x00030005, 0x000000B3, -0x00486F4E, 0x00030005, 0x000000B4, 0x00486F4C, 0x00180005, 0x000000BC, 0x66666944, 0x4C657375, -0x2865626F, 0x75727473, 0x4D2D7463, 0x72657461, 0x2D6C6169, 0x2D346676, 0x662D3166, 0x31662D31, -0x2D31662D, 0x2D336676, 0x2D336676, 0x762D3166, 0x662D3366, 0x66762D31, 0x66762D33, 0x66762D33, -0x663B3132, 0x31663B31, 0x3B31663B, 0x00000000, 0x00050005, 0x000000B8, 0x6574616D, 0x6C616972, -0x00000000, 0x00030005, 0x000000B9, 0x00566F4E, 0x00030005, 0x000000BA, 0x004C6F4E, 0x00030005, -0x000000BB, 0x00486F4C, 0x00230005, 0x000000C5, 0x63657053, 0x72616C75, 0x65626F4C, 0x72747328, -0x2D746375, 0x6574614D, 0x6C616972, 0x3466762D, 0x2D31662D, 0x662D3166, 0x31662D31, 0x3366762D, -0x3366762D, 0x2D31662D, 0x2D336676, 0x762D3166, 0x762D3366, 0x762D3366, 0x3B313266, 0x75727473, -0x4C2D7463, 0x74686769, 0x3466762D, 0x3466762D, 0x3466762D, 0x2D31662D, 0x662D3166, 0x31662D31, -0x66763B31, 0x31663B33, 0x3B31663B, 0x663B3166, 0x00003B31, 0x00050005, 0x000000BE, 0x6574616D, -0x6C616972, 0x00000000, 0x00040005, 0x000000BF, 0x6867696C, 0x00000074, 0x00030005, 0x000000C0, -0x00000068, 0x00030005, 0x000000C1, 0x00566F4E, 0x00030005, 0x000000C2, 0x004C6F4E, 0x00030005, -0x000000C3, 0x00486F4E, 0x00030005, 0x000000C4, 0x00486F4C, 0x00170005, 0x000000CC, 0x6867694C, -0x676E6974, 0x33667628, 0x3366763B, 0x7274733B, 0x2D746375, 0x6574614D, 0x6C616972, 0x3466762D, -0x2D31662D, 0x662D3166, 0x31662D31, 0x3366762D, 0x3366762D, 0x2D31662D, 0x2D336676, 0x762D3166, -0x762D3366, 0x762D3366, 0x3B313266, 0x00000000, 0x00030005, 0x000000C9, 0x00003046, 0x00040005, -0x000000CA, 0x6F507377, 0x00000073, 0x00050005, 0x000000CB, 0x6574616D, 0x6C616972, 0x00000000, -0x00150005, 0x000000D1, 0x284C4249, 0x3B336676, 0x3B336676, 0x75727473, 0x4D2D7463, 0x72657461, -0x2D6C6169, 0x2D346676, 0x662D3166, 0x31662D31, 0x2D31662D, 0x2D336676, 0x2D336676, 0x762D3166, -0x662D3366, 0x66762D31, 0x66762D33, 0x66762D33, 0x003B3132, 0x00030005, 0x000000CE, 0x00003046, -0x00030005, 0x000000CF, 0x0000724C, 0x00050005, 0x000000D0, 0x6574616D, 0x6C616972, 0x00000000, -0x00050005, 0x000000D4, 0x64616853, 0x6146776F, 0x00006564, 0x00030005, 0x000000D6, 0x00494850, -0x00030005, 0x000000D8, 0x00003278, 0x00040005, 0x000000E9, 0x61726170, 0x0000006D, 0x00030005, -0x000000FC, 0x0048784E, 0x00030005, 0x000000FE, 0x00000061, 0x00030005, 0x00000102, 0x0000006B, -0x00030005, 0x0000010C, 0x00000064, 0x00040005, 0x0000011C, 0x61726170, 0x0000006D, 0x00030005, -0x0000012E, 0x00303966, 0x00060005, 0x00000138, 0x6867696C, 0x61635374, 0x72657474, 0x00000000, -0x00040005, 0x00000139, 0x61726170, 0x0000006D, 0x00040005, 0x0000013A, 0x61726170, 0x0000006D, -0x00040005, 0x0000013C, 0x61726170, 0x0000006D, 0x00050005, 0x0000013F, 0x77656976, 0x74616353, -0x00726574, 0x00040005, 0x00000140, 0x61726170, 0x0000006D, 0x00040005, 0x00000141, 0x61726170, -0x0000006D, 0x00040005, 0x00000143, 0x61726170, 0x0000006D, 0x00030005, 0x0000014C, 0x00003261, -0x00040005, 0x00000150, 0x4C584747, 0x00000000, 0x00040005, 0x0000015E, 0x56584747, 0x00000000, -0x00050005, 0x00000172, 0x72657061, 0x65727574, 0x00000000, 0x00050005, 0x00000178, 0x7263696D, -0x6168536F, 0x00776F64, 0x00040005, 0x0000017C, 0x61726170, 0x0000006D, 0x00040005, 0x00000183, -0x61726170, 0x0000006D, 0x00040005, 0x00000185, 0x61726170, 0x0000006D, 0x00040005, 0x00000187, -0x61726170, 0x0000006D, 0x00040005, 0x00000189, 0x61726170, 0x0000006D, 0x00040005, 0x000001B0, -0x61726170, 0x0000006D, 0x00040005, 0x000001B2, 0x61726170, 0x0000006D, 0x00040005, 0x000001B7, -0x61726170, 0x0000006D, 0x00040005, 0x000001B9, 0x61726170, 0x0000006D, 0x00040005, 0x000001BB, -0x61726170, 0x0000006D, 0x00030005, 0x000001C0, 0x00303966, 0x00040005, 0x000001C4, 0x61726170, -0x0000006D, 0x00040005, 0x000001C6, 0x61726170, 0x0000006D, 0x00040005, 0x000001C8, 0x61726170, -0x0000006D, 0x00070005, 0x000001DD, 0x66696E55, 0x4D6D726F, 0x72657461, 0x446C6169, 0x00617461, -0x00070006, 0x000001DD, 0x00000000, 0x65626C41, 0x6F436F64, 0x72756F6C, 0x00000000, 0x00060006, -0x000001DD, 0x00000001, 0x67756F52, 0x73656E68, 0x00000073, 0x00060006, 0x000001DD, 0x00000002, -0x6174654D, 0x63696C6C, 0x00000000, 0x00060006, 0x000001DD, 0x00000003, 0x6C666552, 0x61746365, -0x0065636E, 0x00060006, 0x000001DD, 0x00000004, 0x73696D45, 0x65766973, 0x00000000, 0x00070006, -0x000001DD, 0x00000005, 0x65626C41, 0x614D6F64, 0x63614670, 0x00726F74, 0x00080006, 0x000001DD, -0x00000006, 0x6174654D, 0x63696C6C, 0x4670614D, 0x6F746361, 0x00000072, 0x00080006, 0x000001DD, -0x00000007, 0x67756F52, 0x73656E68, 0x70614D73, 0x74636146, 0x0000726F, 0x00070006, 0x000001DD, -0x00000008, 0x6D726F4E, 0x614D6C61, 0x63614670, 0x00726F74, 0x00080006, 0x000001DD, 0x00000009, -0x73696D45, 0x65766973, 0x4670614D, 0x6F746361, 0x00000072, 0x00060006, 0x000001DD, 0x0000000A, -0x614D4F41, 0x63614670, 0x00726F74, 0x00060006, 0x000001DD, 0x0000000B, 0x68706C41, 0x74754361, -0x0066664F, 0x00060006, 0x000001DD, 0x0000000C, 0x6B726F77, 0x776F6C66, 0x00000000, 0x00070005, -0x000001DF, 0x6574616D, 0x6C616972, 0x706F7250, 0x69747265, 0x00007365, 0x00050005, 0x000001F9, -0x6C415F75, 0x6F646562, 0x0070614D, 0x00050005, 0x000001FC, 0x74726556, 0x61447865, 0x00006174, -0x00050006, 0x000001FC, 0x00000000, 0x6F6C6F43, 0x00007275, 0x00060006, 0x000001FC, 0x00000001, -0x43786554, 0x64726F6F, 0x00000000, 0x00060006, 0x000001FC, 0x00000002, 0x69736F50, 0x6E6F6974, -0x00000000, 0x00050006, 0x000001FC, 0x00000003, 0x6D726F4E, 0x00006C61, 0x00060006, 0x000001FC, -0x00000004, 0x6C726F57, 0x726F4E64, 0x006C616D, 0x00060005, 0x000001FE, 0x74726556, 0x754F7865, -0x74757074, 0x00000000, 0x00040005, 0x00000204, 0x61726170, 0x0000006D, 0x00060005, 0x0000021D, -0x654D5F75, 0x6C6C6174, 0x614D6369, 0x00000070, 0x00060005, 0x00000239, 0x6F525F75, 0x6E686775, -0x4D737365, 0x00007061, 0x00040005, 0x00000250, 0x4F415F75, 0x0070614D, 0x00060005, 0x0000026C, -0x6D455F75, 0x69737369, 0x614D6576, 0x00000070, 0x00040005, 0x00000271, 0x61726170, 0x0000006D, -0x00040005, 0x00000284, 0x6D726F4E, 0x00006C61, 0x00050005, 0x00000285, 0x6F4E5F75, 0x6C616D72, -0x0070614D, 0x00050005, 0x000002A2, 0x646C6F47, 0x6E416E65, 0x00656C67, 0x00030005, 0x000002A4, -0x00000072, 0x00040005, 0x000002AD, 0x74656874, 0x00000061, 0x00040005, 0x000002B4, 0x656E6973, -0x00000000, 0x00040005, 0x000002B7, 0x69736F63, 0x0000656E, 0x00040005, 0x000002C3, 0x426E696D, -0x00736169, 0x00040005, 0x000002C4, 0x6867694C, 0x00000074, 0x00050006, 0x000002C4, 0x00000000, -0x6F6C6F63, 0x00007275, 0x00060006, 0x000002C4, 0x00000001, 0x69736F70, 0x6E6F6974, 0x00000000, -0x00060006, 0x000002C4, 0x00000002, 0x65726964, 0x6F697463, 0x0000006E, 0x00060006, 0x000002C4, -0x00000003, 0x65746E69, 0x7469736E, 0x00000079, 0x00050006, 0x000002C4, 0x00000004, 0x69646172, -0x00007375, 0x00050006, 0x000002C4, 0x00000005, 0x65707974, 0x00000000, 0x00050006, 0x000002C4, -0x00000006, 0x6C676E61, 0x00000065, 0x00050005, 0x000002CB, 0x4C4F4255, 0x74686769, 0x00000000, -0x00050006, 0x000002CB, 0x00000000, 0x6867696C, 0x00007374, 0x00070006, 0x000002CB, 0x00000001, -0x64616853, 0x7254776F, 0x66736E61, 0x006D726F, 0x00060006, 0x000002CB, 0x00000002, 0x77656956, -0x7274614D, 0x00007869, 0x00060006, 0x000002CB, 0x00000003, 0x6867694C, 0x65695674, 0x00000077, -0x00060006, 0x000002CB, 0x00000004, 0x73616942, 0x7274614D, 0x00007869, 0x00070006, 0x000002CB, -0x00000005, 0x656D6163, 0x6F506172, 0x69746973, 0x00006E6F, 0x00060006, 0x000002CB, 0x00000006, -0x696C7053, 0x70654474, 0x00736874, 0x00060006, 0x000002CB, 0x00000007, 0x6867694C, 0x7A695374, -0x00000065, 0x00070006, 0x000002CB, 0x00000008, 0x5378614D, 0x6F646168, 0x73694477, 0x00000074, -0x00060006, 0x000002CB, 0x00000009, 0x64616853, 0x6146776F, 0x00006564, 0x00060006, 0x000002CB, -0x0000000A, 0x63736143, 0x46656461, 0x00656461, 0x00060006, 0x000002CB, 0x0000000B, 0x6867694C, -0x756F4374, 0x0000746E, 0x00060006, 0x000002CB, 0x0000000C, 0x64616853, 0x6F43776F, 0x00746E75, -0x00050006, 0x000002CB, 0x0000000D, 0x65646F4D, 0x00000000, 0x00060006, 0x000002CB, 0x0000000E, -0x4D766E45, 0x6F437069, 0x00746E75, 0x00060006, 0x000002CB, 0x0000000F, 0x74696E49, 0x426C6169, -0x00736169, 0x00050006, 0x000002CB, 0x00000010, 0x74646957, 0x00000068, 0x00050006, 0x000002CB, -0x00000011, 0x67696548, 0x00007468, 0x00070006, 0x000002CB, 0x00000012, 0x64616873, 0x6E45776F, -0x656C6261, 0x00000064, 0x00030005, 0x000002CD, 0x006F6275, 0x00040005, 0x000002D1, 0x73616962, -0x00000000, 0x00040005, 0x000002DD, 0x73616962, 0x00000000, 0x00040005, 0x000002DE, 0x61726170, -0x0000006D, 0x00040005, 0x000002E0, 0x61726170, 0x0000006D, 0x00040005, 0x000002E2, 0x61726170, -0x0000006D, 0x00030005, 0x000002E5, 0x006D7573, 0x00040005, 0x000002E6, 0x73696F6E, 0x00000065, -0x00040005, 0x000002E7, 0x61726170, 0x0000006D, 0x00030005, 0x000002EB, 0x00000069, 0x00040005, -0x000002F3, 0x7366666F, 0x00007465, 0x00040005, 0x000002F4, 0x61726170, 0x0000006D, 0x00040005, -0x000002F6, 0x61726170, 0x0000006D, 0x00040005, 0x000002F7, 0x61726170, 0x0000006D, 0x00030005, -0x000002FD, 0x0000007A, 0x00060005, 0x0000031A, 0x63736163, 0x49656461, 0x7865646E, 0x00000000, -0x00040005, 0x0000031B, 0x77656976, 0x00736F50, 0x00030005, 0x00000325, 0x00000069, 0x00050005, -0x00000341, 0x64616873, 0x6F43776F, 0x0064726F, 0x00040005, 0x00000353, 0x5241454E, 0x00000000, -0x00050005, 0x00000355, 0x61527675, 0x73756964, 0x00000000, 0x00040005, 0x00000360, 0x77656976, -0x00736F50, 0x00060005, 0x00000369, 0x64616873, 0x6D41776F, 0x746E756F, 0x00000000, 0x00050005, -0x0000036A, 0x61685375, 0x4D776F64, 0x00007061, 0x00040005, 0x0000036B, 0x61726170, 0x0000006D, -0x00040005, 0x0000036D, 0x61726170, 0x0000006D, 0x00040005, 0x0000036F, 0x61726170, 0x0000006D, -0x00040005, 0x00000371, 0x61726170, 0x0000006D, 0x00040005, 0x00000373, 0x61726170, 0x0000006D, -0x00040005, 0x00000375, 0x61726170, 0x0000006D, 0x00050005, 0x00000378, 0x63736163, 0x46656461, -0x00656461, 0x00050005, 0x00000385, 0x63736163, 0x4E656461, 0x00747865, 0x00060005, 0x0000039F, -0x64616873, 0x6D41776F, 0x746E756F, 0x00000031, 0x00040005, 0x000003A0, 0x61726170, 0x0000006D, -0x00040005, 0x000003A2, 0x61726170, 0x0000006D, 0x00040005, 0x000003A4, 0x61726170, 0x0000006D, -0x00040005, 0x000003A6, 0x61726170, 0x0000006D, 0x00040005, 0x000003A8, 0x61726170, 0x0000006D, -0x00040005, 0x000003AA, 0x61726170, 0x0000006D, 0x00030005, 0x000003B8, 0x00000044, 0x00040005, -0x000003BA, 0x61726170, 0x0000006D, 0x00040005, 0x000003BC, 0x61726170, 0x0000006D, 0x00030005, -0x000003BF, 0x00000056, 0x00040005, 0x000003C0, 0x61726170, 0x0000006D, 0x00040005, 0x000003C2, -0x61726170, 0x0000006D, 0x00040005, 0x000003C4, 0x61726170, 0x0000006D, 0x00030005, 0x000003C7, -0x00000046, 0x00040005, 0x000003C9, 0x61726170, 0x0000006D, 0x00040005, 0x000003D5, 0x61726170, -0x0000006D, 0x00040005, 0x000003D7, 0x61726170, 0x0000006D, 0x00040005, 0x000003D9, 0x61726170, -0x0000006D, 0x00040005, 0x000003DB, 0x61726170, 0x0000006D, 0x00040005, 0x000003E1, 0x61726170, -0x0000006D, 0x00040005, 0x000003E3, 0x61726170, 0x0000006D, 0x00040005, 0x000003E5, 0x61726170, -0x0000006D, 0x00040005, 0x000003E7, 0x61726170, 0x0000006D, 0x00040005, 0x000003EC, 0x75736572, -0x0000746C, 0x00030005, 0x000003EE, 0x00000069, 0x00040005, 0x000003FA, 0x6867696C, 0x00000074, -0x00040005, 0x0000040D, 0x756C6176, 0x00000065, 0x00030005, 0x00000413, 0x0000004C, 0x00040005, -0x00000419, 0x74736964, 0x00000000, 0x00040005, 0x0000041E, 0x65747461, 0x0000006E, 0x00050005, -0x00000425, 0x65747461, 0x7461756E, 0x006E6F69, 0x00030005, 0x0000043E, 0x0000004C, 0x00050005, -0x00000444, 0x6F747563, 0x6E416666, 0x00656C67, 0x00040005, 0x00000448, 0x74736964, 0x00000000, -0x00040005, 0x0000044D, 0x74656874, 0x00000061, 0x00040005, 0x00000453, 0x69737065, 0x006E6F6C, -0x00050005, 0x00000459, 0x65747461, 0x7461756E, 0x006E6F69, 0x00060005, 0x0000046A, 0x63736163, -0x49656461, 0x7865646E, 0x00000000, 0x00040005, 0x0000046B, 0x61726170, 0x0000006D, 0x00040005, -0x00000474, 0x61726170, 0x0000006D, 0x00040005, 0x00000476, 0x61726170, 0x0000006D, 0x00040005, -0x00000478, 0x61726170, 0x0000006D, 0x00040005, 0x0000047C, 0x61726170, 0x0000006D, 0x00030005, -0x00000481, 0x0000694C, 0x00050005, 0x00000485, 0x6461724C, 0x636E6169, 0x00000065, 0x00030005, -0x0000048C, 0x0000684C, 0x00050005, 0x00000492, 0x6867696C, 0x4C6F4E74, 0x00000000, 0x00040005, -0x00000497, 0x61726170, 0x0000006D, 0x00030005, 0x00000499, 0x00000068, 0x00050005, 0x0000049F, -0x64616873, 0x5F676E69, 0x00566F4E, 0x00040005, 0x000004A5, 0x61726170, 0x0000006D, 0x00030005, -0x000004A7, 0x00566F4E, 0x00030005, 0x000004A9, 0x004C6F4E, 0x00040005, 0x000004AA, 0x61726170, -0x0000006D, 0x00030005, 0x000004AD, 0x00486F4E, 0x00040005, 0x000004B2, 0x61726170, 0x0000006D, -0x00030005, 0x000004B4, 0x00486F4C, 0x00040005, 0x000004B8, 0x61726170, 0x0000006D, 0x00030005, -0x000004BA, 0x00006446, 0x00040005, 0x000004BC, 0x61726170, 0x0000006D, 0x00040005, 0x000004BE, -0x61726170, 0x0000006D, 0x00040005, 0x000004C0, 0x61726170, 0x0000006D, 0x00030005, 0x000004C3, -0x00007246, 0x00040005, 0x000004C7, 0x61726170, 0x0000006D, 0x00040005, 0x000004C9, 0x61726170, -0x0000006D, 0x00040005, 0x000004CB, 0x61726170, 0x0000006D, 0x00040005, 0x000004CD, 0x61726170, -0x0000006D, 0x00040005, 0x000004D0, 0x6F6C6F63, 0x00007275, 0x00040005, 0x000004DA, 0x61726170, -0x0000006D, 0x00040005, 0x000004DC, 0x61726170, 0x0000006D, 0x00050005, 0x000004E9, 0x61727269, -0x6E616964, 0x00006563, 0x00040005, 0x000004ED, 0x72724975, 0x0070614D, 0x00030005, 0x000004F3, -0x00000046, 0x00040005, 0x000004F4, 0x61726170, 0x0000006D, 0x00040005, 0x000004F6, 0x61726170, -0x0000006D, 0x00040005, 0x000004F9, 0x61726170, 0x0000006D, 0x00030005, 0x000004FD, 0x0000646B, -0x00050005, 0x00000505, 0x66666964, 0x49657375, 0x00004C42, 0x00080005, 0x0000050B, 0x6E455F75, -0x64615276, 0x636E6169, 0x78655465, 0x6576654C, 0x0000736C, 0x00070005, 0x0000050F, 0x63657073, -0x72616C75, 0x61727249, 0x6E616964, 0x00006563, 0x00040005, 0x00000510, 0x766E4575, 0x0070614D, -0x00050005, 0x0000051A, 0x63657073, 0x72616C75, 0x004C4249, 0x00050005, 0x0000052D, 0x43786574, -0x756F6C6F, 0x00000072, 0x00050005, 0x00000537, 0x6174656D, 0x63696C6C, 0x00000000, 0x00050005, -0x00000538, 0x67756F72, 0x73656E68, 0x00000073, 0x00030005, 0x00000547, 0x00786574, 0x00030005, -0x0000056B, 0x00786574, 0x00050005, 0x00000589, 0x6574616D, 0x6C616972, 0x00000000, 0x00040005, -0x00000597, 0x61726170, 0x0000006D, 0x00030005, 0x0000059D, 0x00007675, 0x00060005, 0x0000059F, -0x465F6C67, 0x43676172, 0x64726F6F, 0x00000000, 0x00040005, 0x000005AA, 0x6F617373, 0x00000000, -0x00050005, 0x000005AB, 0x41535375, 0x70614D4F, 0x00000000, 0x00040005, 0x000005BA, 0x61726170, -0x0000006D, 0x00050005, 0x000005BF, 0x67756F72, 0x73656E68, 0x00003273, 0x00040005, 0x000005C3, -0x75646E64, 0x00000000, 0x00040005, 0x000005C7, 0x76646E64, 0x00000000, 0x00050005, 0x000005CB, -0x69726176, 0x65636E61, 0x00000000, 0x00070005, 0x000005D3, 0x6E72656B, 0x6F526C65, 0x6E686775, -0x32737365, 0x00000000, 0x00070005, 0x000005D8, 0x746C6966, 0x64657265, 0x67756F52, 0x73656E68, -0x00003273, 0x00040005, 0x000005DC, 0x61726170, 0x0000006D, 0x00040005, 0x000005E1, 0x6F507377, -0x00000073, 0x00050005, 0x000005F3, 0x44524275, 0x54554C46, 0x00000000, 0x00050005, 0x000005FD, -0x6C666572, 0x61746365, 0x0065636E, 0x00040005, 0x000005FE, 0x61726170, 0x0000006D, 0x00030005, -0x00000602, 0x00003046, 0x00040005, 0x00000605, 0x61726170, 0x0000006D, 0x00040005, 0x00000608, -0x61726170, 0x0000006D, 0x00040005, 0x0000061B, 0x61726170, 0x0000006D, 0x00060005, 0x00000625, -0x64616873, 0x6944776F, 0x6E617473, 0x00006563, 0x00070005, 0x00000628, 0x6E617274, 0x69746973, -0x69446E6F, 0x6E617473, 0x00006563, 0x00040005, 0x0000062B, 0x77656976, 0x00736F50, 0x00050005, -0x00000634, 0x74736964, 0x65636E61, 0x00000000, 0x00030005, 0x00000642, 0x0000724C, 0x00070005, -0x0000064C, 0x6867696C, 0x6E6F4374, 0x62697274, 0x6F697475, 0x0000006E, 0x00040005, 0x0000064D, -0x61726170, 0x0000006D, 0x00040005, 0x00000650, 0x61726170, 0x0000006D, 0x00040005, 0x00000652, -0x61726170, 0x0000006D, 0x00060005, 0x00000655, 0x436C6269, 0x72746E6F, 0x74756269, 0x006E6F69, -0x00040005, 0x00000656, 0x61726170, 0x0000006D, 0x00040005, 0x00000659, 0x61726170, 0x0000006D, -0x00040005, 0x0000065B, 0x61726170, 0x0000006D, 0x00050005, 0x0000065E, 0x616E6966, 0x6C6F436C, -0x0072756F, 0x00050005, 0x00000666, 0x4374756F, 0x726F6C6F, 0x00000000, 0x00060005, 0x000006A5, -0x63736163, 0x49656461, 0x7865646E, 0x00000000, 0x00040005, 0x000006A6, 0x61726170, 0x0000006D, -0x00050048, 0x000001DD, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x000001DD, 0x00000001, -0x00000023, 0x00000010, 0x00050048, 0x000001DD, 0x00000002, 0x00000023, 0x00000014, 0x00050048, -0x000001DD, 0x00000003, 0x00000023, 0x00000018, 0x00050048, 0x000001DD, 0x00000004, 0x00000023, -0x0000001C, 0x00050048, 0x000001DD, 0x00000005, 0x00000023, 0x00000020, 0x00050048, 0x000001DD, -0x00000006, 0x00000023, 0x00000024, 0x00050048, 0x000001DD, 0x00000007, 0x00000023, 0x00000028, -0x00050048, 0x000001DD, 0x00000008, 0x00000023, 0x0000002C, 0x00050048, 0x000001DD, 0x00000009, -0x00000023, 0x00000030, 0x00050048, 0x000001DD, 0x0000000A, 0x00000023, 0x00000034, 0x00050048, -0x000001DD, 0x0000000B, 0x00000023, 0x00000038, 0x00050048, 0x000001DD, 0x0000000C, 0x00000023, -0x0000003C, 0x00030047, 0x000001DD, 0x00000002, 0x00040047, 0x000001DF, 0x00000022, 0x00000001, -0x00040047, 0x000001DF, 0x00000021, 0x00000006, 0x00040047, 0x000001F9, 0x00000022, 0x00000001, -0x00040047, 0x000001F9, 0x00000021, 0x00000000, 0x00040047, 0x000001FE, 0x0000001E, 0x00000000, -0x00040047, 0x0000021D, 0x00000022, 0x00000001, 0x00040047, 0x0000021D, 0x00000021, 0x00000001, -0x00040047, 0x00000239, 0x00000022, 0x00000001, 0x00040047, 0x00000239, 0x00000021, 0x00000002, -0x00040047, 0x00000250, 0x00000022, 0x00000001, 0x00040047, 0x00000250, 0x00000021, 0x00000004, -0x00040047, 0x0000026C, 0x00000022, 0x00000001, 0x00040047, 0x0000026C, 0x00000021, 0x00000005, -0x00040047, 0x00000285, 0x00000022, 0x00000001, 0x00040047, 0x00000285, 0x00000021, 0x00000003, -0x00050048, 0x000002C4, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x000002C4, 0x00000001, -0x00000023, 0x00000010, 0x00050048, 0x000002C4, 0x00000002, 0x00000023, 0x00000020, 0x00050048, -0x000002C4, 0x00000003, 0x00000023, 0x00000030, 0x00050048, 0x000002C4, 0x00000004, 0x00000023, -0x00000034, 0x00050048, 0x000002C4, 0x00000005, 0x00000023, 0x00000038, 0x00050048, 0x000002C4, -0x00000006, 0x00000023, 0x0000003C, 0x00040047, 0x000002C6, 0x00000006, 0x00000040, 0x00040047, -0x000002C9, 0x00000006, 0x00000040, 0x00040047, 0x000002CA, 0x00000006, 0x00000010, 0x00050048, -0x000002CB, 0x00000000, 0x00000023, 0x00000000, 0x00040048, 0x000002CB, 0x00000001, 0x00000005, -0x00050048, 0x000002CB, 0x00000001, 0x00000023, 0x00000800, 0x00050048, 0x000002CB, 0x00000001, -0x00000007, 0x00000010, 0x00040048, 0x000002CB, 0x00000002, 0x00000005, 0x00050048, 0x000002CB, -0x00000002, 0x00000023, 0x00000900, 0x00050048, 0x000002CB, 0x00000002, 0x00000007, 0x00000010, -0x00040048, 0x000002CB, 0x00000003, 0x00000005, 0x00050048, 0x000002CB, 0x00000003, 0x00000023, -0x00000940, 0x00050048, 0x000002CB, 0x00000003, 0x00000007, 0x00000010, 0x00040048, 0x000002CB, -0x00000004, 0x00000005, 0x00050048, 0x000002CB, 0x00000004, 0x00000023, 0x00000980, 0x00050048, -0x000002CB, 0x00000004, 0x00000007, 0x00000010, 0x00050048, 0x000002CB, 0x00000005, 0x00000023, -0x000009C0, 0x00050048, 0x000002CB, 0x00000006, 0x00000023, 0x000009D0, 0x00050048, 0x000002CB, -0x00000007, 0x00000023, 0x00000A10, 0x00050048, 0x000002CB, 0x00000008, 0x00000023, 0x00000A14, -0x00050048, 0x000002CB, 0x00000009, 0x00000023, 0x00000A18, 0x00050048, 0x000002CB, 0x0000000A, -0x00000023, 0x00000A1C, 0x00050048, 0x000002CB, 0x0000000B, 0x00000023, 0x00000A20, 0x00050048, -0x000002CB, 0x0000000C, 0x00000023, 0x00000A24, 0x00050048, 0x000002CB, 0x0000000D, 0x00000023, -0x00000A28, 0x00050048, 0x000002CB, 0x0000000E, 0x00000023, 0x00000A2C, 0x00050048, 0x000002CB, -0x0000000F, 0x00000023, 0x00000A30, 0x00050048, 0x000002CB, 0x00000010, 0x00000023, 0x00000A34, -0x00050048, 0x000002CB, 0x00000011, 0x00000023, 0x00000A38, 0x00050048, 0x000002CB, 0x00000012, -0x00000023, 0x00000A3C, 0x00030047, 0x000002CB, 0x00000002, 0x00040047, 0x000002CD, 0x00000022, -0x00000002, 0x00040047, 0x000002CD, 0x00000021, 0x00000005, 0x00040047, 0x0000036A, 0x00000022, -0x00000002, 0x00040047, 0x0000036A, 0x00000021, 0x00000003, 0x00040047, 0x000004ED, 0x00000022, -0x00000002, 0x00040047, 0x000004ED, 0x00000021, 0x00000002, 0x00040047, 0x00000510, 0x00000022, -0x00000002, 0x00040047, 0x00000510, 0x00000021, 0x00000001, 0x00040047, 0x0000059F, 0x0000000B, -0x0000000F, 0x00040047, 0x000005AB, 0x00000022, 0x00000002, 0x00040047, 0x000005AB, 0x00000021, -0x00000004, 0x00040047, 0x000005F3, 0x00000022, 0x00000002, 0x00040047, 0x000005F3, 0x00000021, -0x00000000, 0x00040047, 0x00000666, 0x0000001E, 0x00000000, 0x00020013, 0x00000002, 0x00030021, -0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040020, 0x00000007, 0x00000007, -0x00000006, 0x00040021, 0x00000008, 0x00000006, 0x00000007, 0x00040017, 0x0000000C, 0x00000006, -0x00000003, 0x00040020, 0x0000000D, 0x00000007, 0x0000000C, 0x00040021, 0x0000000E, 0x0000000C, -0x0000000D, 0x00040017, 0x00000012, 0x00000006, 0x00000004, 0x00040020, 0x00000013, 0x00000007, -0x00000012, 0x00040021, 0x00000014, 0x00000012, 0x00000013, 0x00070021, 0x0000001B, 0x00000006, -0x00000007, 0x00000007, 0x0000000C, 0x0000000C, 0x00060021, 0x00000022, 0x0000000C, 0x0000000C, -0x00000007, 0x00000007, 0x00060021, 0x00000028, 0x00000006, 0x00000007, 0x00000007, 0x00000007, -0x00070021, 0x0000002E, 0x00000006, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00050021, -0x0000003A, 0x00000006, 0x00000007, 0x00000007, 0x00050021, 0x00000048, 0x0000000C, 0x00000012, -0x00000007, 0x00060021, 0x0000004D, 0x0000000C, 0x00000012, 0x00000007, 0x00000007, 0x00050021, -0x00000064, 0x0000000C, 0x0000000C, 0x00000007, 0x00060021, 0x00000069, 0x0000000C, 0x0000000D, -0x00000007, 0x00000007, 0x00030021, 0x0000006F, 0x00000012, 0x00030021, 0x00000072, 0x0000000C, -0x00030021, 0x00000075, 0x00000006, 0x00040017, 0x0000007F, 0x00000006, 0x00000002, 0x00040020, -0x00000080, 0x00000007, 0x0000007F, 0x00040021, 0x00000081, 0x00000006, 0x00000080, 0x00040015, -0x00000085, 0x00000020, 0x00000001, 0x00040020, 0x00000086, 0x00000007, 0x00000085, 0x00060021, -0x00000087, 0x0000007F, 0x00000086, 0x00000086, 0x00000007, 0x00060021, 0x0000008D, 0x00000006, -0x0000000D, 0x0000000D, 0x00000086, 0x00090019, 0x00000093, 0x00000006, 0x00000001, 0x00000000, -0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x0003001B, 0x00000094, 0x00000093, 0x00040020, -0x00000095, 0x00000000, 0x00000094, 0x000A0021, 0x00000096, 0x00000006, 0x00000095, 0x00000013, -0x00000007, 0x0000000D, 0x0000000D, 0x0000000D, 0x00000086, 0x00040021, 0x000000A0, 0x00000085, -0x0000000D, 0x00070021, 0x000000A4, 0x00000006, 0x0000000D, 0x00000086, 0x0000000D, 0x0000000D, -0x000F001E, 0x000000AB, 0x00000012, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x0000000C, -0x0000000C, 0x00000006, 0x0000000C, 0x00000006, 0x0000000C, 0x0000000C, 0x0000007F, 0x0009001E, -0x000000AC, 0x00000012, 0x00000012, 0x00000012, 0x00000006, 0x00000006, 0x00000006, 0x00000006, -0x000A0021, 0x000000AD, 0x0000000C, 0x000000AB, 0x000000AC, 0x0000000C, 0x00000007, 0x00000007, -0x00000007, 0x00000007, 0x00070021, 0x000000B7, 0x0000000C, 0x000000AB, 0x00000007, 0x00000007, -0x00000007, 0x00040020, 0x000000C7, 0x00000007, 0x000000AB, 0x00060021, 0x000000C8, 0x0000000C, -0x0000000D, 0x0000000D, 0x000000C7, 0x00040020, 0x000000D3, 0x00000006, 0x00000006, 0x0004003B, -0x000000D3, 0x000000D4, 0x00000006, 0x0004002B, 0x00000006, 0x000000D5, 0x3F800000, 0x0004003B, -0x000000D3, 0x000000D6, 0x00000006, 0x0004002B, 0x00000006, 0x000000D7, 0x3FCF1BBD, 0x0004002B, -0x00000006, 0x000000E4, 0x400CCCCD, 0x0006002C, 0x0000000C, 0x000000E5, 0x000000E4, 0x000000E4, -0x000000E4, 0x00040015, 0x000000ED, 0x00000020, 0x00000000, 0x0004002B, 0x000000ED, 0x000000EE, -0x00000003, 0x0004002B, 0x00000006, 0x000000F8, 0x00000000, 0x0004002B, 0x00000006, 0x00000110, -0x3EA2F983, 0x0004002B, 0x00000006, 0x00000113, 0x477FE000, 0x0004002B, 0x00000006, 0x00000128, -0x40A00000, 0x0004002B, 0x00000006, 0x0000012F, 0x3F000000, 0x0004002B, 0x00000006, 0x00000130, -0x40000000, 0x0004002B, 0x00000006, 0x00000174, 0x3F7FF972, 0x0004002B, 0x00000006, 0x0000018F, -0x38D1B717, 0x0004002B, 0x00000006, 0x000001A4, 0x3E23D70A, 0x0004002B, 0x00000006, 0x000001C1, -0x41840000, 0x0006002C, 0x0000000C, 0x000001C2, 0x000001C1, 0x000001C1, 0x000001C1, 0x000F001E, -0x000001DD, 0x00000012, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, -0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00040020, 0x000001DE, -0x00000002, 0x000001DD, 0x0004003B, 0x000001DE, 0x000001DF, 0x00000002, 0x0004002B, 0x00000085, -0x000001E0, 0x00000005, 0x00040020, 0x000001E1, 0x00000002, 0x00000006, 0x0004002B, 0x00000006, -0x000001E4, 0x3D4CCCCD, 0x00020014, 0x000001E5, 0x0004002B, 0x00000085, 0x000001E9, 0x00000000, -0x00040020, 0x000001EA, 0x00000002, 0x00000012, 0x00090019, 0x000001F6, 0x00000006, 0x00000001, -0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x0003001B, 0x000001F7, 0x000001F6, -0x00040020, 0x000001F8, 0x00000000, 0x000001F7, 0x0004003B, 0x000001F8, 0x000001F9, 0x00000000, -0x00040018, 0x000001FB, 0x0000000C, 0x00000003, 0x0007001E, 0x000001FC, 0x0000000C, 0x0000007F, -0x00000012, 0x0000000C, 0x000001FB, 0x00040020, 0x000001FD, 0x00000001, 0x000001FC, 0x0004003B, -0x000001FD, 0x000001FE, 0x00000001, 0x0004002B, 0x00000085, 0x000001FF, 0x00000001, 0x00040020, -0x00000200, 0x00000001, 0x0000007F, 0x0004002B, 0x00000085, 0x0000020A, 0x00000006, 0x0004002B, -0x00000085, 0x00000210, 0x00000002, 0x0004003B, 0x000001F8, 0x0000021D, 0x00000000, 0x0004002B, -0x00000085, 0x00000228, 0x00000007, 0x0004003B, 0x000001F8, 0x00000239, 0x00000000, 0x0004002B, -0x000000ED, 0x0000023E, 0x00000000, 0x0004002B, 0x00000085, 0x00000244, 0x0000000A, 0x0004003B, -0x000001F8, 0x00000250, 0x00000000, 0x0004002B, 0x00000085, 0x0000025A, 0x00000009, 0x0004002B, -0x00000085, 0x00000260, 0x00000004, 0x0004003B, 0x000001F8, 0x0000026C, 0x00000000, 0x0004002B, -0x00000085, 0x00000278, 0x00000008, 0x0004002B, 0x00000085, 0x0000027E, 0x00000003, 0x00040020, -0x0000027F, 0x00000001, 0x0000000C, 0x0004003B, 0x000001F8, 0x00000285, 0x00000000, 0x00040020, -0x0000028F, 0x00000001, 0x000001FB, 0x0004002B, 0x00000006, 0x00000298, 0x414FD639, 0x0004002B, -0x00000006, 0x00000299, 0x429C774C, 0x0005002C, 0x0000007F, 0x0000029A, 0x00000298, 0x00000299, -0x0004002B, 0x00000006, 0x0000029D, 0x472AEE8C, 0x0004002B, 0x00000006, 0x000002A3, 0x4019999A, -0x0009001E, 0x000002C4, 0x00000012, 0x00000012, 0x00000012, 0x00000006, 0x00000006, 0x00000006, -0x00000006, 0x0004002B, 0x000000ED, 0x000002C5, 0x00000020, 0x0004001C, 0x000002C6, 0x000002C4, -0x000002C5, 0x00040018, 0x000002C7, 0x00000012, 0x00000004, 0x0004002B, 0x000000ED, 0x000002C8, -0x00000004, 0x0004001C, 0x000002C9, 0x000002C7, 0x000002C8, 0x0004001C, 0x000002CA, 0x00000012, -0x000002C8, 0x0015001E, 0x000002CB, 0x000002C6, 0x000002C9, 0x000002C7, 0x000002C7, 0x000002C7, -0x00000012, 0x000002CA, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000085, 0x00000085, -0x00000085, 0x00000085, 0x00000006, 0x00000006, 0x00000006, 0x00000085, 0x00040020, 0x000002CC, -0x00000002, 0x000002CB, 0x0004003B, 0x000002CC, 0x000002CD, 0x00000002, 0x0004002B, 0x00000085, -0x000002CE, 0x0000000F, 0x0004002B, 0x00000006, 0x000002FA, 0x442F0000, 0x0004002B, 0x000000ED, -0x0000030A, 0x00000002, 0x0004002B, 0x00000006, 0x00000316, 0x41000000, 0x00040020, 0x0000031C, -0x00000002, 0x000002C7, 0x0004002B, 0x00000085, 0x0000032C, 0x0000000C, 0x00040020, 0x0000032D, -0x00000002, 0x00000085, 0x0004002B, 0x00000006, 0x00000354, 0x3C23D70A, 0x0004002B, 0x00000006, -0x0000035E, 0x3B03126F, 0x0004003B, 0x00000095, 0x0000036A, 0x00000000, 0x0006002C, 0x0000000C, -0x000003ED, 0x000000F8, 0x000000F8, 0x000000F8, 0x0004002B, 0x00000085, 0x000003F5, 0x0000000B, -0x00040020, 0x000003F9, 0x00000007, 0x000000AC, 0x00040020, 0x000003FC, 0x00000002, 0x000002C4, -0x0004002B, 0x00000006, 0x00000456, 0x3F666666, 0x0004002B, 0x00000085, 0x0000046E, 0x00000012, -0x00090019, 0x000004EA, 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000001, -0x00000000, 0x0003001B, 0x000004EB, 0x000004EA, 0x00040020, 0x000004EC, 0x00000000, 0x000004EB, -0x0004003B, 0x000004EC, 0x000004ED, 0x00000000, 0x0004002B, 0x00000085, 0x0000050C, 0x0000000E, -0x0004003B, 0x000004EC, 0x00000510, 0x00000000, 0x0004002B, 0x000000ED, 0x00000520, 0x00000001, -0x00040020, 0x0000059E, 0x00000001, 0x00000012, 0x0004003B, 0x0000059E, 0x0000059F, 0x00000001, -0x0004002B, 0x00000085, 0x000005A2, 0x00000010, 0x0004002B, 0x00000085, 0x000005A5, 0x00000011, -0x0004003B, 0x000001F8, 0x000005AB, 0x00000000, 0x0004002B, 0x00000006, 0x000005B7, 0x3D3851EC, -0x0004002B, 0x00000006, 0x000005D6, 0x3CA3D70A, 0x0004003B, 0x000001F8, 0x000005F3, 0x00000000, -0x0004002B, 0x00000006, 0x0000060F, 0x3DCCCCCD, 0x00040020, 0x00000665, 0x00000003, 0x00000012, -0x0004003B, 0x00000665, 0x00000666, 0x00000003, 0x0004002B, 0x00000085, 0x0000066C, 0x0000000D, -0x0004002B, 0x00000006, 0x000006B0, 0x3F4CCCCD, 0x0004002B, 0x00000006, 0x000006B1, 0x3E4CCCCD, -0x0007002C, 0x00000012, 0x000006B2, 0x000006B0, 0x000006B1, 0x000006B1, 0x000000D5, 0x0007002C, -0x00000012, 0x000006B6, 0x000006B1, 0x000006B0, 0x000006B1, 0x000000D5, 0x0007002C, 0x00000012, -0x000006BA, 0x000006B1, 0x000006B1, 0x000006B0, 0x000000D5, 0x0007002C, 0x00000012, 0x000006BE, -0x000006B0, 0x000006B0, 0x000006B1, 0x000000D5, 0x0004002B, 0x00000006, 0x000006C4, 0x40C90FDB, -0x0004002B, 0x00000006, 0x000006C5, 0x3727C5AC, 0x0004002B, 0x00000006, 0x000006C6, 0x3D23D70A, -0x0006002C, 0x0000000C, 0x000006C7, 0x000006C6, 0x000006C6, 0x000006C6, 0x0007002C, 0x00000012, -0x000006C8, 0x0000012F, 0x000000F8, 0x000000F8, 0x0000012F, 0x0007002C, 0x00000012, 0x000006C9, -0x000000F8, 0x0000012F, 0x000000F8, 0x0000012F, 0x0007002C, 0x00000012, 0x000006CA, 0x000000F8, -0x000000F8, 0x000000D5, 0x000000F8, 0x0007002C, 0x00000012, 0x000006CB, 0x000000F8, 0x000000F8, -0x000000F8, 0x000000D5, 0x0007002C, 0x000002C7, 0x000006CC, 0x000006C8, 0x000006C9, 0x000006CA, -0x000006CB, 0x0004002B, 0x000000ED, 0x000006CD, 0x00000010, 0x0004001C, 0x000006CE, 0x0000007F, -0x000006CD, 0x0004002B, 0x00000006, 0x000006CF, 0xBF7127FA, 0x0004002B, 0x00000006, 0x000006D0, -0xBECC51E0, 0x0005002C, 0x0000007F, 0x000006D1, 0x000006CF, 0x000006D0, 0x0004002B, 0x00000006, -0x000006D2, 0x3F7211EE, 0x0004002B, 0x00000006, 0x000006D3, 0xBF44D71B, 0x0005002C, 0x0000007F, -0x000006D4, 0x000006D2, 0x000006D3, 0x0004002B, 0x00000006, 0x000006D5, 0xBDC0E398, 0x0004002B, -0x00000006, 0x000006D6, 0xBF6DEC6B, 0x0005002C, 0x0000007F, 0x000006D7, 0x000006D5, 0x000006D6, -0x0004002B, 0x00000006, 0x000006D8, 0x3EB09E84, 0x0004002B, 0x00000006, 0x000006D9, 0x3E967720, -0x0005002C, 0x0000007F, 0x000006DA, 0x000006D8, 0x000006D9, 0x0004002B, 0x00000006, 0x000006DB, -0xBF6A777E, 0x0004002B, 0x00000006, 0x000006DC, 0x3EEA5988, 0x0005002C, 0x0000007F, 0x000006DD, -0x000006DB, 0x000006DC, 0x0004002B, 0x00000006, 0x000006DE, 0xBF50C0D4, 0x0004002B, 0x00000006, -0x000006DF, 0xBF610E50, 0x0005002C, 0x0000007F, 0x000006E0, 0x000006DE, 0x000006DF, 0x0004002B, -0x00000006, 0x000006E1, 0xBEC3FB24, 0x0004002B, 0x00000006, 0x000006E2, 0x3E8DB498, 0x0005002C, -0x0000007F, 0x000006E3, 0x000006E1, 0x000006E2, 0x0004002B, 0x00000006, 0x000006E4, 0x3F798F60, -0x0004002B, 0x00000006, 0x000006E5, 0x3F41A8EC, 0x0005002C, 0x0000007F, 0x000006E6, 0x000006E4, -0x000006E5, 0x0004002B, 0x00000006, 0x000006E7, 0x3EE2EF78, 0x0004002B, 0x00000006, 0x000006E8, -0xBF79A12C, 0x0005002C, 0x0000007F, 0x000006E9, 0x000006E7, 0x000006E8, 0x0004002B, 0x00000006, -0x000006EA, 0x3F099500, 0x0004002B, 0x00000006, 0x000006EB, 0xBEF28D4A, 0x0005002C, 0x0000007F, -0x000006EC, 0x000006EA, 0x000006EB, 0x0004002B, 0x00000006, 0x000006ED, 0xBE87AA08, 0x0004002B, -0x00000006, 0x000006EE, 0xBED67E06, 0x0005002C, 0x0000007F, 0x000006EF, 0x000006ED, 0x000006EE, -0x0004002B, 0x00000006, 0x000006F0, 0x3F4ABEE2, 0x0004002B, 0x00000006, 0x000006F1, 0x3E437BC8, -0x0005002C, 0x0000007F, 0x000006F2, 0x000006F0, 0x000006F1, 0x0004002B, 0x00000006, 0x000006F3, -0xBE77B198, 0x0004002B, 0x00000006, 0x000006F4, 0x3F7F3FA8, 0x0005002C, 0x0000007F, 0x000006F5, -0x000006F3, 0x000006F4, 0x0004002B, 0x00000006, 0x000006F6, 0xBF5068D4, 0x0004002B, 0x00000006, -0x000006F7, 0x3F6A148A, 0x0005002C, 0x0000007F, 0x000006F8, 0x000006F6, 0x000006F7, 0x0004002B, -0x00000006, 0x000006F9, 0x3E4CA330, 0x0004002B, 0x00000006, 0x000006FA, 0x3F495268, 0x0005002C, -0x0000007F, 0x000006FB, 0x000006F9, 0x000006FA, 0x0004002B, 0x00000006, 0x000006FC, 0x3E134898, -0x0004002B, 0x00000006, 0x000006FD, 0xBE106460, 0x0005002C, 0x0000007F, 0x000006FE, 0x000006FC, -0x000006FD, 0x0013002C, 0x000006CE, 0x000006FF, 0x000006D1, 0x000006D4, 0x000006D7, 0x000006DA, -0x000006DD, 0x000006E0, 0x000006E3, 0x000006E6, 0x000006E9, 0x000006EC, 0x000006EF, 0x000006F2, -0x000006F5, 0x000006F8, 0x000006FB, 0x000006FE, 0x0004002B, 0x000000ED, 0x00000700, 0x00000040, -0x0004001C, 0x00000701, 0x0000007F, 0x00000700, 0x0004002B, 0x00000006, 0x00000702, 0xBF625322, -0x0004002B, 0x00000006, 0x00000703, 0x3DFEF391, 0x0005002C, 0x0000007F, 0x00000704, 0x00000702, -0x00000703, 0x0004002B, 0x00000006, 0x00000705, 0xBF36E169, 0x0004002B, 0x00000006, 0x00000706, -0x3CE4E26D, 0x0005002C, 0x0000007F, 0x00000707, 0x00000705, 0x00000706, 0x0004002B, 0x00000006, -0x00000708, 0xBF3F7953, 0x0004002B, 0x00000006, 0x00000709, 0x3E696463, 0x0005002C, 0x0000007F, -0x0000070A, 0x00000708, 0x00000709, 0x0004002B, 0x00000006, 0x0000070B, 0xBF708A37, 0x0004002B, -0x00000006, 0x0000070C, 0x3E797B31, 0x0005002C, 0x0000007F, 0x0000070D, 0x0000070B, 0x0000070C, -0x0004002B, 0x00000006, 0x0000070E, 0xBF7C476F, 0x0004002B, 0x00000006, 0x0000070F, 0x3D3A81DC, -0x0005002C, 0x0000007F, 0x00000710, 0x0000070E, 0x0000070F, 0x0004002B, 0x00000006, 0x00000711, -0xBF5C828C, 0x0004002B, 0x00000006, 0x00000712, 0xBE0B7DC8, 0x0005002C, 0x0000007F, 0x00000713, -0x00000711, 0x00000712, 0x0004002B, 0x00000006, 0x00000714, 0xBF61C66D, 0x0004002B, 0x00000006, -0x00000715, 0x3ECB3786, 0x0005002C, 0x0000007F, 0x00000716, 0x00000714, 0x00000715, 0x0004002B, -0x00000006, 0x00000717, 0xBEEF127F, 0x0004002B, 0x00000006, 0x00000718, 0x3C6DFE76, 0x0005002C, -0x0000007F, 0x00000719, 0x00000717, 0x00000718, 0x0004002B, 0x00000006, 0x0000071A, 0xBF0EE6A7, -0x0004002B, 0x00000006, 0x0000071B, 0x3E59C411, 0x0005002C, 0x0000007F, 0x0000071C, 0x0000071A, -0x0000071B, 0x0004002B, 0x00000006, 0x0000071D, 0xBF14151A, 0x0004002B, 0x00000006, 0x0000071E, -0xBDC43E53, 0x0005002C, 0x0000007F, 0x0000071F, 0x0000071D, 0x0000071E, 0x0004002B, 0x00000006, -0x00000720, 0xBF3D8213, 0x0004002B, 0x00000006, 0x00000721, 0xBDC3DA30, 0x0005002C, 0x0000007F, -0x00000722, 0x00000720, 0x00000721, 0x0004002B, 0x00000006, 0x00000723, 0xBF406E2B, 0x0004002B, -0x00000006, 0x00000724, 0x3EF1F927, 0x0005002C, 0x0000007F, 0x00000725, 0x00000723, 0x00000724, -0x0004002B, 0x00000006, 0x00000726, 0xBF0D9B0B, 0x0004002B, 0x00000006, 0x00000727, 0xBE790364, -0x0005002C, 0x0000007F, 0x00000728, 0x00000726, 0x00000727, 0x0004002B, 0x00000006, 0x00000729, -0xBF2CBD34, 0x0004002B, 0x00000006, 0x0000072A, 0xBEA95571, 0x0005002C, 0x0000007F, 0x0000072B, -0x00000729, 0x0000072A, 0x0004002B, 0x00000006, 0x0000072C, 0xBECE3737, 0x0004002B, 0x00000006, -0x0000072D, 0xBDFA08C0, 0x0005002C, 0x0000007F, 0x0000072E, 0x0000072C, 0x0000072D, 0x0004002B, -0x00000006, 0x0000072F, 0xBEA3B9AE, 0x0004002B, 0x00000006, 0x00000730, 0xBE9FD439, 0x0005002C, -0x0000007F, 0x00000731, 0x0000072F, 0x00000730, 0x0004002B, 0x00000006, 0x00000732, 0xBED3EDB7, -0x0004002B, 0x00000006, 0x00000733, 0xBEE127D4, 0x0005002C, 0x0000007F, 0x00000734, 0x00000732, -0x00000733, 0x0004002B, 0x00000006, 0x00000735, 0xBF7AA9C5, 0x0004002B, 0x00000006, 0x00000736, -0xBE4E132B, 0x0005002C, 0x0000007F, 0x00000737, 0x00000735, 0x00000736, 0x0004002B, 0x00000006, -0x00000738, 0xBF5D9696, 0x0004002B, 0x00000006, 0x00000739, 0xBE93CFD5, 0x0005002C, 0x0000007F, -0x0000073A, 0x00000738, 0x00000739, 0x0004002B, 0x00000006, 0x0000073B, 0xBE798D8B, 0x0004002B, -0x00000006, 0x0000073C, 0xBE3ED9E0, 0x0005002C, 0x0000007F, 0x0000073D, 0x0000073B, 0x0000073C, -0x0004002B, 0x00000006, 0x0000073E, 0xBE96FFC1, 0x0004002B, 0x00000006, 0x0000073F, 0xBD645804, -0x0005002C, 0x0000007F, 0x00000740, 0x0000073E, 0x0000073F, 0x0004002B, 0x00000006, 0x00000741, -0xBF1ABD5E, 0x0004002B, 0x00000006, 0x00000742, 0xBF0B5409, 0x0005002C, 0x0000007F, 0x00000743, -0x00000741, 0x00000742, 0x0004002B, 0x00000006, 0x00000744, 0xBED60B70, 0x0004002B, 0x00000006, -0x00000745, 0xBF167222, 0x0005002C, 0x0000007F, 0x00000746, 0x00000744, 0x00000745, 0x0004002B, -0x00000006, 0x00000747, 0xBF0C957D, 0x0004002B, 0x00000006, 0x00000748, 0xBED4EDD5, 0x0005002C, -0x0000007F, 0x00000749, 0x00000747, 0x00000748, 0x0004002B, 0x00000006, 0x0000074A, 0xBE73CB3E, -0x0004002B, 0x00000006, 0x0000074B, 0xBF1C9C5E, 0x0005002C, 0x0000007F, 0x0000074C, 0x0000074A, -0x0000074B, 0x0004002B, 0x00000006, 0x0000074D, 0xBE88B4C0, 0x0004002B, 0x00000006, 0x0000074E, -0xBEEB5E0F, 0x0005002C, 0x0000007F, 0x0000074F, 0x0000074D, 0x0000074E, 0x0004002B, 0x00000006, -0x00000750, 0xBDCCCFF2, 0x0004002B, 0x00000006, 0x00000751, 0xBE6A9D62, 0x0005002C, 0x0000007F, -0x00000752, 0x00000750, 0x00000751, 0x0004002B, 0x00000006, 0x00000753, 0xBDD0BFA1, 0x0004002B, -0x00000006, 0x00000754, 0xBEC2C16E, 0x0005002C, 0x0000007F, 0x00000755, 0x00000753, 0x00000754, -0x0004002B, 0x00000006, 0x00000756, 0xBF2E749F, 0x0004002B, 0x00000006, 0x00000757, 0xBF3365DC, -0x0005002C, 0x0000007F, 0x00000758, 0x00000756, 0x00000757, 0x0004002B, 0x00000006, 0x00000759, -0xBF4373F3, 0x0004002B, 0x00000006, 0x0000075A, 0xBF0B1B58, 0x0005002C, 0x0000007F, 0x0000075B, -0x00000759, 0x0000075A, 0x0004002B, 0x00000006, 0x0000075C, 0xBF0C8D3B, 0x0004002B, 0x00000006, -0x0000075D, 0xBF403116, 0x0005002C, 0x0000007F, 0x0000075E, 0x0000075C, 0x0000075D, 0x0004002B, -0x00000006, 0x0000075F, 0xBF4F1D93, 0x0004002B, 0x00000006, 0x00000760, 0xBED1461B, 0x0005002C, -0x0000007F, 0x00000761, 0x0000075F, 0x00000760, 0x0004002B, 0x00000006, 0x00000762, 0xBEC6B980, -0x0004002B, 0x00000006, 0x00000763, 0xBF4600B0, 0x0005002C, 0x0000007F, 0x00000764, 0x00000762, -0x00000763, 0x0004002B, 0x00000006, 0x00000765, 0xBEDBD945, 0x0004002B, 0x00000006, 0x00000766, -0xBF6517A4, 0x0005002C, 0x0000007F, 0x00000767, 0x00000765, 0x00000766, 0x0004002B, 0x00000006, -0x00000768, 0xBE06C15D, 0x0004002B, 0x00000006, 0x00000769, 0x3D853D21, 0x0005002C, 0x0000007F, -0x0000076A, 0x00000768, 0x00000769, 0x0004002B, 0x00000006, 0x0000076B, 0xBE8CCD10, 0x0004002B, -0x00000006, 0x0000076C, 0x3DD2C8C5, 0x0005002C, 0x0000007F, 0x0000076D, 0x0000076B, 0x0000076C, -0x0004002B, 0x00000006, 0x0000076E, 0xBDD953DF, 0x0004002B, 0x00000006, 0x0000076F, 0xBD8BEF07, -0x0005002C, 0x0000007F, 0x00000770, 0x0000076E, 0x0000076F, 0x0004002B, 0x00000006, 0x00000771, -0xBE96D3FA, 0x0004002B, 0x00000006, 0x00000772, 0xBF643A54, 0x0005002C, 0x0000007F, 0x00000773, -0x00000771, 0x00000772, 0x0004002B, 0x00000006, 0x00000774, 0xBF21218A, 0x0004002B, 0x00000006, -0x00000775, 0x3EC23F03, 0x0005002C, 0x0000007F, 0x00000776, 0x00000774, 0x00000775, 0x0004002B, -0x00000006, 0x00000777, 0xBED083FD, 0x0004002B, 0x00000006, 0x00000778, 0x3EADF373, 0x0005002C, -0x0000007F, 0x00000779, 0x00000777, 0x00000778, 0x0004002B, 0x00000006, 0x0000077A, 0x3D92BD3C, -0x0004002B, 0x00000006, 0x0000077B, 0xBEC4C0DF, 0x0005002C, 0x0000007F, 0x0000077C, 0x0000077A, -0x0000077B, 0x0004002B, 0x00000006, 0x0000077D, 0x3CB45F18, 0x0004002B, 0x00000006, 0x0000077E, -0xBE870FE0, 0x0005002C, 0x0000007F, 0x0000077F, 0x0000077D, 0x0000077E, 0x0004002B, 0x00000006, -0x00000780, 0x3B7E36D2, 0x0004002B, 0x00000006, 0x00000781, 0xBE0B56B8, 0x0005002C, 0x0000007F, -0x00000782, 0x00000780, 0x00000781, 0x0004002B, 0x00000006, 0x00000783, 0xBE0CD573, 0x0004002B, -0x00000006, 0x00000784, 0xBF44916D, 0x0005002C, 0x0000007F, 0x00000785, 0x00000783, 0x00000784, -0x0004002B, 0x00000006, 0x00000786, 0xBD506141, 0x0004002B, 0x00000006, 0x00000787, 0xBF67F413, -0x0005002C, 0x0000007F, 0x00000788, 0x00000786, 0x00000787, 0x0004002B, 0x00000006, 0x00000789, -0x3DE9BE90, 0x0004002B, 0x00000006, 0x0000078A, 0xBD8F77F2, 0x0005002C, 0x0000007F, 0x0000078B, -0x00000789, 0x0000078A, 0x0004002B, 0x00000006, 0x0000078C, 0x3E273BC9, 0x0004002B, 0x00000006, -0x0000078D, 0xBE5E71CE, 0x0005002C, 0x0000007F, 0x0000078E, 0x0000078C, 0x0000078D, 0x0004002B, -0x00000006, 0x0000078F, 0xBDCD562A, 0x0004002B, 0x00000006, 0x00000790, 0xBF1686A5, 0x0005002C, -0x0000007F, 0x00000791, 0x0000078F, 0x00000790, 0x0004002B, 0x00000006, 0x00000792, 0xBBA1F080, -0x0004002B, 0x00000006, 0x00000793, 0x3E006078, 0x0005002C, 0x0000007F, 0x00000794, 0x00000792, -0x00000793, 0x0004002B, 0x00000006, 0x00000795, 0x3D1098D4, 0x0004002B, 0x00000006, 0x00000796, -0xBF1E8B1A, 0x0005002C, 0x0000007F, 0x00000797, 0x00000795, 0x00000796, 0x0004002B, 0x00000006, -0x00000798, 0x3E48576D, 0x0004002B, 0x00000006, 0x00000799, 0xBEEB04EE, 0x0005002C, 0x0000007F, -0x0000079A, 0x00000798, 0x00000799, 0x0004002B, 0x00000006, 0x0000079B, 0x3E9BA1D3, 0x0004002B, -0x00000006, 0x0000079C, 0xBEB1565C, 0x0005002C, 0x0000007F, 0x0000079D, 0x0000079B, 0x0000079C, -0x0004002B, 0x00000006, 0x0000079E, 0xBF2D9924, 0x0004002B, 0x00000006, 0x0000079F, 0x3F2F62A6, -0x0005002C, 0x0000007F, 0x000007A0, 0x0000079E, 0x0000079F, 0x0004002B, 0x00000006, 0x000007A1, -0xBF20E001, 0x0004002B, 0x00000006, 0x000007A2, 0x3F020AD9, 0x0005002C, 0x0000007F, 0x000007A3, -0x000007A1, 0x000007A2, 0x0004002B, 0x00000006, 0x000007A4, 0xBF022B49, 0x0004002B, 0x00000006, -0x000007A5, 0x3EEAE1AC, 0x0005002C, 0x0000007F, 0x000007A6, 0x000007A4, 0x000007A5, 0x0004002B, -0x00000006, 0x000007A7, 0x3D039EF1, 0x0004002B, 0x00000006, 0x000007A8, 0xBF48331E, 0x0005002C, -0x0000007F, 0x000007A9, 0x000007A7, 0x000007A8, 0x0004002B, 0x00000006, 0x000007AA, 0x3DFB1316, -0x0004002B, 0x00000006, 0x000007AB, 0x3E8F8A6E, 0x0005002C, 0x0000007F, 0x000007AC, 0x000007AA, -0x000007AB, 0x0004002B, 0x00000006, 0x000007AD, 0xBD32C301, 0x0004002B, 0x00000006, 0x000007AE, -0x3E9FCE10, 0x0005002C, 0x0000007F, 0x000007AF, 0x000007AD, 0x000007AE, 0x0004002B, 0x00000006, -0x000007B0, 0x3E082F51, 0x0004002B, 0x00000006, 0x000007B1, 0x3DAE6D9C, 0x0005002C, 0x0000007F, -0x000007B2, 0x000007B0, 0x000007B1, 0x0004002B, 0x00000006, 0x000007B3, 0xBE44B76F, 0x0004002B, -0x00000006, 0x000007B4, 0x3E925AAB, 0x0005002C, 0x0000007F, 0x000007B5, 0x000007B3, 0x000007B4, -0x0004002B, 0x00000006, 0x000007B6, 0x3E3C0725, 0x0004002B, 0x00000006, 0x000007B7, 0xBF369707, -0x0005002C, 0x0000007F, 0x000007B8, 0x000007B6, 0x000007B7, 0x0004002B, 0x00000006, 0x000007B9, -0x3E87CAEA, 0x0004002B, 0x00000006, 0x000007BA, 0xBF18C261, 0x0005002C, 0x0000007F, 0x000007BB, -0x000007B9, 0x000007BA, 0x0004002B, 0x00000006, 0x000007BC, 0xBC1DBEC2, 0x0004002B, 0x00000006, -0x000007BD, 0xBEF75361, 0x0005002C, 0x0000007F, 0x000007BE, 0x000007BC, 0x000007BD, 0x0004002B, -0x00000006, 0x000007BF, 0xBC97AEDE, 0x0004002B, 0x00000006, 0x000007C0, 0x3EDF1477, 0x0005002C, -0x0000007F, 0x000007C1, 0x000007BF, 0x000007C0, 0x0043002C, 0x00000701, 0x000007C2, 0x00000704, -0x00000707, 0x0000070A, 0x0000070D, 0x00000710, 0x00000713, 0x00000716, 0x00000719, 0x0000071C, -0x0000071F, 0x00000722, 0x00000725, 0x00000728, 0x0000072B, 0x0000072E, 0x00000731, 0x00000734, -0x00000737, 0x0000073A, 0x0000073D, 0x00000740, 0x00000743, 0x00000746, 0x00000749, 0x0000074C, -0x0000074F, 0x00000752, 0x00000755, 0x00000758, 0x0000075B, 0x0000075E, 0x00000761, 0x00000764, -0x00000767, 0x0000076A, 0x0000076D, 0x00000770, 0x00000773, 0x00000776, 0x00000779, 0x0000077C, -0x0000077F, 0x00000782, 0x00000785, 0x00000788, 0x0000078B, 0x0000078E, 0x00000791, 0x00000794, -0x00000797, 0x0000079A, 0x0000079D, 0x000007A0, 0x000007A3, 0x000007A6, 0x000007A9, 0x000007AC, -0x000007AF, 0x000007B2, 0x000007B5, 0x000007B8, 0x000007BB, 0x000007BE, 0x000007C1, 0x00050036, -0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200F8, 0x00000005, 0x0004003B, 0x00000013, -0x0000052D, 0x00000007, 0x0004003B, 0x00000007, 0x00000537, 0x00000007, 0x0004003B, 0x00000007, -0x00000538, 0x00000007, 0x0004003B, 0x0000000D, 0x00000547, 0x00000007, 0x0004003B, 0x0000000D, -0x0000056B, 0x00000007, 0x0004003B, 0x000000C7, 0x00000589, 0x00000007, 0x0004003B, 0x0000000D, -0x00000597, 0x00000007, 0x0004003B, 0x00000080, 0x0000059D, 0x00000007, 0x0004003B, 0x00000007, -0x000005AA, 0x00000007, 0x0004003B, 0x00000007, 0x000005BA, 0x00000007, 0x0004003B, 0x00000007, -0x000005BF, 0x00000007, 0x0004003B, 0x0000000D, 0x000005C3, 0x00000007, 0x0004003B, 0x0000000D, -0x000005C7, 0x00000007, 0x0004003B, 0x00000007, 0x000005CB, 0x00000007, 0x0004003B, 0x00000007, -0x000005D3, 0x00000007, 0x0004003B, 0x00000007, 0x000005D8, 0x00000007, 0x0004003B, 0x00000007, -0x000005DC, 0x00000007, 0x0004003B, 0x0000000D, 0x000005E1, 0x00000007, 0x0004003B, 0x00000007, -0x000005FD, 0x00000007, 0x0004003B, 0x00000007, 0x000005FE, 0x00000007, 0x0004003B, 0x0000000D, -0x00000602, 0x00000007, 0x0004003B, 0x00000007, 0x00000605, 0x00000007, 0x0004003B, 0x00000007, -0x00000608, 0x00000007, 0x0004003B, 0x00000007, 0x0000061B, 0x00000007, 0x0004003B, 0x00000007, -0x00000625, 0x00000007, 0x0004003B, 0x00000007, 0x00000628, 0x00000007, 0x0004003B, 0x00000013, -0x0000062B, 0x00000007, 0x0004003B, 0x00000007, 0x00000634, 0x00000007, 0x0004003B, 0x0000000D, -0x00000642, 0x00000007, 0x0004003B, 0x0000000D, 0x0000064C, 0x00000007, 0x0004003B, 0x0000000D, -0x0000064D, 0x00000007, 0x0004003B, 0x0000000D, 0x00000650, 0x00000007, 0x0004003B, 0x000000C7, -0x00000652, 0x00000007, 0x0004003B, 0x0000000D, 0x00000655, 0x00000007, 0x0004003B, 0x0000000D, -0x00000656, 0x00000007, 0x0004003B, 0x0000000D, 0x00000659, 0x00000007, 0x0004003B, 0x000000C7, -0x0000065B, 0x00000007, 0x0004003B, 0x0000000D, 0x0000065E, 0x00000007, 0x0004003B, 0x00000086, -0x000006A5, 0x00000007, 0x0004003B, 0x0000000D, 0x000006A6, 0x00000007, 0x0003003E, 0x000000D4, -0x000000D5, 0x0003003E, 0x000000D6, 0x000000D7, 0x00040039, 0x00000012, 0x0000052E, 0x00000070, -0x0003003E, 0x0000052D, 0x0000052E, 0x00050041, 0x00000007, 0x0000052F, 0x0000052D, 0x000000EE, -0x0004003D, 0x00000006, 0x00000530, 0x0000052F, 0x00050041, 0x000001E1, 0x00000531, 0x000001DF, -0x000003F5, 0x0004003D, 0x00000006, 0x00000532, 0x00000531, 0x000500B8, 0x000001E5, 0x00000533, -0x00000530, 0x00000532, 0x000300F7, 0x00000535, 0x00000000, 0x000400FA, 0x00000533, 0x00000534, -0x00000535, 0x000200F8, 0x00000534, 0x000100FC, 0x000200F8, 0x00000535, 0x0003003E, 0x00000537, -0x000000F8, 0x0003003E, 0x00000538, 0x000000F8, 0x00050041, 0x000001E1, 0x00000539, 0x000001DF, -0x0000032C, 0x0004003D, 0x00000006, 0x0000053A, 0x00000539, 0x000500B4, 0x000001E5, 0x0000053B, -0x0000053A, 0x000000F8, 0x000300F7, 0x0000053D, 0x00000000, 0x000400FA, 0x0000053B, 0x0000053C, -0x00000541, 0x000200F8, 0x0000053C, 0x00040039, 0x0000000C, 0x0000053E, 0x00000073, 0x00050051, -0x00000006, 0x0000053F, 0x0000053E, 0x00000000, 0x0003003E, 0x00000537, 0x0000053F, 0x00040039, -0x00000006, 0x00000540, 0x00000076, 0x0003003E, 0x00000538, 0x00000540, 0x000200F9, 0x0000053D, -0x000200F8, 0x00000541, 0x00050041, 0x000001E1, 0x00000542, 0x000001DF, 0x0000032C, 0x0004003D, -0x00000006, 0x00000543, 0x00000542, 0x000500B4, 0x000001E5, 0x00000544, 0x00000543, 0x000000D5, -0x000300F7, 0x00000546, 0x00000000, 0x000400FA, 0x00000544, 0x00000545, 0x00000565, 0x000200F8, -0x00000545, 0x0004003D, 0x000001F7, 0x00000548, 0x0000021D, 0x00050041, 0x00000200, 0x00000549, -0x000001FE, 0x000001FF, 0x0004003D, 0x0000007F, 0x0000054A, 0x00000549, 0x00050057, 0x00000012, -0x0000054B, 0x00000548, 0x0000054A, 0x0008004F, 0x0000000C, 0x0000054C, 0x0000054B, 0x0000054B, -0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000547, 0x0000054C, 0x00050041, 0x000001E1, -0x0000054D, 0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, 0x0000054E, 0x0000054D, 0x00050083, -0x00000006, 0x0000054F, 0x000000D5, 0x0000054E, 0x00050041, 0x000001E1, 0x00000550, 0x000001DF, -0x00000210, 0x0004003D, 0x00000006, 0x00000551, 0x00000550, 0x00050085, 0x00000006, 0x00000552, -0x0000054F, 0x00000551, 0x00050041, 0x000001E1, 0x00000553, 0x000001DF, 0x0000020A, 0x0004003D, -0x00000006, 0x00000554, 0x00000553, 0x00050041, 0x00000007, 0x00000555, 0x00000547, 0x0000030A, +0x00000000, 0x00040005, 0x0000007A, 0x65626C61, 0x00006F64, 0x00050005, 0x00000081, 0x73696F4E, +0x66762865, 0x00003B32, 0x00030005, 0x00000080, 0x00006F63, 0x00090005, 0x00000089, 0x65676F56, +0x7369446C, 0x6D61536B, 0x28656C70, 0x693B3169, 0x31663B31, 0x0000003B, 0x00050005, 0x00000086, +0x706D6173, 0x6E49656C, 0x00786564, 0x00060005, 0x00000087, 0x706D6173, 0x4373656C, 0x746E756F, +0x00000000, 0x00030005, 0x00000088, 0x00696870, 0x00090005, 0x0000008F, 0x53746547, 0x6F646168, +0x61694277, 0x66762873, 0x66763B33, 0x31693B33, 0x0000003B, 0x00060005, 0x0000008C, 0x6867696C, +0x72694474, 0x69746365, 0x00006E6F, 0x00040005, 0x0000008D, 0x6D726F6E, 0x00006C61, 0x00050005, +0x0000008E, 0x64616873, 0x6E49776F, 0x00786564, 0x00100005, 0x0000009C, 0x53464350, 0x6F646168, +0x72694477, 0x69746365, 0x6C616E6F, 0x6867694C, 0x41732874, 0x763B3132, 0x663B3466, 0x66763B31, +0x66763B33, 0x66763B33, 0x31693B33, 0x0000003B, 0x00050005, 0x00000095, 0x64616873, 0x614D776F, +0x00000070, 0x00060005, 0x00000096, 0x64616873, 0x6F43776F, 0x7364726F, 0x00000000, 0x00050005, +0x00000097, 0x61527675, 0x73756964, 0x00000000, 0x00060005, 0x00000098, 0x6867696C, 0x72694474, +0x69746365, 0x00006E6F, 0x00040005, 0x00000099, 0x6D726F6E, 0x00006C61, 0x00040005, 0x0000009A, +0x6F507377, 0x00000073, 0x00060005, 0x0000009B, 0x63736163, 0x49656461, 0x7865646E, 0x00000000, +0x00090005, 0x000000A0, 0x636C6143, 0x74616C75, 0x73614365, 0x65646163, 0x65646E49, 0x66762878, +0x00003B33, 0x00040005, 0x0000009F, 0x6F507377, 0x00000073, 0x000A0005, 0x000000A7, 0x636C6143, +0x74616C75, 0x61685365, 0x28776F64, 0x3B336676, 0x763B3169, 0x763B3366, 0x003B3366, 0x00040005, +0x000000A3, 0x6F507377, 0x00000073, 0x00060005, 0x000000A4, 0x63736163, 0x49656461, 0x7865646E, +0x00000000, 0x00060005, 0x000000A5, 0x6867696C, 0x72694474, 0x69746365, 0x00006E6F, 0x00040005, +0x000000A6, 0x6D726F6E, 0x00006C61, 0x00050005, 0x000000A9, 0x6574614D, 0x6C616972, 0x00000000, +0x00050006, 0x000000A9, 0x00000000, 0x65626C41, 0x00006F64, 0x00060006, 0x000000A9, 0x00000001, +0x6174654D, 0x63696C6C, 0x00000000, 0x00060006, 0x000000A9, 0x00000002, 0x67756F52, 0x73656E68, +0x00000073, 0x00080006, 0x000000A9, 0x00000003, 0x63726550, 0x75747065, 0x6F526C61, 0x6E686775, +0x00737365, 0x00060006, 0x000000A9, 0x00000004, 0x6C666552, 0x61746365, 0x0065636E, 0x00060006, +0x000000A9, 0x00000005, 0x73696D45, 0x65766973, 0x00000000, 0x00050006, 0x000000A9, 0x00000006, +0x6D726F4E, 0x00006C61, 0x00040006, 0x000000A9, 0x00000007, 0x00004F41, 0x00050006, 0x000000A9, +0x00000008, 0x77656956, 0x00000000, 0x00050006, 0x000000A9, 0x00000009, 0x746F444E, 0x00000056, +0x00040006, 0x000000A9, 0x0000000A, 0x00003046, 0x00080006, 0x000000A9, 0x0000000B, 0x72656E45, +0x6F437967, 0x6E65706D, 0x69746173, 0x00006E6F, 0x00040006, 0x000000A9, 0x0000000C, 0x00676664, +0x00040005, 0x000000AA, 0x6867694C, 0x00000074, 0x00050006, 0x000000AA, 0x00000000, 0x6F6C6F63, +0x00007275, 0x00060006, 0x000000AA, 0x00000001, 0x69736F70, 0x6E6F6974, 0x00000000, 0x00060006, +0x000000AA, 0x00000002, 0x65726964, 0x6F697463, 0x0000006E, 0x00060006, 0x000000AA, 0x00000003, +0x65746E69, 0x7469736E, 0x00000079, 0x00050006, 0x000000AA, 0x00000004, 0x69646172, 0x00007375, +0x00050006, 0x000000AA, 0x00000005, 0x65707974, 0x00000000, 0x00050006, 0x000000AA, 0x00000006, +0x6C676E61, 0x00000065, 0x00230005, 0x000000B3, 0x746F7349, 0x69706F72, 0x626F4C63, 0x74732865, +0x74637572, 0x74614D2D, 0x61697265, 0x66762D6C, 0x31662D34, 0x2D31662D, 0x662D3166, 0x66762D31, +0x66762D33, 0x31662D33, 0x3366762D, 0x2D31662D, 0x2D336676, 0x2D336676, 0x31326676, 0x7274733B, +0x2D746375, 0x6867694C, 0x66762D74, 0x66762D34, 0x66762D34, 0x31662D34, 0x2D31662D, 0x662D3166, +0x763B3131, 0x663B3366, 0x31663B31, 0x3B31663B, 0x003B3166, 0x00050005, 0x000000AC, 0x6574616D, +0x6C616972, 0x00000000, 0x00040005, 0x000000AD, 0x6867696C, 0x00000074, 0x00030005, 0x000000AE, +0x00000068, 0x00030005, 0x000000AF, 0x00566F4E, 0x00030005, 0x000000B0, 0x004C6F4E, 0x00030005, +0x000000B1, 0x00486F4E, 0x00030005, 0x000000B2, 0x00486F4C, 0x00180005, 0x000000BA, 0x66666944, +0x4C657375, 0x2865626F, 0x75727473, 0x4D2D7463, 0x72657461, 0x2D6C6169, 0x2D346676, 0x662D3166, +0x31662D31, 0x2D31662D, 0x2D336676, 0x2D336676, 0x762D3166, 0x662D3366, 0x66762D31, 0x66762D33, +0x66762D33, 0x663B3132, 0x31663B31, 0x3B31663B, 0x00000000, 0x00050005, 0x000000B6, 0x6574616D, +0x6C616972, 0x00000000, 0x00030005, 0x000000B7, 0x00566F4E, 0x00030005, 0x000000B8, 0x004C6F4E, +0x00030005, 0x000000B9, 0x00486F4C, 0x00230005, 0x000000C3, 0x63657053, 0x72616C75, 0x65626F4C, +0x72747328, 0x2D746375, 0x6574614D, 0x6C616972, 0x3466762D, 0x2D31662D, 0x662D3166, 0x31662D31, +0x3366762D, 0x3366762D, 0x2D31662D, 0x2D336676, 0x762D3166, 0x762D3366, 0x762D3366, 0x3B313266, +0x75727473, 0x4C2D7463, 0x74686769, 0x3466762D, 0x3466762D, 0x3466762D, 0x2D31662D, 0x662D3166, +0x31662D31, 0x66763B31, 0x31663B33, 0x3B31663B, 0x663B3166, 0x00003B31, 0x00050005, 0x000000BC, +0x6574616D, 0x6C616972, 0x00000000, 0x00040005, 0x000000BD, 0x6867696C, 0x00000074, 0x00030005, +0x000000BE, 0x00000068, 0x00030005, 0x000000BF, 0x00566F4E, 0x00030005, 0x000000C0, 0x004C6F4E, +0x00030005, 0x000000C1, 0x00486F4E, 0x00030005, 0x000000C2, 0x00486F4C, 0x00170005, 0x000000CA, +0x6867694C, 0x676E6974, 0x33667628, 0x3366763B, 0x7274733B, 0x2D746375, 0x6574614D, 0x6C616972, +0x3466762D, 0x2D31662D, 0x662D3166, 0x31662D31, 0x3366762D, 0x3366762D, 0x2D31662D, 0x2D336676, +0x762D3166, 0x762D3366, 0x762D3366, 0x3B313266, 0x00000000, 0x00030005, 0x000000C7, 0x00003046, +0x00040005, 0x000000C8, 0x6F507377, 0x00000073, 0x00050005, 0x000000C9, 0x6574616D, 0x6C616972, +0x00000000, 0x00150005, 0x000000CF, 0x284C4249, 0x3B336676, 0x3B336676, 0x75727473, 0x4D2D7463, +0x72657461, 0x2D6C6169, 0x2D346676, 0x662D3166, 0x31662D31, 0x2D31662D, 0x2D336676, 0x2D336676, +0x762D3166, 0x662D3366, 0x66762D31, 0x66762D33, 0x66762D33, 0x003B3132, 0x00030005, 0x000000CC, +0x00003046, 0x00030005, 0x000000CD, 0x0000724C, 0x00050005, 0x000000CE, 0x6574616D, 0x6C616972, +0x00000000, 0x00050005, 0x000000D2, 0x64616853, 0x6146776F, 0x00006564, 0x00030005, 0x000000D4, +0x00494850, 0x00030005, 0x000000D6, 0x00003278, 0x00040005, 0x000000E7, 0x61726170, 0x0000006D, +0x00030005, 0x000000FA, 0x0048784E, 0x00030005, 0x000000FC, 0x00000061, 0x00030005, 0x00000100, +0x0000006B, 0x00030005, 0x0000010A, 0x00000064, 0x00040005, 0x0000011A, 0x61726170, 0x0000006D, +0x00030005, 0x0000012C, 0x00303966, 0x00060005, 0x00000136, 0x6867696C, 0x61635374, 0x72657474, +0x00000000, 0x00040005, 0x00000137, 0x61726170, 0x0000006D, 0x00040005, 0x00000138, 0x61726170, +0x0000006D, 0x00040005, 0x0000013A, 0x61726170, 0x0000006D, 0x00050005, 0x0000013D, 0x77656976, +0x74616353, 0x00726574, 0x00040005, 0x0000013E, 0x61726170, 0x0000006D, 0x00040005, 0x0000013F, +0x61726170, 0x0000006D, 0x00040005, 0x00000141, 0x61726170, 0x0000006D, 0x00030005, 0x0000014A, +0x00003261, 0x00040005, 0x0000014E, 0x4C584747, 0x00000000, 0x00040005, 0x0000015C, 0x56584747, +0x00000000, 0x00050005, 0x00000170, 0x72657061, 0x65727574, 0x00000000, 0x00050005, 0x00000176, +0x7263696D, 0x6168536F, 0x00776F64, 0x00040005, 0x0000017A, 0x61726170, 0x0000006D, 0x00040005, +0x00000181, 0x61726170, 0x0000006D, 0x00040005, 0x00000183, 0x61726170, 0x0000006D, 0x00040005, +0x00000185, 0x61726170, 0x0000006D, 0x00040005, 0x00000187, 0x61726170, 0x0000006D, 0x00040005, +0x000001AE, 0x61726170, 0x0000006D, 0x00040005, 0x000001B0, 0x61726170, 0x0000006D, 0x00040005, +0x000001B5, 0x61726170, 0x0000006D, 0x00040005, 0x000001B7, 0x61726170, 0x0000006D, 0x00040005, +0x000001B9, 0x61726170, 0x0000006D, 0x00030005, 0x000001BE, 0x00303966, 0x00040005, 0x000001C2, +0x61726170, 0x0000006D, 0x00040005, 0x000001C4, 0x61726170, 0x0000006D, 0x00040005, 0x000001C6, +0x61726170, 0x0000006D, 0x00070005, 0x000001DB, 0x66696E55, 0x4D6D726F, 0x72657461, 0x446C6169, +0x00617461, 0x00070006, 0x000001DB, 0x00000000, 0x65626C41, 0x6F436F64, 0x72756F6C, 0x00000000, +0x00060006, 0x000001DB, 0x00000001, 0x67756F52, 0x73656E68, 0x00000073, 0x00060006, 0x000001DB, +0x00000002, 0x6174654D, 0x63696C6C, 0x00000000, 0x00060006, 0x000001DB, 0x00000003, 0x6C666552, +0x61746365, 0x0065636E, 0x00060006, 0x000001DB, 0x00000004, 0x73696D45, 0x65766973, 0x00000000, +0x00070006, 0x000001DB, 0x00000005, 0x65626C41, 0x614D6F64, 0x63614670, 0x00726F74, 0x00080006, +0x000001DB, 0x00000006, 0x6174654D, 0x63696C6C, 0x4670614D, 0x6F746361, 0x00000072, 0x00080006, +0x000001DB, 0x00000007, 0x67756F52, 0x73656E68, 0x70614D73, 0x74636146, 0x0000726F, 0x00070006, +0x000001DB, 0x00000008, 0x6D726F4E, 0x614D6C61, 0x63614670, 0x00726F74, 0x00080006, 0x000001DB, +0x00000009, 0x73696D45, 0x65766973, 0x4670614D, 0x6F746361, 0x00000072, 0x00060006, 0x000001DB, +0x0000000A, 0x614D4F41, 0x63614670, 0x00726F74, 0x00060006, 0x000001DB, 0x0000000B, 0x68706C41, +0x74754361, 0x0066664F, 0x00060006, 0x000001DB, 0x0000000C, 0x6B726F77, 0x776F6C66, 0x00000000, +0x00070005, 0x000001DD, 0x6574616D, 0x6C616972, 0x706F7250, 0x69747265, 0x00007365, 0x00050005, +0x000001F7, 0x6C415F75, 0x6F646562, 0x0070614D, 0x00050005, 0x000001FA, 0x74726556, 0x61447865, +0x00006174, 0x00050006, 0x000001FA, 0x00000000, 0x6F6C6F43, 0x00007275, 0x00060006, 0x000001FA, +0x00000001, 0x43786554, 0x64726F6F, 0x00000000, 0x00060006, 0x000001FA, 0x00000002, 0x69736F50, +0x6E6F6974, 0x00000000, 0x00050006, 0x000001FA, 0x00000003, 0x6D726F4E, 0x00006C61, 0x00060006, +0x000001FA, 0x00000004, 0x6C726F57, 0x726F4E64, 0x006C616D, 0x00060005, 0x000001FC, 0x74726556, +0x754F7865, 0x74757074, 0x00000000, 0x00040005, 0x00000202, 0x61726170, 0x0000006D, 0x00060005, +0x0000021B, 0x654D5F75, 0x6C6C6174, 0x614D6369, 0x00000070, 0x00060005, 0x00000237, 0x6F525F75, +0x6E686775, 0x4D737365, 0x00007061, 0x00040005, 0x0000024E, 0x4F415F75, 0x0070614D, 0x00060005, +0x0000026A, 0x6D455F75, 0x69737369, 0x614D6576, 0x00000070, 0x00040005, 0x0000026F, 0x61726170, +0x0000006D, 0x00050005, 0x00000281, 0x646C6F47, 0x6E416E65, 0x00656C67, 0x00030005, 0x00000283, +0x00000072, 0x00040005, 0x0000028C, 0x74656874, 0x00000061, 0x00040005, 0x00000293, 0x656E6973, +0x00000000, 0x00040005, 0x00000296, 0x69736F63, 0x0000656E, 0x00040005, 0x000002A2, 0x426E696D, +0x00736169, 0x00040005, 0x000002A3, 0x6867694C, 0x00000074, 0x00050006, 0x000002A3, 0x00000000, +0x6F6C6F63, 0x00007275, 0x00060006, 0x000002A3, 0x00000001, 0x69736F70, 0x6E6F6974, 0x00000000, +0x00060006, 0x000002A3, 0x00000002, 0x65726964, 0x6F697463, 0x0000006E, 0x00060006, 0x000002A3, +0x00000003, 0x65746E69, 0x7469736E, 0x00000079, 0x00050006, 0x000002A3, 0x00000004, 0x69646172, +0x00007375, 0x00050006, 0x000002A3, 0x00000005, 0x65707974, 0x00000000, 0x00050006, 0x000002A3, +0x00000006, 0x6C676E61, 0x00000065, 0x00050005, 0x000002AA, 0x4C4F4255, 0x74686769, 0x00000000, +0x00050006, 0x000002AA, 0x00000000, 0x6867696C, 0x00007374, 0x00070006, 0x000002AA, 0x00000001, +0x64616853, 0x7254776F, 0x66736E61, 0x006D726F, 0x00060006, 0x000002AA, 0x00000002, 0x77656956, +0x7274614D, 0x00007869, 0x00060006, 0x000002AA, 0x00000003, 0x6867694C, 0x65695674, 0x00000077, +0x00060006, 0x000002AA, 0x00000004, 0x73616942, 0x7274614D, 0x00007869, 0x00070006, 0x000002AA, +0x00000005, 0x656D6163, 0x6F506172, 0x69746973, 0x00006E6F, 0x00060006, 0x000002AA, 0x00000006, +0x696C7053, 0x70654474, 0x00736874, 0x00060006, 0x000002AA, 0x00000007, 0x6867694C, 0x7A695374, +0x00000065, 0x00070006, 0x000002AA, 0x00000008, 0x5378614D, 0x6F646168, 0x73694477, 0x00000074, +0x00060006, 0x000002AA, 0x00000009, 0x64616853, 0x6146776F, 0x00006564, 0x00060006, 0x000002AA, +0x0000000A, 0x63736143, 0x46656461, 0x00656461, 0x00060006, 0x000002AA, 0x0000000B, 0x6867694C, +0x756F4374, 0x0000746E, 0x00060006, 0x000002AA, 0x0000000C, 0x64616853, 0x6F43776F, 0x00746E75, +0x00050006, 0x000002AA, 0x0000000D, 0x65646F4D, 0x00000000, 0x00060006, 0x000002AA, 0x0000000E, +0x4D766E45, 0x6F437069, 0x00746E75, 0x00060006, 0x000002AA, 0x0000000F, 0x74696E49, 0x426C6169, +0x00736169, 0x00050006, 0x000002AA, 0x00000010, 0x74646957, 0x00000068, 0x00050006, 0x000002AA, +0x00000011, 0x67696548, 0x00007468, 0x00070006, 0x000002AA, 0x00000012, 0x64616873, 0x6E45776F, +0x656C6261, 0x00000064, 0x00030005, 0x000002AC, 0x006F6275, 0x00040005, 0x000002B0, 0x73616962, +0x00000000, 0x00040005, 0x000002BC, 0x73616962, 0x00000000, 0x00040005, 0x000002BD, 0x61726170, +0x0000006D, 0x00040005, 0x000002BF, 0x61726170, 0x0000006D, 0x00040005, 0x000002C1, 0x61726170, +0x0000006D, 0x00030005, 0x000002C4, 0x006D7573, 0x00040005, 0x000002C5, 0x73696F6E, 0x00000065, +0x00040005, 0x000002C6, 0x61726170, 0x0000006D, 0x00030005, 0x000002CA, 0x00000069, 0x00040005, +0x000002D3, 0x7366666F, 0x00007465, 0x00040005, 0x000002D4, 0x61726170, 0x0000006D, 0x00040005, +0x000002D6, 0x61726170, 0x0000006D, 0x00040005, 0x000002D7, 0x61726170, 0x0000006D, 0x00030005, +0x000002DD, 0x0000007A, 0x00060005, 0x000002FA, 0x63736163, 0x49656461, 0x7865646E, 0x00000000, +0x00040005, 0x000002FB, 0x77656976, 0x00736F50, 0x00030005, 0x00000305, 0x00000069, 0x00050005, +0x00000321, 0x64616873, 0x6F43776F, 0x0064726F, 0x00040005, 0x00000333, 0x5241454E, 0x00000000, +0x00050005, 0x00000335, 0x61527675, 0x73756964, 0x00000000, 0x00040005, 0x00000340, 0x77656976, +0x00736F50, 0x00060005, 0x00000349, 0x64616873, 0x6D41776F, 0x746E756F, 0x00000000, 0x00050005, +0x0000034A, 0x61685375, 0x4D776F64, 0x00007061, 0x00040005, 0x0000034B, 0x61726170, 0x0000006D, +0x00040005, 0x0000034D, 0x61726170, 0x0000006D, 0x00040005, 0x0000034F, 0x61726170, 0x0000006D, +0x00040005, 0x00000351, 0x61726170, 0x0000006D, 0x00040005, 0x00000353, 0x61726170, 0x0000006D, +0x00040005, 0x00000355, 0x61726170, 0x0000006D, 0x00050005, 0x00000358, 0x63736163, 0x46656461, +0x00656461, 0x00050005, 0x00000365, 0x63736163, 0x4E656461, 0x00747865, 0x00060005, 0x0000037F, +0x64616873, 0x6D41776F, 0x746E756F, 0x00000031, 0x00040005, 0x00000380, 0x61726170, 0x0000006D, +0x00040005, 0x00000382, 0x61726170, 0x0000006D, 0x00040005, 0x00000384, 0x61726170, 0x0000006D, +0x00040005, 0x00000386, 0x61726170, 0x0000006D, 0x00040005, 0x00000388, 0x61726170, 0x0000006D, +0x00040005, 0x0000038A, 0x61726170, 0x0000006D, 0x00030005, 0x00000398, 0x00000044, 0x00040005, +0x0000039A, 0x61726170, 0x0000006D, 0x00040005, 0x0000039C, 0x61726170, 0x0000006D, 0x00030005, +0x0000039F, 0x00000056, 0x00040005, 0x000003A0, 0x61726170, 0x0000006D, 0x00040005, 0x000003A2, +0x61726170, 0x0000006D, 0x00040005, 0x000003A4, 0x61726170, 0x0000006D, 0x00030005, 0x000003A7, +0x00000046, 0x00040005, 0x000003A9, 0x61726170, 0x0000006D, 0x00040005, 0x000003B5, 0x61726170, +0x0000006D, 0x00040005, 0x000003B7, 0x61726170, 0x0000006D, 0x00040005, 0x000003B9, 0x61726170, +0x0000006D, 0x00040005, 0x000003BB, 0x61726170, 0x0000006D, 0x00040005, 0x000003C1, 0x61726170, +0x0000006D, 0x00040005, 0x000003C3, 0x61726170, 0x0000006D, 0x00040005, 0x000003C5, 0x61726170, +0x0000006D, 0x00040005, 0x000003C7, 0x61726170, 0x0000006D, 0x00040005, 0x000003CC, 0x75736572, +0x0000746C, 0x00030005, 0x000003CE, 0x00000069, 0x00040005, 0x000003DA, 0x6867696C, 0x00000074, +0x00040005, 0x000003EE, 0x756C6176, 0x00000065, 0x00030005, 0x000003F4, 0x0000004C, 0x00040005, +0x000003FA, 0x74736964, 0x00000000, 0x00040005, 0x000003FF, 0x65747461, 0x0000006E, 0x00050005, +0x00000406, 0x65747461, 0x7461756E, 0x006E6F69, 0x00030005, 0x0000041F, 0x0000004C, 0x00050005, +0x00000425, 0x6F747563, 0x6E416666, 0x00656C67, 0x00040005, 0x00000429, 0x74736964, 0x00000000, +0x00040005, 0x0000042E, 0x74656874, 0x00000061, 0x00040005, 0x00000434, 0x69737065, 0x006E6F6C, +0x00050005, 0x0000043A, 0x65747461, 0x7461756E, 0x006E6F69, 0x00060005, 0x0000044B, 0x63736163, +0x49656461, 0x7865646E, 0x00000000, 0x00040005, 0x0000044C, 0x61726170, 0x0000006D, 0x00040005, +0x00000455, 0x61726170, 0x0000006D, 0x00040005, 0x00000457, 0x61726170, 0x0000006D, 0x00040005, +0x00000459, 0x61726170, 0x0000006D, 0x00040005, 0x0000045D, 0x61726170, 0x0000006D, 0x00030005, +0x00000462, 0x0000694C, 0x00050005, 0x00000466, 0x6461724C, 0x636E6169, 0x00000065, 0x00030005, +0x0000046D, 0x0000684C, 0x00050005, 0x00000473, 0x6867696C, 0x4C6F4E74, 0x00000000, 0x00040005, +0x00000478, 0x61726170, 0x0000006D, 0x00030005, 0x0000047A, 0x00000068, 0x00050005, 0x00000480, +0x64616873, 0x5F676E69, 0x00566F4E, 0x00040005, 0x00000486, 0x61726170, 0x0000006D, 0x00030005, +0x00000488, 0x00566F4E, 0x00030005, 0x0000048A, 0x004C6F4E, 0x00040005, 0x0000048B, 0x61726170, +0x0000006D, 0x00030005, 0x0000048E, 0x00486F4E, 0x00040005, 0x00000493, 0x61726170, 0x0000006D, +0x00030005, 0x00000495, 0x00486F4C, 0x00040005, 0x00000499, 0x61726170, 0x0000006D, 0x00030005, +0x0000049B, 0x00006446, 0x00040005, 0x0000049D, 0x61726170, 0x0000006D, 0x00040005, 0x0000049F, +0x61726170, 0x0000006D, 0x00040005, 0x000004A1, 0x61726170, 0x0000006D, 0x00030005, 0x000004A4, +0x00007246, 0x00040005, 0x000004A8, 0x61726170, 0x0000006D, 0x00040005, 0x000004AA, 0x61726170, +0x0000006D, 0x00040005, 0x000004AC, 0x61726170, 0x0000006D, 0x00040005, 0x000004AE, 0x61726170, +0x0000006D, 0x00040005, 0x000004B1, 0x6F6C6F63, 0x00007275, 0x00040005, 0x000004BB, 0x61726170, +0x0000006D, 0x00040005, 0x000004BD, 0x61726170, 0x0000006D, 0x00050005, 0x000004CA, 0x61727269, +0x6E616964, 0x00006563, 0x00040005, 0x000004CE, 0x72724975, 0x0070614D, 0x00030005, 0x000004D4, +0x00000046, 0x00040005, 0x000004D5, 0x61726170, 0x0000006D, 0x00040005, 0x000004D7, 0x61726170, +0x0000006D, 0x00040005, 0x000004DA, 0x61726170, 0x0000006D, 0x00030005, 0x000004DE, 0x0000646B, +0x00050005, 0x000004E6, 0x66666964, 0x49657375, 0x00004C42, 0x00080005, 0x000004EC, 0x6E455F75, +0x64615276, 0x636E6169, 0x78655465, 0x6576654C, 0x0000736C, 0x00070005, 0x000004F0, 0x63657073, +0x72616C75, 0x61727249, 0x6E616964, 0x00006563, 0x00040005, 0x000004F1, 0x766E4575, 0x0070614D, +0x00050005, 0x000004FB, 0x63657073, 0x72616C75, 0x004C4249, 0x00050005, 0x0000050E, 0x43786574, +0x756F6C6F, 0x00000072, 0x00050005, 0x00000518, 0x6174656D, 0x63696C6C, 0x00000000, 0x00050005, +0x00000519, 0x67756F72, 0x73656E68, 0x00000073, 0x00030005, 0x00000528, 0x00786574, 0x00030005, +0x0000054C, 0x00786574, 0x00050005, 0x0000056A, 0x6574616D, 0x6C616972, 0x00000000, 0x00050005, +0x0000057F, 0x6F4E5F75, 0x6C616D72, 0x0070614D, 0x00040005, 0x00000598, 0x61726170, 0x0000006D, +0x00030005, 0x0000059E, 0x00007675, 0x00060005, 0x000005A0, 0x465F6C67, 0x43676172, 0x64726F6F, +0x00000000, 0x00040005, 0x000005AB, 0x6F617373, 0x00000000, 0x00050005, 0x000005AC, 0x41535375, +0x70614D4F, 0x00000000, 0x00040005, 0x000005BB, 0x61726170, 0x0000006D, 0x00050005, 0x000005C0, +0x67756F72, 0x73656E68, 0x00003273, 0x00040005, 0x000005C4, 0x75646E64, 0x00000000, 0x00040005, +0x000005C8, 0x76646E64, 0x00000000, 0x00050005, 0x000005CC, 0x69726176, 0x65636E61, 0x00000000, +0x00070005, 0x000005D4, 0x6E72656B, 0x6F526C65, 0x6E686775, 0x32737365, 0x00000000, 0x00070005, +0x000005D9, 0x746C6966, 0x64657265, 0x67756F52, 0x73656E68, 0x00003273, 0x00040005, 0x000005DD, +0x61726170, 0x0000006D, 0x00040005, 0x000005E7, 0x6F507377, 0x00000073, 0x00050005, 0x000005F9, +0x44524275, 0x54554C46, 0x00000000, 0x00050005, 0x00000603, 0x6C666572, 0x61746365, 0x0065636E, +0x00040005, 0x00000604, 0x61726170, 0x0000006D, 0x00030005, 0x00000608, 0x00003046, 0x00040005, +0x0000060B, 0x61726170, 0x0000006D, 0x00040005, 0x0000060E, 0x61726170, 0x0000006D, 0x00040005, +0x00000621, 0x61726170, 0x0000006D, 0x00060005, 0x0000062B, 0x64616873, 0x6944776F, 0x6E617473, +0x00006563, 0x00070005, 0x0000062E, 0x6E617274, 0x69746973, 0x69446E6F, 0x6E617473, 0x00006563, +0x00040005, 0x00000631, 0x77656976, 0x00736F50, 0x00050005, 0x0000063A, 0x74736964, 0x65636E61, +0x00000000, 0x00030005, 0x00000648, 0x0000724C, 0x00070005, 0x00000652, 0x6867696C, 0x6E6F4374, +0x62697274, 0x6F697475, 0x0000006E, 0x00040005, 0x00000653, 0x61726170, 0x0000006D, 0x00040005, +0x00000656, 0x61726170, 0x0000006D, 0x00040005, 0x00000658, 0x61726170, 0x0000006D, 0x00060005, +0x0000065B, 0x436C6269, 0x72746E6F, 0x74756269, 0x006E6F69, 0x00040005, 0x0000065C, 0x61726170, +0x0000006D, 0x00040005, 0x0000065F, 0x61726170, 0x0000006D, 0x00040005, 0x00000661, 0x61726170, +0x0000006D, 0x00050005, 0x00000664, 0x616E6966, 0x6C6F436C, 0x0072756F, 0x00050005, 0x0000066C, +0x4374756F, 0x726F6C6F, 0x00000000, 0x00060005, 0x000006AB, 0x63736163, 0x49656461, 0x7865646E, +0x00000000, 0x00040005, 0x000006AC, 0x61726170, 0x0000006D, 0x00050048, 0x000001DB, 0x00000000, +0x00000023, 0x00000000, 0x00050048, 0x000001DB, 0x00000001, 0x00000023, 0x00000010, 0x00050048, +0x000001DB, 0x00000002, 0x00000023, 0x00000014, 0x00050048, 0x000001DB, 0x00000003, 0x00000023, +0x00000018, 0x00050048, 0x000001DB, 0x00000004, 0x00000023, 0x0000001C, 0x00050048, 0x000001DB, +0x00000005, 0x00000023, 0x00000020, 0x00050048, 0x000001DB, 0x00000006, 0x00000023, 0x00000024, +0x00050048, 0x000001DB, 0x00000007, 0x00000023, 0x00000028, 0x00050048, 0x000001DB, 0x00000008, +0x00000023, 0x0000002C, 0x00050048, 0x000001DB, 0x00000009, 0x00000023, 0x00000030, 0x00050048, +0x000001DB, 0x0000000A, 0x00000023, 0x00000034, 0x00050048, 0x000001DB, 0x0000000B, 0x00000023, +0x00000038, 0x00050048, 0x000001DB, 0x0000000C, 0x00000023, 0x0000003C, 0x00030047, 0x000001DB, +0x00000002, 0x00040047, 0x000001DD, 0x00000022, 0x00000001, 0x00040047, 0x000001DD, 0x00000021, +0x00000006, 0x00040047, 0x000001F7, 0x00000022, 0x00000001, 0x00040047, 0x000001F7, 0x00000021, +0x00000000, 0x00040047, 0x000001FC, 0x0000001E, 0x00000000, 0x00040047, 0x0000021B, 0x00000022, +0x00000001, 0x00040047, 0x0000021B, 0x00000021, 0x00000001, 0x00040047, 0x00000237, 0x00000022, +0x00000001, 0x00040047, 0x00000237, 0x00000021, 0x00000002, 0x00040047, 0x0000024E, 0x00000022, +0x00000001, 0x00040047, 0x0000024E, 0x00000021, 0x00000004, 0x00040047, 0x0000026A, 0x00000022, +0x00000001, 0x00040047, 0x0000026A, 0x00000021, 0x00000005, 0x00050048, 0x000002A3, 0x00000000, +0x00000023, 0x00000000, 0x00050048, 0x000002A3, 0x00000001, 0x00000023, 0x00000010, 0x00050048, +0x000002A3, 0x00000002, 0x00000023, 0x00000020, 0x00050048, 0x000002A3, 0x00000003, 0x00000023, +0x00000030, 0x00050048, 0x000002A3, 0x00000004, 0x00000023, 0x00000034, 0x00050048, 0x000002A3, +0x00000005, 0x00000023, 0x00000038, 0x00050048, 0x000002A3, 0x00000006, 0x00000023, 0x0000003C, +0x00040047, 0x000002A5, 0x00000006, 0x00000040, 0x00040047, 0x000002A8, 0x00000006, 0x00000040, +0x00040047, 0x000002A9, 0x00000006, 0x00000010, 0x00050048, 0x000002AA, 0x00000000, 0x00000023, +0x00000000, 0x00040048, 0x000002AA, 0x00000001, 0x00000005, 0x00050048, 0x000002AA, 0x00000001, +0x00000023, 0x00000800, 0x00050048, 0x000002AA, 0x00000001, 0x00000007, 0x00000010, 0x00040048, +0x000002AA, 0x00000002, 0x00000005, 0x00050048, 0x000002AA, 0x00000002, 0x00000023, 0x00000900, +0x00050048, 0x000002AA, 0x00000002, 0x00000007, 0x00000010, 0x00040048, 0x000002AA, 0x00000003, +0x00000005, 0x00050048, 0x000002AA, 0x00000003, 0x00000023, 0x00000940, 0x00050048, 0x000002AA, +0x00000003, 0x00000007, 0x00000010, 0x00040048, 0x000002AA, 0x00000004, 0x00000005, 0x00050048, +0x000002AA, 0x00000004, 0x00000023, 0x00000980, 0x00050048, 0x000002AA, 0x00000004, 0x00000007, +0x00000010, 0x00050048, 0x000002AA, 0x00000005, 0x00000023, 0x000009C0, 0x00050048, 0x000002AA, +0x00000006, 0x00000023, 0x000009D0, 0x00050048, 0x000002AA, 0x00000007, 0x00000023, 0x00000A10, +0x00050048, 0x000002AA, 0x00000008, 0x00000023, 0x00000A14, 0x00050048, 0x000002AA, 0x00000009, +0x00000023, 0x00000A18, 0x00050048, 0x000002AA, 0x0000000A, 0x00000023, 0x00000A1C, 0x00050048, +0x000002AA, 0x0000000B, 0x00000023, 0x00000A20, 0x00050048, 0x000002AA, 0x0000000C, 0x00000023, +0x00000A24, 0x00050048, 0x000002AA, 0x0000000D, 0x00000023, 0x00000A28, 0x00050048, 0x000002AA, +0x0000000E, 0x00000023, 0x00000A2C, 0x00050048, 0x000002AA, 0x0000000F, 0x00000023, 0x00000A30, +0x00050048, 0x000002AA, 0x00000010, 0x00000023, 0x00000A34, 0x00050048, 0x000002AA, 0x00000011, +0x00000023, 0x00000A38, 0x00050048, 0x000002AA, 0x00000012, 0x00000023, 0x00000A3C, 0x00030047, +0x000002AA, 0x00000002, 0x00040047, 0x000002AC, 0x00000022, 0x00000002, 0x00040047, 0x000002AC, +0x00000021, 0x00000005, 0x00040047, 0x0000034A, 0x00000022, 0x00000002, 0x00040047, 0x0000034A, +0x00000021, 0x00000003, 0x00040047, 0x000004CE, 0x00000022, 0x00000002, 0x00040047, 0x000004CE, +0x00000021, 0x00000002, 0x00040047, 0x000004F1, 0x00000022, 0x00000002, 0x00040047, 0x000004F1, +0x00000021, 0x00000001, 0x00040047, 0x0000057F, 0x00000022, 0x00000001, 0x00040047, 0x0000057F, +0x00000021, 0x00000003, 0x00040047, 0x000005A0, 0x0000000B, 0x0000000F, 0x00040047, 0x000005AC, +0x00000022, 0x00000002, 0x00040047, 0x000005AC, 0x00000021, 0x00000004, 0x00040047, 0x000005F9, +0x00000022, 0x00000002, 0x00040047, 0x000005F9, 0x00000021, 0x00000000, 0x00040047, 0x0000066C, +0x0000001E, 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, +0x00000006, 0x00000020, 0x00040020, 0x00000007, 0x00000007, 0x00000006, 0x00040021, 0x00000008, +0x00000006, 0x00000007, 0x00040017, 0x0000000C, 0x00000006, 0x00000003, 0x00040020, 0x0000000D, +0x00000007, 0x0000000C, 0x00040021, 0x0000000E, 0x0000000C, 0x0000000D, 0x00040017, 0x00000012, +0x00000006, 0x00000004, 0x00040020, 0x00000013, 0x00000007, 0x00000012, 0x00040021, 0x00000014, +0x00000012, 0x00000013, 0x00070021, 0x0000001B, 0x00000006, 0x00000007, 0x00000007, 0x0000000C, +0x0000000C, 0x00060021, 0x00000022, 0x0000000C, 0x0000000C, 0x00000007, 0x00000007, 0x00060021, +0x00000028, 0x00000006, 0x00000007, 0x00000007, 0x00000007, 0x00070021, 0x0000002E, 0x00000006, +0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00050021, 0x0000003A, 0x00000006, 0x00000007, +0x00000007, 0x00050021, 0x00000048, 0x0000000C, 0x00000012, 0x00000007, 0x00060021, 0x0000004D, +0x0000000C, 0x00000012, 0x00000007, 0x00000007, 0x00050021, 0x00000064, 0x0000000C, 0x0000000C, +0x00000007, 0x00060021, 0x00000069, 0x0000000C, 0x0000000D, 0x00000007, 0x00000007, 0x00030021, +0x0000006F, 0x00000012, 0x00030021, 0x00000072, 0x0000000C, 0x00030021, 0x00000075, 0x00000006, +0x00040017, 0x0000007D, 0x00000006, 0x00000002, 0x00040020, 0x0000007E, 0x00000007, 0x0000007D, +0x00040021, 0x0000007F, 0x00000006, 0x0000007E, 0x00040015, 0x00000083, 0x00000020, 0x00000001, +0x00040020, 0x00000084, 0x00000007, 0x00000083, 0x00060021, 0x00000085, 0x0000007D, 0x00000084, +0x00000084, 0x00000007, 0x00060021, 0x0000008B, 0x00000006, 0x0000000D, 0x0000000D, 0x00000084, +0x00090019, 0x00000091, 0x00000006, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x00000001, +0x00000000, 0x0003001B, 0x00000092, 0x00000091, 0x00040020, 0x00000093, 0x00000000, 0x00000092, +0x000A0021, 0x00000094, 0x00000006, 0x00000093, 0x00000013, 0x00000007, 0x0000000D, 0x0000000D, +0x0000000D, 0x00000084, 0x00040021, 0x0000009E, 0x00000083, 0x0000000D, 0x00070021, 0x000000A2, +0x00000006, 0x0000000D, 0x00000084, 0x0000000D, 0x0000000D, 0x000F001E, 0x000000A9, 0x00000012, +0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x0000000C, 0x0000000C, 0x00000006, 0x0000000C, +0x00000006, 0x0000000C, 0x0000000C, 0x0000007D, 0x0009001E, 0x000000AA, 0x00000012, 0x00000012, +0x00000012, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x000A0021, 0x000000AB, 0x0000000C, +0x000000A9, 0x000000AA, 0x0000000C, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00070021, +0x000000B5, 0x0000000C, 0x000000A9, 0x00000007, 0x00000007, 0x00000007, 0x00040020, 0x000000C5, +0x00000007, 0x000000A9, 0x00060021, 0x000000C6, 0x0000000C, 0x0000000D, 0x0000000D, 0x000000C5, +0x00040020, 0x000000D1, 0x00000006, 0x00000006, 0x0004003B, 0x000000D1, 0x000000D2, 0x00000006, +0x0004002B, 0x00000006, 0x000000D3, 0x3F800000, 0x0004003B, 0x000000D1, 0x000000D4, 0x00000006, +0x0004002B, 0x00000006, 0x000000D5, 0x3FCF1BBD, 0x0004002B, 0x00000006, 0x000000E2, 0x400CCCCD, +0x0006002C, 0x0000000C, 0x000000E3, 0x000000E2, 0x000000E2, 0x000000E2, 0x00040015, 0x000000EB, +0x00000020, 0x00000000, 0x0004002B, 0x000000EB, 0x000000EC, 0x00000003, 0x0004002B, 0x00000006, +0x000000F6, 0x00000000, 0x0004002B, 0x00000006, 0x0000010E, 0x3EA2F983, 0x0004002B, 0x00000006, +0x00000111, 0x477FE000, 0x0004002B, 0x00000006, 0x00000126, 0x40A00000, 0x0004002B, 0x00000006, +0x0000012D, 0x3F000000, 0x0004002B, 0x00000006, 0x0000012E, 0x40000000, 0x0004002B, 0x00000006, +0x00000172, 0x3F7FF972, 0x0004002B, 0x00000006, 0x0000018D, 0x38D1B717, 0x0004002B, 0x00000006, +0x000001A2, 0x3E23D70A, 0x0004002B, 0x00000006, 0x000001BF, 0x41840000, 0x0006002C, 0x0000000C, +0x000001C0, 0x000001BF, 0x000001BF, 0x000001BF, 0x000F001E, 0x000001DB, 0x00000012, 0x00000006, +0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000006, +0x00000006, 0x00000006, 0x00000006, 0x00040020, 0x000001DC, 0x00000002, 0x000001DB, 0x0004003B, +0x000001DC, 0x000001DD, 0x00000002, 0x0004002B, 0x00000083, 0x000001DE, 0x00000005, 0x00040020, +0x000001DF, 0x00000002, 0x00000006, 0x0004002B, 0x00000006, 0x000001E2, 0x3D4CCCCD, 0x00020014, +0x000001E3, 0x0004002B, 0x00000083, 0x000001E7, 0x00000000, 0x00040020, 0x000001E8, 0x00000002, +0x00000012, 0x00090019, 0x000001F4, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000000, +0x00000001, 0x00000000, 0x0003001B, 0x000001F5, 0x000001F4, 0x00040020, 0x000001F6, 0x00000000, +0x000001F5, 0x0004003B, 0x000001F6, 0x000001F7, 0x00000000, 0x00040018, 0x000001F9, 0x0000000C, +0x00000003, 0x0007001E, 0x000001FA, 0x0000000C, 0x0000007D, 0x00000012, 0x0000000C, 0x000001F9, +0x00040020, 0x000001FB, 0x00000001, 0x000001FA, 0x0004003B, 0x000001FB, 0x000001FC, 0x00000001, +0x0004002B, 0x00000083, 0x000001FD, 0x00000001, 0x00040020, 0x000001FE, 0x00000001, 0x0000007D, +0x0004002B, 0x00000083, 0x00000208, 0x00000006, 0x0004002B, 0x00000083, 0x0000020E, 0x00000002, +0x0004003B, 0x000001F6, 0x0000021B, 0x00000000, 0x0004002B, 0x00000083, 0x00000226, 0x00000007, +0x0004003B, 0x000001F6, 0x00000237, 0x00000000, 0x0004002B, 0x000000EB, 0x0000023C, 0x00000000, +0x0004002B, 0x00000083, 0x00000242, 0x0000000A, 0x0004003B, 0x000001F6, 0x0000024E, 0x00000000, +0x0004002B, 0x00000083, 0x00000258, 0x00000009, 0x0004002B, 0x00000083, 0x0000025E, 0x00000004, +0x0004003B, 0x000001F6, 0x0000026A, 0x00000000, 0x0004002B, 0x00000006, 0x00000277, 0x414FD639, +0x0004002B, 0x00000006, 0x00000278, 0x429C774C, 0x0005002C, 0x0000007D, 0x00000279, 0x00000277, +0x00000278, 0x0004002B, 0x00000006, 0x0000027C, 0x472AEE8C, 0x0004002B, 0x00000006, 0x00000282, +0x4019999A, 0x0009001E, 0x000002A3, 0x00000012, 0x00000012, 0x00000012, 0x00000006, 0x00000006, +0x00000006, 0x00000006, 0x0004002B, 0x000000EB, 0x000002A4, 0x00000020, 0x0004001C, 0x000002A5, +0x000002A3, 0x000002A4, 0x00040018, 0x000002A6, 0x00000012, 0x00000004, 0x0004002B, 0x000000EB, +0x000002A7, 0x00000004, 0x0004001C, 0x000002A8, 0x000002A6, 0x000002A7, 0x0004001C, 0x000002A9, +0x00000012, 0x000002A7, 0x0015001E, 0x000002AA, 0x000002A5, 0x000002A8, 0x000002A6, 0x000002A6, +0x000002A6, 0x00000012, 0x000002A9, 0x00000006, 0x00000006, 0x00000006, 0x00000006, 0x00000083, +0x00000083, 0x00000083, 0x00000083, 0x00000006, 0x00000006, 0x00000006, 0x00000083, 0x00040020, +0x000002AB, 0x00000002, 0x000002AA, 0x0004003B, 0x000002AB, 0x000002AC, 0x00000002, 0x0004002B, +0x00000083, 0x000002AD, 0x0000000F, 0x0004002B, 0x00000083, 0x000002D1, 0x00000008, 0x0004002B, +0x00000006, 0x000002DA, 0x442F0000, 0x0004002B, 0x000000EB, 0x000002EA, 0x00000002, 0x0004002B, +0x00000006, 0x000002F6, 0x41000000, 0x00040020, 0x000002FC, 0x00000002, 0x000002A6, 0x0004002B, +0x00000083, 0x0000030C, 0x0000000C, 0x00040020, 0x0000030D, 0x00000002, 0x00000083, 0x0004002B, +0x00000006, 0x00000334, 0x3C23D70A, 0x0004002B, 0x00000006, 0x0000033E, 0x3B03126F, 0x0004003B, +0x00000093, 0x0000034A, 0x00000000, 0x0006002C, 0x0000000C, 0x000003CD, 0x000000F6, 0x000000F6, +0x000000F6, 0x0004002B, 0x00000083, 0x000003D5, 0x0000000B, 0x00040020, 0x000003D9, 0x00000007, +0x000000AA, 0x00040020, 0x000003DC, 0x00000002, 0x000002A3, 0x0004002B, 0x00000083, 0x000003E6, +0x00000003, 0x0004002B, 0x00000006, 0x00000437, 0x3F666666, 0x0004002B, 0x00000083, 0x0000044F, +0x00000012, 0x00090019, 0x000004CB, 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000000, +0x00000001, 0x00000000, 0x0003001B, 0x000004CC, 0x000004CB, 0x00040020, 0x000004CD, 0x00000000, +0x000004CC, 0x0004003B, 0x000004CD, 0x000004CE, 0x00000000, 0x0004002B, 0x00000083, 0x000004ED, +0x0000000E, 0x0004003B, 0x000004CD, 0x000004F1, 0x00000000, 0x0004002B, 0x000000EB, 0x00000501, +0x00000001, 0x00040020, 0x00000574, 0x00000001, 0x0000000C, 0x0004002B, 0x00000006, 0x0000057B, +0x3D23D70A, 0x0004003B, 0x000001F6, 0x0000057F, 0x00000000, 0x00040020, 0x0000058A, 0x00000001, +0x000001F9, 0x00040020, 0x0000059F, 0x00000001, 0x00000012, 0x0004003B, 0x0000059F, 0x000005A0, +0x00000001, 0x0004002B, 0x00000083, 0x000005A3, 0x00000010, 0x0004002B, 0x00000083, 0x000005A6, +0x00000011, 0x0004003B, 0x000001F6, 0x000005AC, 0x00000000, 0x0004002B, 0x00000006, 0x000005B8, +0x3D3851EC, 0x0004002B, 0x00000006, 0x000005D7, 0x3CA3D70A, 0x0004002B, 0x00000006, 0x000005E4, +0x3B04B5DD, 0x0004003B, 0x000001F6, 0x000005F9, 0x00000000, 0x0004002B, 0x00000006, 0x00000615, +0x3DCCCCCD, 0x00040020, 0x0000066B, 0x00000003, 0x00000012, 0x0004003B, 0x0000066B, 0x0000066C, +0x00000003, 0x0004002B, 0x00000083, 0x00000672, 0x0000000D, 0x0004002B, 0x00000006, 0x000006B6, +0x3F4CCCCD, 0x0004002B, 0x00000006, 0x000006B7, 0x3E4CCCCD, 0x0007002C, 0x00000012, 0x000006B8, +0x000006B6, 0x000006B7, 0x000006B7, 0x000000D3, 0x0007002C, 0x00000012, 0x000006BC, 0x000006B7, +0x000006B6, 0x000006B7, 0x000000D3, 0x0007002C, 0x00000012, 0x000006C0, 0x000006B7, 0x000006B7, +0x000006B6, 0x000000D3, 0x0007002C, 0x00000012, 0x000006C4, 0x000006B6, 0x000006B6, 0x000006B7, +0x000000D3, 0x0004002B, 0x00000006, 0x000006CA, 0x40C90FDB, 0x0004002B, 0x00000006, 0x000006CB, +0x3727C5AC, 0x0006002C, 0x0000000C, 0x000006CC, 0x0000057B, 0x0000057B, 0x0000057B, 0x0007002C, +0x00000012, 0x000006CD, 0x0000012D, 0x000000F6, 0x000000F6, 0x0000012D, 0x0007002C, 0x00000012, +0x000006CE, 0x000000F6, 0x0000012D, 0x000000F6, 0x0000012D, 0x0007002C, 0x00000012, 0x000006CF, +0x000000F6, 0x000000F6, 0x000000D3, 0x000000F6, 0x0007002C, 0x00000012, 0x000006D0, 0x000000F6, +0x000000F6, 0x000000F6, 0x000000D3, 0x0007002C, 0x000002A6, 0x000006D1, 0x000006CD, 0x000006CE, +0x000006CF, 0x000006D0, 0x0004002B, 0x000000EB, 0x000006D2, 0x00000010, 0x0004001C, 0x000006D3, +0x0000007D, 0x000006D2, 0x0004002B, 0x00000006, 0x000006D4, 0xBF7127FA, 0x0004002B, 0x00000006, +0x000006D5, 0xBECC51E0, 0x0005002C, 0x0000007D, 0x000006D6, 0x000006D4, 0x000006D5, 0x0004002B, +0x00000006, 0x000006D7, 0x3F7211EE, 0x0004002B, 0x00000006, 0x000006D8, 0xBF44D71B, 0x0005002C, +0x0000007D, 0x000006D9, 0x000006D7, 0x000006D8, 0x0004002B, 0x00000006, 0x000006DA, 0xBDC0E398, +0x0004002B, 0x00000006, 0x000006DB, 0xBF6DEC6B, 0x0005002C, 0x0000007D, 0x000006DC, 0x000006DA, +0x000006DB, 0x0004002B, 0x00000006, 0x000006DD, 0x3EB09E84, 0x0004002B, 0x00000006, 0x000006DE, +0x3E967720, 0x0005002C, 0x0000007D, 0x000006DF, 0x000006DD, 0x000006DE, 0x0004002B, 0x00000006, +0x000006E0, 0xBF6A777E, 0x0004002B, 0x00000006, 0x000006E1, 0x3EEA5988, 0x0005002C, 0x0000007D, +0x000006E2, 0x000006E0, 0x000006E1, 0x0004002B, 0x00000006, 0x000006E3, 0xBF50C0D4, 0x0004002B, +0x00000006, 0x000006E4, 0xBF610E50, 0x0005002C, 0x0000007D, 0x000006E5, 0x000006E3, 0x000006E4, +0x0004002B, 0x00000006, 0x000006E6, 0xBEC3FB24, 0x0004002B, 0x00000006, 0x000006E7, 0x3E8DB498, +0x0005002C, 0x0000007D, 0x000006E8, 0x000006E6, 0x000006E7, 0x0004002B, 0x00000006, 0x000006E9, +0x3F798F60, 0x0004002B, 0x00000006, 0x000006EA, 0x3F41A8EC, 0x0005002C, 0x0000007D, 0x000006EB, +0x000006E9, 0x000006EA, 0x0004002B, 0x00000006, 0x000006EC, 0x3EE2EF78, 0x0004002B, 0x00000006, +0x000006ED, 0xBF79A12C, 0x0005002C, 0x0000007D, 0x000006EE, 0x000006EC, 0x000006ED, 0x0004002B, +0x00000006, 0x000006EF, 0x3F099500, 0x0004002B, 0x00000006, 0x000006F0, 0xBEF28D4A, 0x0005002C, +0x0000007D, 0x000006F1, 0x000006EF, 0x000006F0, 0x0004002B, 0x00000006, 0x000006F2, 0xBE87AA08, +0x0004002B, 0x00000006, 0x000006F3, 0xBED67E06, 0x0005002C, 0x0000007D, 0x000006F4, 0x000006F2, +0x000006F3, 0x0004002B, 0x00000006, 0x000006F5, 0x3F4ABEE2, 0x0004002B, 0x00000006, 0x000006F6, +0x3E437BC8, 0x0005002C, 0x0000007D, 0x000006F7, 0x000006F5, 0x000006F6, 0x0004002B, 0x00000006, +0x000006F8, 0xBE77B198, 0x0004002B, 0x00000006, 0x000006F9, 0x3F7F3FA8, 0x0005002C, 0x0000007D, +0x000006FA, 0x000006F8, 0x000006F9, 0x0004002B, 0x00000006, 0x000006FB, 0xBF5068D4, 0x0004002B, +0x00000006, 0x000006FC, 0x3F6A148A, 0x0005002C, 0x0000007D, 0x000006FD, 0x000006FB, 0x000006FC, +0x0004002B, 0x00000006, 0x000006FE, 0x3E4CA330, 0x0004002B, 0x00000006, 0x000006FF, 0x3F495268, +0x0005002C, 0x0000007D, 0x00000700, 0x000006FE, 0x000006FF, 0x0004002B, 0x00000006, 0x00000701, +0x3E134898, 0x0004002B, 0x00000006, 0x00000702, 0xBE106460, 0x0005002C, 0x0000007D, 0x00000703, +0x00000701, 0x00000702, 0x0013002C, 0x000006D3, 0x00000704, 0x000006D6, 0x000006D9, 0x000006DC, +0x000006DF, 0x000006E2, 0x000006E5, 0x000006E8, 0x000006EB, 0x000006EE, 0x000006F1, 0x000006F4, +0x000006F7, 0x000006FA, 0x000006FD, 0x00000700, 0x00000703, 0x0004002B, 0x000000EB, 0x00000705, +0x00000040, 0x0004001C, 0x00000706, 0x0000007D, 0x00000705, 0x0004002B, 0x00000006, 0x00000707, +0xBF625322, 0x0004002B, 0x00000006, 0x00000708, 0x3DFEF391, 0x0005002C, 0x0000007D, 0x00000709, +0x00000707, 0x00000708, 0x0004002B, 0x00000006, 0x0000070A, 0xBF36E169, 0x0004002B, 0x00000006, +0x0000070B, 0x3CE4E26D, 0x0005002C, 0x0000007D, 0x0000070C, 0x0000070A, 0x0000070B, 0x0004002B, +0x00000006, 0x0000070D, 0xBF3F7953, 0x0004002B, 0x00000006, 0x0000070E, 0x3E696463, 0x0005002C, +0x0000007D, 0x0000070F, 0x0000070D, 0x0000070E, 0x0004002B, 0x00000006, 0x00000710, 0xBF708A37, +0x0004002B, 0x00000006, 0x00000711, 0x3E797B31, 0x0005002C, 0x0000007D, 0x00000712, 0x00000710, +0x00000711, 0x0004002B, 0x00000006, 0x00000713, 0xBF7C476F, 0x0004002B, 0x00000006, 0x00000714, +0x3D3A81DC, 0x0005002C, 0x0000007D, 0x00000715, 0x00000713, 0x00000714, 0x0004002B, 0x00000006, +0x00000716, 0xBF5C828C, 0x0004002B, 0x00000006, 0x00000717, 0xBE0B7DC8, 0x0005002C, 0x0000007D, +0x00000718, 0x00000716, 0x00000717, 0x0004002B, 0x00000006, 0x00000719, 0xBF61C66D, 0x0004002B, +0x00000006, 0x0000071A, 0x3ECB3786, 0x0005002C, 0x0000007D, 0x0000071B, 0x00000719, 0x0000071A, +0x0004002B, 0x00000006, 0x0000071C, 0xBEEF127F, 0x0004002B, 0x00000006, 0x0000071D, 0x3C6DFE76, +0x0005002C, 0x0000007D, 0x0000071E, 0x0000071C, 0x0000071D, 0x0004002B, 0x00000006, 0x0000071F, +0xBF0EE6A7, 0x0004002B, 0x00000006, 0x00000720, 0x3E59C411, 0x0005002C, 0x0000007D, 0x00000721, +0x0000071F, 0x00000720, 0x0004002B, 0x00000006, 0x00000722, 0xBF14151A, 0x0004002B, 0x00000006, +0x00000723, 0xBDC43E53, 0x0005002C, 0x0000007D, 0x00000724, 0x00000722, 0x00000723, 0x0004002B, +0x00000006, 0x00000725, 0xBF3D8213, 0x0004002B, 0x00000006, 0x00000726, 0xBDC3DA30, 0x0005002C, +0x0000007D, 0x00000727, 0x00000725, 0x00000726, 0x0004002B, 0x00000006, 0x00000728, 0xBF406E2B, +0x0004002B, 0x00000006, 0x00000729, 0x3EF1F927, 0x0005002C, 0x0000007D, 0x0000072A, 0x00000728, +0x00000729, 0x0004002B, 0x00000006, 0x0000072B, 0xBF0D9B0B, 0x0004002B, 0x00000006, 0x0000072C, +0xBE790364, 0x0005002C, 0x0000007D, 0x0000072D, 0x0000072B, 0x0000072C, 0x0004002B, 0x00000006, +0x0000072E, 0xBF2CBD34, 0x0004002B, 0x00000006, 0x0000072F, 0xBEA95571, 0x0005002C, 0x0000007D, +0x00000730, 0x0000072E, 0x0000072F, 0x0004002B, 0x00000006, 0x00000731, 0xBECE3737, 0x0004002B, +0x00000006, 0x00000732, 0xBDFA08C0, 0x0005002C, 0x0000007D, 0x00000733, 0x00000731, 0x00000732, +0x0004002B, 0x00000006, 0x00000734, 0xBEA3B9AE, 0x0004002B, 0x00000006, 0x00000735, 0xBE9FD439, +0x0005002C, 0x0000007D, 0x00000736, 0x00000734, 0x00000735, 0x0004002B, 0x00000006, 0x00000737, +0xBED3EDB7, 0x0004002B, 0x00000006, 0x00000738, 0xBEE127D4, 0x0005002C, 0x0000007D, 0x00000739, +0x00000737, 0x00000738, 0x0004002B, 0x00000006, 0x0000073A, 0xBF7AA9C5, 0x0004002B, 0x00000006, +0x0000073B, 0xBE4E132B, 0x0005002C, 0x0000007D, 0x0000073C, 0x0000073A, 0x0000073B, 0x0004002B, +0x00000006, 0x0000073D, 0xBF5D9696, 0x0004002B, 0x00000006, 0x0000073E, 0xBE93CFD5, 0x0005002C, +0x0000007D, 0x0000073F, 0x0000073D, 0x0000073E, 0x0004002B, 0x00000006, 0x00000740, 0xBE798D8B, +0x0004002B, 0x00000006, 0x00000741, 0xBE3ED9E0, 0x0005002C, 0x0000007D, 0x00000742, 0x00000740, +0x00000741, 0x0004002B, 0x00000006, 0x00000743, 0xBE96FFC1, 0x0004002B, 0x00000006, 0x00000744, +0xBD645804, 0x0005002C, 0x0000007D, 0x00000745, 0x00000743, 0x00000744, 0x0004002B, 0x00000006, +0x00000746, 0xBF1ABD5E, 0x0004002B, 0x00000006, 0x00000747, 0xBF0B5409, 0x0005002C, 0x0000007D, +0x00000748, 0x00000746, 0x00000747, 0x0004002B, 0x00000006, 0x00000749, 0xBED60B70, 0x0004002B, +0x00000006, 0x0000074A, 0xBF167222, 0x0005002C, 0x0000007D, 0x0000074B, 0x00000749, 0x0000074A, +0x0004002B, 0x00000006, 0x0000074C, 0xBF0C957D, 0x0004002B, 0x00000006, 0x0000074D, 0xBED4EDD5, +0x0005002C, 0x0000007D, 0x0000074E, 0x0000074C, 0x0000074D, 0x0004002B, 0x00000006, 0x0000074F, +0xBE73CB3E, 0x0004002B, 0x00000006, 0x00000750, 0xBF1C9C5E, 0x0005002C, 0x0000007D, 0x00000751, +0x0000074F, 0x00000750, 0x0004002B, 0x00000006, 0x00000752, 0xBE88B4C0, 0x0004002B, 0x00000006, +0x00000753, 0xBEEB5E0F, 0x0005002C, 0x0000007D, 0x00000754, 0x00000752, 0x00000753, 0x0004002B, +0x00000006, 0x00000755, 0xBDCCCFF2, 0x0004002B, 0x00000006, 0x00000756, 0xBE6A9D62, 0x0005002C, +0x0000007D, 0x00000757, 0x00000755, 0x00000756, 0x0004002B, 0x00000006, 0x00000758, 0xBDD0BFA1, +0x0004002B, 0x00000006, 0x00000759, 0xBEC2C16E, 0x0005002C, 0x0000007D, 0x0000075A, 0x00000758, +0x00000759, 0x0004002B, 0x00000006, 0x0000075B, 0xBF2E749F, 0x0004002B, 0x00000006, 0x0000075C, +0xBF3365DC, 0x0005002C, 0x0000007D, 0x0000075D, 0x0000075B, 0x0000075C, 0x0004002B, 0x00000006, +0x0000075E, 0xBF4373F3, 0x0004002B, 0x00000006, 0x0000075F, 0xBF0B1B58, 0x0005002C, 0x0000007D, +0x00000760, 0x0000075E, 0x0000075F, 0x0004002B, 0x00000006, 0x00000761, 0xBF0C8D3B, 0x0004002B, +0x00000006, 0x00000762, 0xBF403116, 0x0005002C, 0x0000007D, 0x00000763, 0x00000761, 0x00000762, +0x0004002B, 0x00000006, 0x00000764, 0xBF4F1D93, 0x0004002B, 0x00000006, 0x00000765, 0xBED1461B, +0x0005002C, 0x0000007D, 0x00000766, 0x00000764, 0x00000765, 0x0004002B, 0x00000006, 0x00000767, +0xBEC6B980, 0x0004002B, 0x00000006, 0x00000768, 0xBF4600B0, 0x0005002C, 0x0000007D, 0x00000769, +0x00000767, 0x00000768, 0x0004002B, 0x00000006, 0x0000076A, 0xBEDBD945, 0x0004002B, 0x00000006, +0x0000076B, 0xBF6517A4, 0x0005002C, 0x0000007D, 0x0000076C, 0x0000076A, 0x0000076B, 0x0004002B, +0x00000006, 0x0000076D, 0xBE06C15D, 0x0004002B, 0x00000006, 0x0000076E, 0x3D853D21, 0x0005002C, +0x0000007D, 0x0000076F, 0x0000076D, 0x0000076E, 0x0004002B, 0x00000006, 0x00000770, 0xBE8CCD10, +0x0004002B, 0x00000006, 0x00000771, 0x3DD2C8C5, 0x0005002C, 0x0000007D, 0x00000772, 0x00000770, +0x00000771, 0x0004002B, 0x00000006, 0x00000773, 0xBDD953DF, 0x0004002B, 0x00000006, 0x00000774, +0xBD8BEF07, 0x0005002C, 0x0000007D, 0x00000775, 0x00000773, 0x00000774, 0x0004002B, 0x00000006, +0x00000776, 0xBE96D3FA, 0x0004002B, 0x00000006, 0x00000777, 0xBF643A54, 0x0005002C, 0x0000007D, +0x00000778, 0x00000776, 0x00000777, 0x0004002B, 0x00000006, 0x00000779, 0xBF21218A, 0x0004002B, +0x00000006, 0x0000077A, 0x3EC23F03, 0x0005002C, 0x0000007D, 0x0000077B, 0x00000779, 0x0000077A, +0x0004002B, 0x00000006, 0x0000077C, 0xBED083FD, 0x0004002B, 0x00000006, 0x0000077D, 0x3EADF373, +0x0005002C, 0x0000007D, 0x0000077E, 0x0000077C, 0x0000077D, 0x0004002B, 0x00000006, 0x0000077F, +0x3D92BD3C, 0x0004002B, 0x00000006, 0x00000780, 0xBEC4C0DF, 0x0005002C, 0x0000007D, 0x00000781, +0x0000077F, 0x00000780, 0x0004002B, 0x00000006, 0x00000782, 0x3CB45F18, 0x0004002B, 0x00000006, +0x00000783, 0xBE870FE0, 0x0005002C, 0x0000007D, 0x00000784, 0x00000782, 0x00000783, 0x0004002B, +0x00000006, 0x00000785, 0x3B7E36D2, 0x0004002B, 0x00000006, 0x00000786, 0xBE0B56B8, 0x0005002C, +0x0000007D, 0x00000787, 0x00000785, 0x00000786, 0x0004002B, 0x00000006, 0x00000788, 0xBE0CD573, +0x0004002B, 0x00000006, 0x00000789, 0xBF44916D, 0x0005002C, 0x0000007D, 0x0000078A, 0x00000788, +0x00000789, 0x0004002B, 0x00000006, 0x0000078B, 0xBD506141, 0x0004002B, 0x00000006, 0x0000078C, +0xBF67F413, 0x0005002C, 0x0000007D, 0x0000078D, 0x0000078B, 0x0000078C, 0x0004002B, 0x00000006, +0x0000078E, 0x3DE9BE90, 0x0004002B, 0x00000006, 0x0000078F, 0xBD8F77F2, 0x0005002C, 0x0000007D, +0x00000790, 0x0000078E, 0x0000078F, 0x0004002B, 0x00000006, 0x00000791, 0x3E273BC9, 0x0004002B, +0x00000006, 0x00000792, 0xBE5E71CE, 0x0005002C, 0x0000007D, 0x00000793, 0x00000791, 0x00000792, +0x0004002B, 0x00000006, 0x00000794, 0xBDCD562A, 0x0004002B, 0x00000006, 0x00000795, 0xBF1686A5, +0x0005002C, 0x0000007D, 0x00000796, 0x00000794, 0x00000795, 0x0004002B, 0x00000006, 0x00000797, +0xBBA1F080, 0x0004002B, 0x00000006, 0x00000798, 0x3E006078, 0x0005002C, 0x0000007D, 0x00000799, +0x00000797, 0x00000798, 0x0004002B, 0x00000006, 0x0000079A, 0x3D1098D4, 0x0004002B, 0x00000006, +0x0000079B, 0xBF1E8B1A, 0x0005002C, 0x0000007D, 0x0000079C, 0x0000079A, 0x0000079B, 0x0004002B, +0x00000006, 0x0000079D, 0x3E48576D, 0x0004002B, 0x00000006, 0x0000079E, 0xBEEB04EE, 0x0005002C, +0x0000007D, 0x0000079F, 0x0000079D, 0x0000079E, 0x0004002B, 0x00000006, 0x000007A0, 0x3E9BA1D3, +0x0004002B, 0x00000006, 0x000007A1, 0xBEB1565C, 0x0005002C, 0x0000007D, 0x000007A2, 0x000007A0, +0x000007A1, 0x0004002B, 0x00000006, 0x000007A3, 0xBF2D9924, 0x0004002B, 0x00000006, 0x000007A4, +0x3F2F62A6, 0x0005002C, 0x0000007D, 0x000007A5, 0x000007A3, 0x000007A4, 0x0004002B, 0x00000006, +0x000007A6, 0xBF20E001, 0x0004002B, 0x00000006, 0x000007A7, 0x3F020AD9, 0x0005002C, 0x0000007D, +0x000007A8, 0x000007A6, 0x000007A7, 0x0004002B, 0x00000006, 0x000007A9, 0xBF022B49, 0x0004002B, +0x00000006, 0x000007AA, 0x3EEAE1AC, 0x0005002C, 0x0000007D, 0x000007AB, 0x000007A9, 0x000007AA, +0x0004002B, 0x00000006, 0x000007AC, 0x3D039EF1, 0x0004002B, 0x00000006, 0x000007AD, 0xBF48331E, +0x0005002C, 0x0000007D, 0x000007AE, 0x000007AC, 0x000007AD, 0x0004002B, 0x00000006, 0x000007AF, +0x3DFB1316, 0x0004002B, 0x00000006, 0x000007B0, 0x3E8F8A6E, 0x0005002C, 0x0000007D, 0x000007B1, +0x000007AF, 0x000007B0, 0x0004002B, 0x00000006, 0x000007B2, 0xBD32C301, 0x0004002B, 0x00000006, +0x000007B3, 0x3E9FCE10, 0x0005002C, 0x0000007D, 0x000007B4, 0x000007B2, 0x000007B3, 0x0004002B, +0x00000006, 0x000007B5, 0x3E082F51, 0x0004002B, 0x00000006, 0x000007B6, 0x3DAE6D9C, 0x0005002C, +0x0000007D, 0x000007B7, 0x000007B5, 0x000007B6, 0x0004002B, 0x00000006, 0x000007B8, 0xBE44B76F, +0x0004002B, 0x00000006, 0x000007B9, 0x3E925AAB, 0x0005002C, 0x0000007D, 0x000007BA, 0x000007B8, +0x000007B9, 0x0004002B, 0x00000006, 0x000007BB, 0x3E3C0725, 0x0004002B, 0x00000006, 0x000007BC, +0xBF369707, 0x0005002C, 0x0000007D, 0x000007BD, 0x000007BB, 0x000007BC, 0x0004002B, 0x00000006, +0x000007BE, 0x3E87CAEA, 0x0004002B, 0x00000006, 0x000007BF, 0xBF18C261, 0x0005002C, 0x0000007D, +0x000007C0, 0x000007BE, 0x000007BF, 0x0004002B, 0x00000006, 0x000007C1, 0xBC1DBEC2, 0x0004002B, +0x00000006, 0x000007C2, 0xBEF75361, 0x0005002C, 0x0000007D, 0x000007C3, 0x000007C1, 0x000007C2, +0x0004002B, 0x00000006, 0x000007C4, 0xBC97AEDE, 0x0004002B, 0x00000006, 0x000007C5, 0x3EDF1477, +0x0005002C, 0x0000007D, 0x000007C6, 0x000007C4, 0x000007C5, 0x0043002C, 0x00000706, 0x000007C7, +0x00000709, 0x0000070C, 0x0000070F, 0x00000712, 0x00000715, 0x00000718, 0x0000071B, 0x0000071E, +0x00000721, 0x00000724, 0x00000727, 0x0000072A, 0x0000072D, 0x00000730, 0x00000733, 0x00000736, +0x00000739, 0x0000073C, 0x0000073F, 0x00000742, 0x00000745, 0x00000748, 0x0000074B, 0x0000074E, +0x00000751, 0x00000754, 0x00000757, 0x0000075A, 0x0000075D, 0x00000760, 0x00000763, 0x00000766, +0x00000769, 0x0000076C, 0x0000076F, 0x00000772, 0x00000775, 0x00000778, 0x0000077B, 0x0000077E, +0x00000781, 0x00000784, 0x00000787, 0x0000078A, 0x0000078D, 0x00000790, 0x00000793, 0x00000796, +0x00000799, 0x0000079C, 0x0000079F, 0x000007A2, 0x000007A5, 0x000007A8, 0x000007AB, 0x000007AE, +0x000007B1, 0x000007B4, 0x000007B7, 0x000007BA, 0x000007BD, 0x000007C0, 0x000007C3, 0x000007C6, +0x00050036, 0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200F8, 0x00000005, 0x0004003B, +0x00000013, 0x0000050E, 0x00000007, 0x0004003B, 0x00000007, 0x00000518, 0x00000007, 0x0004003B, +0x00000007, 0x00000519, 0x00000007, 0x0004003B, 0x0000000D, 0x00000528, 0x00000007, 0x0004003B, +0x0000000D, 0x0000054C, 0x00000007, 0x0004003B, 0x000000C5, 0x0000056A, 0x00000007, 0x0004003B, +0x0000000D, 0x00000598, 0x00000007, 0x0004003B, 0x0000007E, 0x0000059E, 0x00000007, 0x0004003B, +0x00000007, 0x000005AB, 0x00000007, 0x0004003B, 0x00000007, 0x000005BB, 0x00000007, 0x0004003B, +0x00000007, 0x000005C0, 0x00000007, 0x0004003B, 0x0000000D, 0x000005C4, 0x00000007, 0x0004003B, +0x0000000D, 0x000005C8, 0x00000007, 0x0004003B, 0x00000007, 0x000005CC, 0x00000007, 0x0004003B, +0x00000007, 0x000005D4, 0x00000007, 0x0004003B, 0x00000007, 0x000005D9, 0x00000007, 0x0004003B, +0x00000007, 0x000005DD, 0x00000007, 0x0004003B, 0x0000000D, 0x000005E7, 0x00000007, 0x0004003B, +0x00000007, 0x00000603, 0x00000007, 0x0004003B, 0x00000007, 0x00000604, 0x00000007, 0x0004003B, +0x0000000D, 0x00000608, 0x00000007, 0x0004003B, 0x00000007, 0x0000060B, 0x00000007, 0x0004003B, +0x00000007, 0x0000060E, 0x00000007, 0x0004003B, 0x00000007, 0x00000621, 0x00000007, 0x0004003B, +0x00000007, 0x0000062B, 0x00000007, 0x0004003B, 0x00000007, 0x0000062E, 0x00000007, 0x0004003B, +0x00000013, 0x00000631, 0x00000007, 0x0004003B, 0x00000007, 0x0000063A, 0x00000007, 0x0004003B, +0x0000000D, 0x00000648, 0x00000007, 0x0004003B, 0x0000000D, 0x00000652, 0x00000007, 0x0004003B, +0x0000000D, 0x00000653, 0x00000007, 0x0004003B, 0x0000000D, 0x00000656, 0x00000007, 0x0004003B, +0x000000C5, 0x00000658, 0x00000007, 0x0004003B, 0x0000000D, 0x0000065B, 0x00000007, 0x0004003B, +0x0000000D, 0x0000065C, 0x00000007, 0x0004003B, 0x0000000D, 0x0000065F, 0x00000007, 0x0004003B, +0x000000C5, 0x00000661, 0x00000007, 0x0004003B, 0x0000000D, 0x00000664, 0x00000007, 0x0004003B, +0x00000084, 0x000006AB, 0x00000007, 0x0004003B, 0x0000000D, 0x000006AC, 0x00000007, 0x0003003E, +0x000000D2, 0x000000D3, 0x0003003E, 0x000000D4, 0x000000D5, 0x00040039, 0x00000012, 0x0000050F, +0x00000070, 0x0003003E, 0x0000050E, 0x0000050F, 0x00050041, 0x00000007, 0x00000510, 0x0000050E, +0x000000EC, 0x0004003D, 0x00000006, 0x00000511, 0x00000510, 0x00050041, 0x000001DF, 0x00000512, +0x000001DD, 0x000003D5, 0x0004003D, 0x00000006, 0x00000513, 0x00000512, 0x000500B8, 0x000001E3, +0x00000514, 0x00000511, 0x00000513, 0x000300F7, 0x00000516, 0x00000000, 0x000400FA, 0x00000514, +0x00000515, 0x00000516, 0x000200F8, 0x00000515, 0x000100FC, 0x000200F8, 0x00000516, 0x0003003E, +0x00000518, 0x000000F6, 0x0003003E, 0x00000519, 0x000000F6, 0x00050041, 0x000001DF, 0x0000051A, +0x000001DD, 0x0000030C, 0x0004003D, 0x00000006, 0x0000051B, 0x0000051A, 0x000500B4, 0x000001E3, +0x0000051C, 0x0000051B, 0x000000F6, 0x000300F7, 0x0000051E, 0x00000000, 0x000400FA, 0x0000051C, +0x0000051D, 0x00000522, 0x000200F8, 0x0000051D, 0x00040039, 0x0000000C, 0x0000051F, 0x00000073, +0x00050051, 0x00000006, 0x00000520, 0x0000051F, 0x00000000, 0x0003003E, 0x00000518, 0x00000520, +0x00040039, 0x00000006, 0x00000521, 0x00000076, 0x0003003E, 0x00000519, 0x00000521, 0x000200F9, +0x0000051E, 0x000200F8, 0x00000522, 0x00050041, 0x000001DF, 0x00000523, 0x000001DD, 0x0000030C, +0x0004003D, 0x00000006, 0x00000524, 0x00000523, 0x000500B4, 0x000001E3, 0x00000525, 0x00000524, +0x000000D3, 0x000300F7, 0x00000527, 0x00000000, 0x000400FA, 0x00000525, 0x00000526, 0x00000546, +0x000200F8, 0x00000526, 0x0004003D, 0x000001F5, 0x00000529, 0x0000021B, 0x00050041, 0x000001FE, +0x0000052A, 0x000001FC, 0x000001FD, 0x0004003D, 0x0000007D, 0x0000052B, 0x0000052A, 0x00050057, +0x00000012, 0x0000052C, 0x00000529, 0x0000052B, 0x0008004F, 0x0000000C, 0x0000052D, 0x0000052C, +0x0000052C, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000528, 0x0000052D, 0x00050041, +0x000001DF, 0x0000052E, 0x000001DD, 0x00000208, 0x0004003D, 0x00000006, 0x0000052F, 0x0000052E, +0x00050083, 0x00000006, 0x00000530, 0x000000D3, 0x0000052F, 0x00050041, 0x000001DF, 0x00000531, +0x000001DD, 0x0000020E, 0x0004003D, 0x00000006, 0x00000532, 0x00000531, 0x00050085, 0x00000006, +0x00000533, 0x00000530, 0x00000532, 0x00050041, 0x000001DF, 0x00000534, 0x000001DD, 0x00000208, +0x0004003D, 0x00000006, 0x00000535, 0x00000534, 0x00050041, 0x00000007, 0x00000536, 0x00000528, +0x000002EA, 0x0004003D, 0x00000006, 0x00000537, 0x00000536, 0x00050085, 0x00000006, 0x00000538, +0x00000535, 0x00000537, 0x00050081, 0x00000006, 0x00000539, 0x00000533, 0x00000538, 0x0003003E, +0x00000518, 0x00000539, 0x00050041, 0x000001DF, 0x0000053A, 0x000001DD, 0x00000208, 0x0004003D, +0x00000006, 0x0000053B, 0x0000053A, 0x00050083, 0x00000006, 0x0000053C, 0x000000D3, 0x0000053B, +0x00050041, 0x000001DF, 0x0000053D, 0x000001DD, 0x000001FD, 0x0004003D, 0x00000006, 0x0000053E, +0x0000053D, 0x00050085, 0x00000006, 0x0000053F, 0x0000053C, 0x0000053E, 0x00050041, 0x000001DF, +0x00000540, 0x000001DD, 0x00000208, 0x0004003D, 0x00000006, 0x00000541, 0x00000540, 0x00050041, +0x00000007, 0x00000542, 0x00000528, 0x00000501, 0x0004003D, 0x00000006, 0x00000543, 0x00000542, +0x00050085, 0x00000006, 0x00000544, 0x00000541, 0x00000543, 0x00050081, 0x00000006, 0x00000545, +0x0000053F, 0x00000544, 0x0003003E, 0x00000519, 0x00000545, 0x000200F9, 0x00000527, 0x000200F8, +0x00000546, 0x00050041, 0x000001DF, 0x00000547, 0x000001DD, 0x0000030C, 0x0004003D, 0x00000006, +0x00000548, 0x00000547, 0x000500B4, 0x000001E3, 0x00000549, 0x00000548, 0x0000012E, 0x000300F7, +0x0000054B, 0x00000000, 0x000400FA, 0x00000549, 0x0000054A, 0x0000054B, 0x000200F8, 0x0000054A, +0x0004003D, 0x000001F5, 0x0000054D, 0x0000021B, 0x00050041, 0x000001FE, 0x0000054E, 0x000001FC, +0x000001FD, 0x0004003D, 0x0000007D, 0x0000054F, 0x0000054E, 0x00050057, 0x00000012, 0x00000550, +0x0000054D, 0x0000054F, 0x0008004F, 0x0000000C, 0x00000551, 0x00000550, 0x00000550, 0x00000000, +0x00000001, 0x00000002, 0x0003003E, 0x0000054C, 0x00000551, 0x00050041, 0x000001DF, 0x00000552, +0x000001DD, 0x00000208, 0x0004003D, 0x00000006, 0x00000553, 0x00000552, 0x00050083, 0x00000006, +0x00000554, 0x000000D3, 0x00000553, 0x00050041, 0x000001DF, 0x00000555, 0x000001DD, 0x0000020E, 0x0004003D, 0x00000006, 0x00000556, 0x00000555, 0x00050085, 0x00000006, 0x00000557, 0x00000554, -0x00000556, 0x00050081, 0x00000006, 0x00000558, 0x00000552, 0x00000557, 0x0003003E, 0x00000537, -0x00000558, 0x00050041, 0x000001E1, 0x00000559, 0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, -0x0000055A, 0x00000559, 0x00050083, 0x00000006, 0x0000055B, 0x000000D5, 0x0000055A, 0x00050041, -0x000001E1, 0x0000055C, 0x000001DF, 0x000001FF, 0x0004003D, 0x00000006, 0x0000055D, 0x0000055C, -0x00050085, 0x00000006, 0x0000055E, 0x0000055B, 0x0000055D, 0x00050041, 0x000001E1, 0x0000055F, -0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, 0x00000560, 0x0000055F, 0x00050041, 0x00000007, -0x00000561, 0x00000547, 0x00000520, 0x0004003D, 0x00000006, 0x00000562, 0x00000561, 0x00050085, -0x00000006, 0x00000563, 0x00000560, 0x00000562, 0x00050081, 0x00000006, 0x00000564, 0x0000055E, -0x00000563, 0x0003003E, 0x00000538, 0x00000564, 0x000200F9, 0x00000546, 0x000200F8, 0x00000565, -0x00050041, 0x000001E1, 0x00000566, 0x000001DF, 0x0000032C, 0x0004003D, 0x00000006, 0x00000567, -0x00000566, 0x000500B4, 0x000001E5, 0x00000568, 0x00000567, 0x00000130, 0x000300F7, 0x0000056A, -0x00000000, 0x000400FA, 0x00000568, 0x00000569, 0x0000056A, 0x000200F8, 0x00000569, 0x0004003D, -0x000001F7, 0x0000056C, 0x0000021D, 0x00050041, 0x00000200, 0x0000056D, 0x000001FE, 0x000001FF, -0x0004003D, 0x0000007F, 0x0000056E, 0x0000056D, 0x00050057, 0x00000012, 0x0000056F, 0x0000056C, -0x0000056E, 0x0008004F, 0x0000000C, 0x00000570, 0x0000056F, 0x0000056F, 0x00000000, 0x00000001, -0x00000002, 0x0003003E, 0x0000056B, 0x00000570, 0x00050041, 0x000001E1, 0x00000571, 0x000001DF, -0x0000020A, 0x0004003D, 0x00000006, 0x00000572, 0x00000571, 0x00050083, 0x00000006, 0x00000573, -0x000000D5, 0x00000572, 0x00050041, 0x000001E1, 0x00000574, 0x000001DF, 0x00000210, 0x0004003D, -0x00000006, 0x00000575, 0x00000574, 0x00050085, 0x00000006, 0x00000576, 0x00000573, 0x00000575, -0x00050041, 0x000001E1, 0x00000577, 0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, 0x00000578, -0x00000577, 0x00050041, 0x00000007, 0x00000579, 0x0000056B, 0x0000030A, 0x0004003D, 0x00000006, -0x0000057A, 0x00000579, 0x00050085, 0x00000006, 0x0000057B, 0x00000578, 0x0000057A, 0x00050081, -0x00000006, 0x0000057C, 0x00000576, 0x0000057B, 0x0003003E, 0x00000537, 0x0000057C, 0x00050041, -0x000001E1, 0x0000057D, 0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, 0x0000057E, 0x0000057D, -0x00050083, 0x00000006, 0x0000057F, 0x000000D5, 0x0000057E, 0x00050041, 0x000001E1, 0x00000580, -0x000001DF, 0x000001FF, 0x0004003D, 0x00000006, 0x00000581, 0x00000580, 0x00050085, 0x00000006, -0x00000582, 0x0000057F, 0x00000581, 0x00050041, 0x000001E1, 0x00000583, 0x000001DF, 0x0000020A, -0x0004003D, 0x00000006, 0x00000584, 0x00000583, 0x00050041, 0x00000007, 0x00000585, 0x0000056B, -0x00000520, 0x0004003D, 0x00000006, 0x00000586, 0x00000585, 0x00050085, 0x00000006, 0x00000587, -0x00000584, 0x00000586, 0x00050081, 0x00000006, 0x00000588, 0x00000582, 0x00000587, 0x0003003E, -0x00000538, 0x00000588, 0x000200F9, 0x0000056A, 0x000200F8, 0x0000056A, 0x000200F9, 0x00000546, -0x000200F8, 0x00000546, 0x000200F9, 0x0000053D, 0x000200F8, 0x0000053D, 0x0004003D, 0x00000012, -0x0000058A, 0x0000052D, 0x00050041, 0x00000013, 0x0000058B, 0x00000589, 0x000001E9, 0x0003003E, -0x0000058B, 0x0000058A, 0x0004003D, 0x00000006, 0x0000058C, 0x00000537, 0x00050041, 0x00000007, -0x0000058D, 0x00000589, 0x000001FF, 0x0003003E, 0x0000058D, 0x0000058C, 0x0004003D, 0x00000006, -0x0000058E, 0x00000538, 0x00050041, 0x00000007, 0x0000058F, 0x00000589, 0x0000027E, 0x0003003E, -0x0000058F, 0x0000058E, 0x00050041, 0x000001E1, 0x00000590, 0x000001DF, 0x0000027E, 0x0004003D, -0x00000006, 0x00000591, 0x00000590, 0x00050041, 0x00000007, 0x00000592, 0x00000589, 0x00000260, -0x0003003E, 0x00000592, 0x00000591, 0x00040039, 0x0000000C, 0x00000593, 0x0000007D, 0x00050041, -0x0000000D, 0x00000594, 0x00000589, 0x0000020A, 0x0003003E, 0x00000594, 0x00000593, 0x00040039, -0x00000006, 0x00000595, 0x00000078, 0x00050041, 0x00000007, 0x00000596, 0x00000589, 0x00000228, -0x0003003E, 0x00000596, 0x00000595, 0x00050041, 0x00000013, 0x00000598, 0x00000589, 0x000001E9, -0x0004003D, 0x00000012, 0x00000599, 0x00000598, 0x0008004F, 0x0000000C, 0x0000059A, 0x00000599, -0x00000599, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000597, 0x0000059A, 0x00050039, -0x0000000C, 0x0000059B, 0x0000007B, 0x00000597, 0x00050041, 0x0000000D, 0x0000059C, 0x00000589, -0x000001E0, 0x0003003E, 0x0000059C, 0x0000059B, 0x0004003D, 0x00000012, 0x000005A0, 0x0000059F, -0x0007004F, 0x0000007F, 0x000005A1, 0x000005A0, 0x000005A0, 0x00000000, 0x00000001, 0x00050041, -0x000001E1, 0x000005A3, 0x000002CD, 0x000005A2, 0x0004003D, 0x00000006, 0x000005A4, 0x000005A3, -0x00050041, 0x000001E1, 0x000005A6, 0x000002CD, 0x000005A5, 0x0004003D, 0x00000006, 0x000005A7, -0x000005A6, 0x00050050, 0x0000007F, 0x000005A8, 0x000005A4, 0x000005A7, 0x00050088, 0x0000007F, -0x000005A9, 0x000005A1, 0x000005A8, 0x0003003E, 0x0000059D, 0x000005A9, 0x0004003D, 0x000001F7, -0x000005AC, 0x000005AB, 0x0004003D, 0x0000007F, 0x000005AD, 0x0000059D, 0x00050057, 0x00000012, -0x000005AE, 0x000005AC, 0x000005AD, 0x00050051, 0x00000006, 0x000005AF, 0x000005AE, 0x00000000, -0x0003003E, 0x000005AA, 0x000005AF, 0x0004003D, 0x00000006, 0x000005B0, 0x000005AA, 0x00050041, -0x00000013, 0x000005B1, 0x00000589, 0x000001E9, 0x0004003D, 0x00000012, 0x000005B2, 0x000005B1, -0x0005008E, 0x00000012, 0x000005B3, 0x000005B2, 0x000005B0, 0x00050041, 0x00000013, 0x000005B4, -0x00000589, 0x000001E9, 0x0003003E, 0x000005B4, 0x000005B3, 0x00050041, 0x00000007, 0x000005B5, -0x00000589, 0x0000027E, 0x0004003D, 0x00000006, 0x000005B6, 0x000005B5, 0x0008000C, 0x00000006, -0x000005B8, 0x00000001, 0x0000002B, 0x000005B6, 0x000005B7, 0x000000D5, 0x00050041, 0x00000007, -0x000005B9, 0x00000589, 0x0000027E, 0x0003003E, 0x000005B9, 0x000005B8, 0x00050041, 0x00000007, -0x000005BB, 0x00000589, 0x00000210, 0x0004003D, 0x00000006, 0x000005BC, 0x000005BB, 0x0003003E, -0x000005BA, 0x000005BC, 0x00050039, 0x00000006, 0x000005BD, 0x00000057, 0x000005BA, 0x00050041, -0x00000007, 0x000005BE, 0x00000589, 0x00000210, 0x0003003E, 0x000005BE, 0x000005BD, 0x0004003D, -0x00000006, 0x000005C0, 0x00000538, 0x0004003D, 0x00000006, 0x000005C1, 0x00000538, 0x00050085, -0x00000006, 0x000005C2, 0x000005C0, 0x000005C1, 0x0003003E, 0x000005BF, 0x000005C2, 0x00050041, -0x0000000D, 0x000005C4, 0x00000589, 0x0000020A, 0x0004003D, 0x0000000C, 0x000005C5, 0x000005C4, -0x000400CF, 0x0000000C, 0x000005C6, 0x000005C5, 0x0003003E, 0x000005C3, 0x000005C6, 0x00050041, -0x0000000D, 0x000005C8, 0x00000589, 0x0000020A, 0x0004003D, 0x0000000C, 0x000005C9, 0x000005C8, -0x000400D0, 0x0000000C, 0x000005CA, 0x000005C9, 0x0003003E, 0x000005C7, 0x000005CA, 0x0004003D, -0x0000000C, 0x000005CC, 0x000005C3, 0x0004003D, 0x0000000C, 0x000005CD, 0x000005C3, 0x00050094, -0x00000006, 0x000005CE, 0x000005CC, 0x000005CD, 0x0004003D, 0x0000000C, 0x000005CF, 0x000005C7, -0x0004003D, 0x0000000C, 0x000005D0, 0x000005C7, 0x00050094, 0x00000006, 0x000005D1, 0x000005CF, -0x000005D0, 0x00050081, 0x00000006, 0x000005D2, 0x000005CE, 0x000005D1, 0x0003003E, 0x000005CB, -0x000005D2, 0x0004003D, 0x00000006, 0x000005D4, 0x000005CB, 0x00050085, 0x00000006, 0x000005D5, -0x000005D4, 0x000000D5, 0x0007000C, 0x00000006, 0x000005D7, 0x00000001, 0x00000025, 0x000005D5, -0x000005D6, 0x0003003E, 0x000005D3, 0x000005D7, 0x0004003D, 0x00000006, 0x000005D9, 0x000005BF, -0x0004003D, 0x00000006, 0x000005DA, 0x000005D3, 0x00050081, 0x00000006, 0x000005DB, 0x000005D9, -0x000005DA, 0x0003003E, 0x000005DC, 0x000005DB, 0x00050039, 0x00000006, 0x000005DD, 0x00000019, -0x000005DC, 0x0003003E, 0x000005D8, 0x000005DD, 0x0004003D, 0x00000006, 0x000005DE, 0x000005D8, -0x0006000C, 0x00000006, 0x000005DF, 0x00000001, 0x0000001F, 0x000005DE, 0x00050041, 0x00000007, -0x000005E0, 0x00000589, 0x00000210, 0x0003003E, 0x000005E0, 0x000005DF, 0x00050041, 0x0000059E, -0x000005E2, 0x000001FE, 0x00000210, 0x0004003D, 0x00000012, 0x000005E3, 0x000005E2, 0x0008004F, -0x0000000C, 0x000005E4, 0x000005E3, 0x000005E3, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, -0x000005E1, 0x000005E4, 0x00050041, 0x000001EA, 0x000005E5, 0x000002CD, 0x000001E0, 0x0004003D, -0x00000012, 0x000005E6, 0x000005E5, 0x0008004F, 0x0000000C, 0x000005E7, 0x000005E6, 0x000005E6, -0x00000000, 0x00000001, 0x00000002, 0x0004003D, 0x0000000C, 0x000005E8, 0x000005E1, 0x00050083, -0x0000000C, 0x000005E9, 0x000005E7, 0x000005E8, 0x0006000C, 0x0000000C, 0x000005EA, 0x00000001, -0x00000045, 0x000005E9, 0x00050041, 0x0000000D, 0x000005EB, 0x00000589, 0x00000278, 0x0003003E, -0x000005EB, 0x000005EA, 0x00050041, 0x0000000D, 0x000005EC, 0x00000589, 0x0000020A, 0x0004003D, -0x0000000C, 0x000005ED, 0x000005EC, 0x00050041, 0x0000000D, 0x000005EE, 0x00000589, 0x00000278, -0x0004003D, 0x0000000C, 0x000005EF, 0x000005EE, 0x00050094, 0x00000006, 0x000005F0, 0x000005ED, -0x000005EF, 0x0007000C, 0x00000006, 0x000005F1, 0x00000001, 0x00000028, 0x000005F0, 0x0000018F, -0x00050041, 0x00000007, 0x000005F2, 0x00000589, 0x0000025A, 0x0003003E, 0x000005F2, 0x000005F1, -0x0004003D, 0x000001F7, 0x000005F4, 0x000005F3, 0x00050041, 0x00000007, 0x000005F5, 0x00000589, -0x0000025A, 0x0004003D, 0x00000006, 0x000005F6, 0x000005F5, 0x00050041, 0x00000007, 0x000005F7, -0x00000589, 0x0000027E, 0x0004003D, 0x00000006, 0x000005F8, 0x000005F7, 0x00050050, 0x0000007F, -0x000005F9, 0x000005F6, 0x000005F8, 0x00050057, 0x00000012, 0x000005FA, 0x000005F4, 0x000005F9, -0x0007004F, 0x0000007F, 0x000005FB, 0x000005FA, 0x000005FA, 0x00000000, 0x00000001, 0x00050041, -0x00000080, 0x000005FC, 0x00000589, 0x0000032C, 0x0003003E, 0x000005FC, 0x000005FB, 0x00050041, -0x00000007, 0x000005FF, 0x00000589, 0x00000260, 0x0004003D, 0x00000006, 0x00000600, 0x000005FF, -0x0003003E, 0x000005FE, 0x00000600, 0x00050039, 0x00000006, 0x00000601, 0x00000054, 0x000005FE, -0x0003003E, 0x000005FD, 0x00000601, 0x00050041, 0x00000013, 0x00000603, 0x00000589, 0x000001E9, -0x0004003D, 0x00000012, 0x00000604, 0x00000603, 0x00050041, 0x00000007, 0x00000606, 0x00000589, -0x000001FF, 0x0004003D, 0x00000006, 0x00000607, 0x00000606, 0x0003003E, 0x00000605, 0x00000607, -0x0004003D, 0x00000006, 0x00000609, 0x000005FD, 0x0003003E, 0x00000608, 0x00000609, 0x00070039, -0x0000000C, 0x0000060A, 0x00000051, 0x00000604, 0x00000605, 0x00000608, 0x0003003E, 0x00000602, -0x0000060A, 0x0004003D, 0x0000000C, 0x0000060B, 0x00000602, 0x00050041, 0x0000000D, 0x0000060C, -0x00000589, 0x00000244, 0x0003003E, 0x0000060C, 0x0000060B, 0x00050041, 0x0000000D, 0x0000060D, -0x00000589, 0x00000244, 0x0004003D, 0x0000000C, 0x0000060E, 0x0000060D, 0x00060041, 0x00000007, -0x00000610, 0x00000589, 0x0000032C, 0x00000520, 0x0004003D, 0x00000006, 0x00000611, 0x00000610, -0x0007000C, 0x00000006, 0x00000612, 0x00000001, 0x00000028, 0x0000060F, 0x00000611, 0x00050088, -0x00000006, 0x00000613, 0x000000D5, 0x00000612, 0x00050083, 0x00000006, 0x00000614, 0x00000613, -0x000000D5, 0x0005008E, 0x0000000C, 0x00000615, 0x0000060E, 0x00000614, 0x00060050, 0x0000000C, -0x00000616, 0x000000D5, 0x000000D5, 0x000000D5, 0x00050081, 0x0000000C, 0x00000617, 0x00000616, -0x00000615, 0x00050041, 0x0000000D, 0x00000618, 0x00000589, 0x000003F5, 0x0003003E, 0x00000618, -0x00000617, 0x00050041, 0x00000013, 0x00000619, 0x00000589, 0x000001E9, 0x0004003D, 0x00000012, -0x0000061A, 0x00000619, 0x00050041, 0x00000007, 0x0000061C, 0x00000589, 0x000001FF, 0x0004003D, -0x00000006, 0x0000061D, 0x0000061C, 0x0003003E, 0x0000061B, 0x0000061D, 0x00060039, 0x0000000C, -0x0000061E, 0x0000004B, 0x0000061A, 0x0000061B, 0x00060041, 0x00000007, 0x0000061F, 0x00000589, -0x000001E9, 0x0000023E, 0x00050051, 0x00000006, 0x00000620, 0x0000061E, 0x00000000, 0x0003003E, -0x0000061F, 0x00000620, 0x00060041, 0x00000007, 0x00000621, 0x00000589, 0x000001E9, 0x00000520, -0x00050051, 0x00000006, 0x00000622, 0x0000061E, 0x00000001, 0x0003003E, 0x00000621, 0x00000622, -0x00060041, 0x00000007, 0x00000623, 0x00000589, 0x000001E9, 0x0000030A, 0x00050051, 0x00000006, -0x00000624, 0x0000061E, 0x00000002, 0x0003003E, 0x00000623, 0x00000624, 0x00050041, 0x000001E1, -0x00000626, 0x000002CD, 0x00000278, 0x0004003D, 0x00000006, 0x00000627, 0x00000626, 0x0003003E, -0x00000625, 0x00000627, 0x00050041, 0x000001E1, 0x00000629, 0x000002CD, 0x0000025A, 0x0004003D, -0x00000006, 0x0000062A, 0x00000629, 0x0003003E, 0x00000628, 0x0000062A, 0x00050041, 0x0000031C, -0x0000062C, 0x000002CD, 0x00000210, 0x0004003D, 0x000002C7, 0x0000062D, 0x0000062C, 0x0004003D, -0x0000000C, 0x0000062E, 0x000005E1, 0x00050051, 0x00000006, 0x0000062F, 0x0000062E, 0x00000000, -0x00050051, 0x00000006, 0x00000630, 0x0000062E, 0x00000001, 0x00050051, 0x00000006, 0x00000631, -0x0000062E, 0x00000002, 0x00070050, 0x00000012, 0x00000632, 0x0000062F, 0x00000630, 0x00000631, -0x000000D5, 0x00050091, 0x00000012, 0x00000633, 0x0000062D, 0x00000632, 0x0003003E, 0x0000062B, -0x00000633, 0x0004003D, 0x00000012, 0x00000635, 0x0000062B, 0x0006000C, 0x00000006, 0x00000636, -0x00000001, 0x00000042, 0x00000635, 0x0003003E, 0x00000634, 0x00000636, 0x0004003D, 0x00000006, -0x00000637, 0x00000634, 0x0004003D, 0x00000006, 0x00000638, 0x00000625, 0x0004003D, 0x00000006, -0x00000639, 0x00000628, 0x00050083, 0x00000006, 0x0000063A, 0x00000638, 0x00000639, 0x00050083, -0x00000006, 0x0000063B, 0x00000637, 0x0000063A, 0x0003003E, 0x000000D4, 0x0000063B, 0x0004003D, -0x00000006, 0x0000063C, 0x00000628, 0x0004003D, 0x00000006, 0x0000063D, 0x000000D4, 0x00050088, -0x00000006, 0x0000063E, 0x0000063D, 0x0000063C, 0x0003003E, 0x000000D4, 0x0000063E, 0x0004003D, -0x00000006, 0x0000063F, 0x000000D4, 0x00050083, 0x00000006, 0x00000640, 0x000000D5, 0x0000063F, -0x0008000C, 0x00000006, 0x00000641, 0x00000001, 0x0000002B, 0x00000640, 0x000000F8, 0x000000D5, -0x0003003E, 0x000000D4, 0x00000641, 0x00050041, 0x00000007, 0x00000643, 0x00000589, 0x0000025A, -0x0004003D, 0x00000006, 0x00000644, 0x00000643, 0x00050085, 0x00000006, 0x00000645, 0x00000130, -0x00000644, 0x00050041, 0x0000000D, 0x00000646, 0x00000589, 0x0000020A, 0x0004003D, 0x0000000C, -0x00000647, 0x00000646, 0x0005008E, 0x0000000C, 0x00000648, 0x00000647, 0x00000645, 0x00050041, -0x0000000D, 0x00000649, 0x00000589, 0x00000278, 0x0004003D, 0x0000000C, 0x0000064A, 0x00000649, -0x00050083, 0x0000000C, 0x0000064B, 0x00000648, 0x0000064A, 0x0003003E, 0x00000642, 0x0000064B, -0x00050041, 0x0000000D, 0x0000064E, 0x00000589, 0x00000244, 0x0004003D, 0x0000000C, 0x0000064F, -0x0000064E, 0x0003003E, 0x0000064D, 0x0000064F, 0x0004003D, 0x0000000C, 0x00000651, 0x000005E1, -0x0003003E, 0x00000650, 0x00000651, 0x0004003D, 0x000000AB, 0x00000653, 0x00000589, 0x0003003E, -0x00000652, 0x00000653, 0x00070039, 0x0000000C, 0x00000654, 0x000000CC, 0x0000064D, 0x00000650, -0x00000652, 0x0003003E, 0x0000064C, 0x00000654, 0x00050041, 0x0000000D, 0x00000657, 0x00000589, -0x00000244, 0x0004003D, 0x0000000C, 0x00000658, 0x00000657, 0x0003003E, 0x00000656, 0x00000658, -0x0004003D, 0x0000000C, 0x0000065A, 0x00000642, 0x0003003E, 0x00000659, 0x0000065A, 0x0004003D, -0x000000AB, 0x0000065C, 0x00000589, 0x0003003E, 0x0000065B, 0x0000065C, 0x00070039, 0x0000000C, -0x0000065D, 0x000000D1, 0x00000656, 0x00000659, 0x0000065B, 0x0003003E, 0x00000655, 0x0000065D, -0x0004003D, 0x0000000C, 0x0000065F, 0x0000064C, 0x0004003D, 0x0000000C, 0x00000660, 0x00000655, -0x00050081, 0x0000000C, 0x00000661, 0x0000065F, 0x00000660, 0x00050041, 0x0000000D, 0x00000662, -0x00000589, 0x000001E0, 0x0004003D, 0x0000000C, 0x00000663, 0x00000662, 0x00050081, 0x0000000C, -0x00000664, 0x00000661, 0x00000663, 0x0003003E, 0x0000065E, 0x00000664, 0x0004003D, 0x0000000C, -0x00000667, 0x0000065E, 0x00050051, 0x00000006, 0x00000668, 0x00000667, 0x00000000, 0x00050051, -0x00000006, 0x00000669, 0x00000667, 0x00000001, 0x00050051, 0x00000006, 0x0000066A, 0x00000667, -0x00000002, 0x00070050, 0x00000012, 0x0000066B, 0x00000668, 0x00000669, 0x0000066A, 0x000000D5, -0x0003003E, 0x00000666, 0x0000066B, 0x00050041, 0x0000032D, 0x0000066D, 0x000002CD, 0x0000066C, -0x0004003D, 0x00000085, 0x0000066E, 0x0000066D, 0x000500AD, 0x000001E5, 0x0000066F, 0x0000066E, -0x000001E9, 0x000300F7, 0x00000671, 0x00000000, 0x000400FA, 0x0000066F, 0x00000670, 0x00000671, -0x000200F8, 0x00000670, 0x00050041, 0x0000032D, 0x00000672, 0x000002CD, 0x0000066C, 0x0004003D, -0x00000085, 0x00000673, 0x00000672, 0x000300F7, 0x0000067B, 0x00000000, 0x001100FB, 0x00000673, -0x0000067B, 0x00000001, 0x00000674, 0x00000002, 0x00000675, 0x00000003, 0x00000676, 0x00000004, -0x00000677, 0x00000005, 0x00000678, 0x00000006, 0x00000679, 0x00000007, 0x0000067A, 0x000200F8, -0x00000674, 0x00050041, 0x00000013, 0x0000067C, 0x00000589, 0x000001E9, 0x0004003D, 0x00000012, -0x0000067D, 0x0000067C, 0x0003003E, 0x00000666, 0x0000067D, 0x000200F9, 0x0000067B, 0x000200F8, -0x00000675, 0x00050041, 0x00000007, 0x0000067F, 0x00000589, 0x000001FF, 0x0004003D, 0x00000006, -0x00000680, 0x0000067F, 0x00060050, 0x0000000C, 0x00000681, 0x00000680, 0x00000680, 0x00000680, -0x00050051, 0x00000006, 0x00000682, 0x00000681, 0x00000000, 0x00050051, 0x00000006, 0x00000683, -0x00000681, 0x00000001, 0x00050051, 0x00000006, 0x00000684, 0x00000681, 0x00000002, 0x00070050, -0x00000012, 0x00000685, 0x00000682, 0x00000683, 0x00000684, 0x000000D5, 0x0003003E, 0x00000666, -0x00000685, 0x000200F9, 0x0000067B, 0x000200F8, 0x00000676, 0x00050041, 0x00000007, 0x00000687, -0x00000589, 0x0000027E, 0x0004003D, 0x00000006, 0x00000688, 0x00000687, 0x00060050, 0x0000000C, -0x00000689, 0x00000688, 0x00000688, 0x00000688, 0x00050051, 0x00000006, 0x0000068A, 0x00000689, -0x00000000, 0x00050051, 0x00000006, 0x0000068B, 0x00000689, 0x00000001, 0x00050051, 0x00000006, -0x0000068C, 0x00000689, 0x00000002, 0x00070050, 0x00000012, 0x0000068D, 0x0000068A, 0x0000068B, -0x0000068C, 0x000000D5, 0x0003003E, 0x00000666, 0x0000068D, 0x000200F9, 0x0000067B, 0x000200F8, -0x00000677, 0x00050041, 0x00000007, 0x0000068F, 0x00000589, 0x00000228, 0x0004003D, 0x00000006, -0x00000690, 0x0000068F, 0x00060050, 0x0000000C, 0x00000691, 0x00000690, 0x00000690, 0x00000690, -0x00050051, 0x00000006, 0x00000692, 0x00000691, 0x00000000, 0x00050051, 0x00000006, 0x00000693, -0x00000691, 0x00000001, 0x00050051, 0x00000006, 0x00000694, 0x00000691, 0x00000002, 0x00070050, -0x00000012, 0x00000695, 0x00000692, 0x00000693, 0x00000694, 0x000000D5, 0x0003003E, 0x00000666, -0x00000695, 0x000200F9, 0x0000067B, 0x000200F8, 0x00000678, 0x00050041, 0x0000000D, 0x00000697, -0x00000589, 0x000001E0, 0x0004003D, 0x0000000C, 0x00000698, 0x00000697, 0x00050051, 0x00000006, -0x00000699, 0x00000698, 0x00000000, 0x00050051, 0x00000006, 0x0000069A, 0x00000698, 0x00000001, -0x00050051, 0x00000006, 0x0000069B, 0x00000698, 0x00000002, 0x00070050, 0x00000012, 0x0000069C, -0x00000699, 0x0000069A, 0x0000069B, 0x000000D5, 0x0003003E, 0x00000666, 0x0000069C, 0x000200F9, -0x0000067B, 0x000200F8, 0x00000679, 0x00050041, 0x0000000D, 0x0000069E, 0x00000589, 0x0000020A, -0x0004003D, 0x0000000C, 0x0000069F, 0x0000069E, 0x00050051, 0x00000006, 0x000006A0, 0x0000069F, -0x00000000, 0x00050051, 0x00000006, 0x000006A1, 0x0000069F, 0x00000001, 0x00050051, 0x00000006, -0x000006A2, 0x0000069F, 0x00000002, 0x00070050, 0x00000012, 0x000006A3, 0x000006A0, 0x000006A1, -0x000006A2, 0x000000D5, 0x0003003E, 0x00000666, 0x000006A3, 0x000200F9, 0x0000067B, 0x000200F8, -0x0000067A, 0x0004003D, 0x0000000C, 0x000006A7, 0x000005E1, 0x0003003E, 0x000006A6, 0x000006A7, -0x00050039, 0x00000085, 0x000006A8, 0x000000A2, 0x000006A6, 0x0003003E, 0x000006A5, 0x000006A8, -0x0004003D, 0x00000085, 0x000006A9, 0x000006A5, 0x000300F7, 0x000006AE, 0x00000000, 0x000B00FB, -0x000006A9, 0x000006AE, 0x00000000, 0x000006AA, 0x00000001, 0x000006AB, 0x00000002, 0x000006AC, -0x00000003, 0x000006AD, 0x000200F8, 0x000006AA, 0x0004003D, 0x00000012, 0x000006AF, 0x00000666, -0x00050085, 0x00000012, 0x000006B3, 0x000006AF, 0x000006B2, 0x0003003E, 0x00000666, 0x000006B3, -0x000200F9, 0x000006AE, 0x000200F8, 0x000006AB, 0x0004003D, 0x00000012, 0x000006B5, 0x00000666, -0x00050085, 0x00000012, 0x000006B7, 0x000006B5, 0x000006B6, 0x0003003E, 0x00000666, 0x000006B7, -0x000200F9, 0x000006AE, 0x000200F8, 0x000006AC, 0x0004003D, 0x00000012, 0x000006B9, 0x00000666, -0x00050085, 0x00000012, 0x000006BB, 0x000006B9, 0x000006BA, 0x0003003E, 0x00000666, 0x000006BB, -0x000200F9, 0x000006AE, 0x000200F8, 0x000006AD, 0x0004003D, 0x00000012, 0x000006BD, 0x00000666, -0x00050085, 0x00000012, 0x000006BF, 0x000006BD, 0x000006BE, 0x0003003E, 0x00000666, 0x000006BF, -0x000200F9, 0x000006AE, 0x000200F8, 0x000006AE, 0x000200F9, 0x0000067B, 0x000200F8, 0x0000067B, -0x000200F9, 0x00000671, 0x000200F8, 0x00000671, 0x000100FD, 0x00010038, 0x00050036, 0x00000006, -0x0000000A, 0x00000000, 0x00000008, 0x00030037, 0x00000007, 0x00000009, 0x000200F8, 0x0000000B, -0x0004003B, 0x00000007, 0x000000D8, 0x00000007, 0x0004003D, 0x00000006, 0x000000D9, 0x00000009, -0x0004003D, 0x00000006, 0x000000DA, 0x00000009, 0x00050085, 0x00000006, 0x000000DB, 0x000000D9, -0x000000DA, 0x0003003E, 0x000000D8, 0x000000DB, 0x0004003D, 0x00000006, 0x000000DC, 0x000000D8, -0x0004003D, 0x00000006, 0x000000DD, 0x000000D8, 0x00050085, 0x00000006, 0x000000DE, 0x000000DC, -0x000000DD, 0x0004003D, 0x00000006, 0x000000DF, 0x00000009, 0x00050085, 0x00000006, 0x000000E0, -0x000000DE, 0x000000DF, 0x000200FE, 0x000000E0, 0x00010038, 0x00050036, 0x0000000C, 0x00000010, -0x00000000, 0x0000000E, 0x00030037, 0x0000000D, 0x0000000F, 0x000200F8, 0x00000011, 0x0004003D, -0x0000000C, 0x000000E3, 0x0000000F, 0x0007000C, 0x0000000C, 0x000000E6, 0x00000001, 0x0000001A, -0x000000E3, 0x000000E5, 0x000200FE, 0x000000E6, 0x00010038, 0x00050036, 0x00000012, 0x00000016, -0x00000000, 0x00000014, 0x00030037, 0x00000013, 0x00000015, 0x000200F8, 0x00000017, 0x0004003B, -0x0000000D, 0x000000E9, 0x00000007, 0x0004003D, 0x00000012, 0x000000EA, 0x00000015, 0x0008004F, -0x0000000C, 0x000000EB, 0x000000EA, 0x000000EA, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, -0x000000E9, 0x000000EB, 0x00050039, 0x0000000C, 0x000000EC, 0x00000010, 0x000000E9, 0x00050041, -0x00000007, 0x000000EF, 0x00000015, 0x000000EE, 0x0004003D, 0x00000006, 0x000000F0, 0x000000EF, -0x00050051, 0x00000006, 0x000000F1, 0x000000EC, 0x00000000, 0x00050051, 0x00000006, 0x000000F2, -0x000000EC, 0x00000001, 0x00050051, 0x00000006, 0x000000F3, 0x000000EC, 0x00000002, 0x00070050, -0x00000012, 0x000000F4, 0x000000F1, 0x000000F2, 0x000000F3, 0x000000F0, 0x000200FE, 0x000000F4, -0x00010038, 0x00050036, 0x00000006, 0x00000019, 0x00000000, 0x00000008, 0x00030037, 0x00000007, -0x00000018, 0x000200F8, 0x0000001A, 0x0004003D, 0x00000006, 0x000000F7, 0x00000018, 0x0008000C, -0x00000006, 0x000000F9, 0x00000001, 0x0000002B, 0x000000F7, 0x000000F8, 0x000000D5, 0x000200FE, -0x000000F9, 0x00010038, 0x00050036, 0x00000006, 0x00000020, 0x00000000, 0x0000001B, 0x00030037, -0x00000007, 0x0000001C, 0x00030037, 0x00000007, 0x0000001D, 0x00030037, 0x0000000C, 0x0000001E, -0x00030037, 0x0000000C, 0x0000001F, 0x000200F8, 0x00000021, 0x0004003B, 0x0000000D, 0x000000FC, -0x00000007, 0x0004003B, 0x00000007, 0x000000FE, 0x00000007, 0x0004003B, 0x00000007, 0x00000102, -0x00000007, 0x0004003B, 0x00000007, 0x0000010C, 0x00000007, 0x0007000C, 0x0000000C, 0x000000FD, -0x00000001, 0x00000044, 0x0000001E, 0x0000001F, 0x0003003E, 0x000000FC, 0x000000FD, 0x0004003D, -0x00000006, 0x000000FF, 0x0000001D, 0x0004003D, 0x00000006, 0x00000100, 0x0000001C, 0x00050085, -0x00000006, 0x00000101, 0x000000FF, 0x00000100, 0x0003003E, 0x000000FE, 0x00000101, 0x0004003D, -0x00000006, 0x00000103, 0x0000001C, 0x0004003D, 0x0000000C, 0x00000104, 0x000000FC, 0x0004003D, -0x0000000C, 0x00000105, 0x000000FC, 0x00050094, 0x00000006, 0x00000106, 0x00000104, 0x00000105, -0x0004003D, 0x00000006, 0x00000107, 0x000000FE, 0x0004003D, 0x00000006, 0x00000108, 0x000000FE, -0x00050085, 0x00000006, 0x00000109, 0x00000107, 0x00000108, 0x00050081, 0x00000006, 0x0000010A, -0x00000106, 0x00000109, 0x00050088, 0x00000006, 0x0000010B, 0x00000103, 0x0000010A, 0x0003003E, -0x00000102, 0x0000010B, 0x0004003D, 0x00000006, 0x0000010D, 0x00000102, 0x0004003D, 0x00000006, -0x0000010E, 0x00000102, 0x00050085, 0x00000006, 0x0000010F, 0x0000010D, 0x0000010E, 0x00050085, -0x00000006, 0x00000111, 0x0000010F, 0x00000110, 0x0003003E, 0x0000010C, 0x00000111, 0x0004003D, -0x00000006, 0x00000112, 0x0000010C, 0x0007000C, 0x00000006, 0x00000114, 0x00000001, 0x00000025, -0x00000112, 0x00000113, 0x000200FE, 0x00000114, 0x00010038, 0x00050036, 0x0000000C, 0x00000026, -0x00000000, 0x00000022, 0x00030037, 0x0000000C, 0x00000023, 0x00030037, 0x00000007, 0x00000024, -0x00030037, 0x00000007, 0x00000025, 0x000200F8, 0x00000027, 0x0004003B, 0x00000007, 0x0000011C, -0x00000007, 0x0004003D, 0x00000006, 0x00000117, 0x00000024, 0x00060050, 0x0000000C, 0x00000118, -0x00000117, 0x00000117, 0x00000117, 0x00050083, 0x0000000C, 0x00000119, 0x00000118, 0x00000023, -0x0004003D, 0x00000006, 0x0000011A, 0x00000025, 0x00050083, 0x00000006, 0x0000011B, 0x000000D5, -0x0000011A, 0x0003003E, 0x0000011C, 0x0000011B, 0x00050039, 0x00000006, 0x0000011D, 0x0000000A, -0x0000011C, 0x0005008E, 0x0000000C, 0x0000011E, 0x00000119, 0x0000011D, 0x00050081, 0x0000000C, -0x0000011F, 0x00000023, 0x0000011E, 0x000200FE, 0x0000011F, 0x00010038, 0x00050036, 0x00000006, -0x0000002C, 0x00000000, 0x00000028, 0x00030037, 0x00000007, 0x00000029, 0x00030037, 0x00000007, -0x0000002A, 0x00030037, 0x00000007, 0x0000002B, 0x000200F8, 0x0000002D, 0x0004003D, 0x00000006, -0x00000122, 0x0000002A, 0x0004003D, 0x00000006, 0x00000123, 0x0000002B, 0x0004003D, 0x00000006, -0x00000124, 0x0000002A, 0x00050083, 0x00000006, 0x00000125, 0x00000123, 0x00000124, 0x0004003D, -0x00000006, 0x00000126, 0x00000029, 0x00050083, 0x00000006, 0x00000127, 0x000000D5, 0x00000126, -0x0007000C, 0x00000006, 0x00000129, 0x00000001, 0x0000001A, 0x00000127, 0x00000128, 0x00050085, -0x00000006, 0x0000012A, 0x00000125, 0x00000129, 0x00050081, 0x00000006, 0x0000012B, 0x00000122, -0x0000012A, 0x000200FE, 0x0000012B, 0x00010038, 0x00050036, 0x00000006, 0x00000033, 0x00000000, -0x0000002E, 0x00030037, 0x00000007, 0x0000002F, 0x00030037, 0x00000007, 0x00000030, 0x00030037, -0x00000007, 0x00000031, 0x00030037, 0x00000007, 0x00000032, 0x000200F8, 0x00000034, 0x0004003B, -0x00000007, 0x0000012E, 0x00000007, 0x0004003B, 0x00000007, 0x00000138, 0x00000007, 0x0004003B, -0x00000007, 0x00000139, 0x00000007, 0x0004003B, 0x00000007, 0x0000013A, 0x00000007, 0x0004003B, -0x00000007, 0x0000013C, 0x00000007, 0x0004003B, 0x00000007, 0x0000013F, 0x00000007, 0x0004003B, -0x00000007, 0x00000140, 0x00000007, 0x0004003B, 0x00000007, 0x00000141, 0x00000007, 0x0004003B, -0x00000007, 0x00000143, 0x00000007, 0x0004003D, 0x00000006, 0x00000131, 0x0000002F, 0x00050085, -0x00000006, 0x00000132, 0x00000130, 0x00000131, 0x0004003D, 0x00000006, 0x00000133, 0x00000032, -0x00050085, 0x00000006, 0x00000134, 0x00000132, 0x00000133, 0x0004003D, 0x00000006, 0x00000135, -0x00000032, 0x00050085, 0x00000006, 0x00000136, 0x00000134, 0x00000135, 0x00050081, 0x00000006, -0x00000137, 0x0000012F, 0x00000136, 0x0003003E, 0x0000012E, 0x00000137, 0x0003003E, 0x00000139, -0x000000D5, 0x0004003D, 0x00000006, 0x0000013B, 0x0000012E, 0x0003003E, 0x0000013A, 0x0000013B, -0x0004003D, 0x00000006, 0x0000013D, 0x00000031, 0x0003003E, 0x0000013C, 0x0000013D, 0x00070039, -0x00000006, 0x0000013E, 0x0000002C, 0x00000139, 0x0000013A, 0x0000013C, 0x0003003E, 0x00000138, -0x0000013E, 0x0003003E, 0x00000140, 0x000000D5, 0x0004003D, 0x00000006, 0x00000142, 0x0000012E, -0x0003003E, 0x00000141, 0x00000142, 0x0004003D, 0x00000006, 0x00000144, 0x00000030, 0x0003003E, -0x00000143, 0x00000144, 0x00070039, 0x00000006, 0x00000145, 0x0000002C, 0x00000140, 0x00000141, -0x00000143, 0x0003003E, 0x0000013F, 0x00000145, 0x0004003D, 0x00000006, 0x00000146, 0x00000138, -0x0004003D, 0x00000006, 0x00000147, 0x0000013F, 0x00050085, 0x00000006, 0x00000148, 0x00000146, -0x00000147, 0x00050085, 0x00000006, 0x00000149, 0x00000148, 0x00000110, 0x000200FE, 0x00000149, -0x00010038, 0x00050036, 0x00000006, 0x00000038, 0x00000000, 0x00000028, 0x00030037, 0x00000007, -0x00000035, 0x00030037, 0x00000007, 0x00000036, 0x00030037, 0x00000007, 0x00000037, 0x000200F8, -0x00000039, 0x0004003B, 0x00000007, 0x0000014C, 0x00000007, 0x0004003B, 0x00000007, 0x00000150, -0x00000007, 0x0004003B, 0x00000007, 0x0000015E, 0x00000007, 0x0004003D, 0x00000006, 0x0000014D, -0x00000037, 0x0004003D, 0x00000006, 0x0000014E, 0x00000037, 0x00050085, 0x00000006, 0x0000014F, -0x0000014D, 0x0000014E, 0x0003003E, 0x0000014C, 0x0000014F, 0x0004003D, 0x00000006, 0x00000151, -0x00000035, 0x0004003D, 0x00000006, 0x00000152, 0x00000036, 0x0004007F, 0x00000006, 0x00000153, -0x00000152, 0x0004003D, 0x00000006, 0x00000154, 0x0000014C, 0x00050085, 0x00000006, 0x00000155, -0x00000153, 0x00000154, 0x0004003D, 0x00000006, 0x00000156, 0x00000036, 0x00050081, 0x00000006, -0x00000157, 0x00000155, 0x00000156, 0x0004003D, 0x00000006, 0x00000158, 0x00000036, 0x00050085, -0x00000006, 0x00000159, 0x00000157, 0x00000158, 0x0004003D, 0x00000006, 0x0000015A, 0x0000014C, -0x00050081, 0x00000006, 0x0000015B, 0x00000159, 0x0000015A, 0x0006000C, 0x00000006, 0x0000015C, -0x00000001, 0x0000001F, 0x0000015B, 0x00050085, 0x00000006, 0x0000015D, 0x00000151, 0x0000015C, -0x0003003E, 0x00000150, 0x0000015D, 0x0004003D, 0x00000006, 0x0000015F, 0x00000036, 0x0004003D, -0x00000006, 0x00000160, 0x00000035, 0x0004007F, 0x00000006, 0x00000161, 0x00000160, 0x0004003D, -0x00000006, 0x00000162, 0x0000014C, 0x00050085, 0x00000006, 0x00000163, 0x00000161, 0x00000162, -0x0004003D, 0x00000006, 0x00000164, 0x00000035, 0x00050081, 0x00000006, 0x00000165, 0x00000163, -0x00000164, 0x0004003D, 0x00000006, 0x00000166, 0x00000035, 0x00050085, 0x00000006, 0x00000167, -0x00000165, 0x00000166, 0x0004003D, 0x00000006, 0x00000168, 0x0000014C, 0x00050081, 0x00000006, -0x00000169, 0x00000167, 0x00000168, 0x0006000C, 0x00000006, 0x0000016A, 0x00000001, 0x0000001F, -0x00000169, 0x00050085, 0x00000006, 0x0000016B, 0x0000015F, 0x0000016A, 0x0003003E, 0x0000015E, -0x0000016B, 0x0004003D, 0x00000006, 0x0000016C, 0x0000015E, 0x0004003D, 0x00000006, 0x0000016D, -0x00000150, 0x00050081, 0x00000006, 0x0000016E, 0x0000016C, 0x0000016D, 0x00050088, 0x00000006, -0x0000016F, 0x0000012F, 0x0000016E, 0x000200FE, 0x0000016F, 0x00010038, 0x00050036, 0x00000006, -0x0000003D, 0x00000000, 0x0000003A, 0x00030037, 0x00000007, 0x0000003B, 0x00030037, 0x00000007, -0x0000003C, 0x000200F8, 0x0000003E, 0x0004003B, 0x00000007, 0x00000172, 0x00000007, 0x0004003B, -0x00000007, 0x00000178, 0x00000007, 0x0004003B, 0x00000007, 0x0000017C, 0x00000007, 0x0004003D, -0x00000006, 0x00000173, 0x0000003C, 0x0007000C, 0x00000006, 0x00000175, 0x00000001, 0x00000025, -0x00000173, 0x00000174, 0x00050083, 0x00000006, 0x00000176, 0x000000D5, 0x00000175, 0x0006000C, -0x00000006, 0x00000177, 0x00000001, 0x00000020, 0x00000176, 0x0003003E, 0x00000172, 0x00000177, -0x0004003D, 0x00000006, 0x00000179, 0x0000003B, 0x0004003D, 0x00000006, 0x0000017A, 0x00000172, -0x00050085, 0x00000006, 0x0000017B, 0x00000179, 0x0000017A, 0x0003003E, 0x0000017C, 0x0000017B, -0x00050039, 0x00000006, 0x0000017D, 0x00000019, 0x0000017C, 0x0003003E, 0x00000178, 0x0000017D, -0x0004003D, 0x00000006, 0x0000017E, 0x00000178, 0x0004003D, 0x00000006, 0x0000017F, 0x00000178, -0x00050085, 0x00000006, 0x00000180, 0x0000017E, 0x0000017F, 0x000200FE, 0x00000180, 0x00010038, -0x00050036, 0x00000006, 0x00000043, 0x00000000, 0x0000002E, 0x00030037, 0x00000007, 0x0000003F, -0x00030037, 0x00000007, 0x00000040, 0x00030037, 0x00000007, 0x00000041, 0x00030037, 0x00000007, -0x00000042, 0x000200F8, 0x00000044, 0x0004003B, 0x00000007, 0x00000183, 0x00000007, 0x0004003B, -0x00000007, 0x00000185, 0x00000007, 0x0004003B, 0x00000007, 0x00000187, 0x00000007, 0x0004003B, -0x00000007, 0x00000189, 0x00000007, 0x0004003D, 0x00000006, 0x00000184, 0x0000003F, 0x0003003E, -0x00000183, 0x00000184, 0x0004003D, 0x00000006, 0x00000186, 0x00000040, 0x0003003E, 0x00000185, -0x00000186, 0x0004003D, 0x00000006, 0x00000188, 0x00000041, 0x0003003E, 0x00000187, 0x00000188, -0x0004003D, 0x00000006, 0x0000018A, 0x00000042, 0x0003003E, 0x00000189, 0x0000018A, 0x00080039, -0x00000006, 0x0000018B, 0x00000033, 0x00000183, 0x00000185, 0x00000187, 0x00000189, 0x000200FE, -0x0000018B, 0x00010038, 0x00050036, 0x00000006, 0x00000046, 0x00000000, 0x00000008, 0x00030037, -0x00000007, 0x00000045, 0x000200F8, 0x00000047, 0x0004003D, 0x00000006, 0x0000018E, 0x00000045, -0x0007000C, 0x00000006, 0x00000190, 0x00000001, 0x00000028, 0x0000018E, 0x0000018F, 0x000200FE, -0x00000190, 0x00010038, 0x00050036, 0x0000000C, 0x0000004B, 0x00000000, 0x00000048, 0x00030037, -0x00000012, 0x00000049, 0x00030037, 0x00000007, 0x0000004A, 0x000200F8, 0x0000004C, 0x0008004F, -0x0000000C, 0x00000193, 0x00000049, 0x00000049, 0x00000000, 0x00000001, 0x00000002, 0x0004003D, -0x00000006, 0x00000194, 0x0000004A, 0x00050083, 0x00000006, 0x00000195, 0x000000D5, 0x00000194, -0x0005008E, 0x0000000C, 0x00000196, 0x00000193, 0x00000195, 0x000200FE, 0x00000196, 0x00010038, -0x00050036, 0x0000000C, 0x00000051, 0x00000000, 0x0000004D, 0x00030037, 0x00000012, 0x0000004E, -0x00030037, 0x00000007, 0x0000004F, 0x00030037, 0x00000007, 0x00000050, 0x000200F8, 0x00000052, -0x0008004F, 0x0000000C, 0x00000199, 0x0000004E, 0x0000004E, 0x00000000, 0x00000001, 0x00000002, -0x0004003D, 0x00000006, 0x0000019A, 0x0000004F, 0x0005008E, 0x0000000C, 0x0000019B, 0x00000199, -0x0000019A, 0x0004003D, 0x00000006, 0x0000019C, 0x00000050, 0x0004003D, 0x00000006, 0x0000019D, -0x0000004F, 0x00050083, 0x00000006, 0x0000019E, 0x000000D5, 0x0000019D, 0x00050085, 0x00000006, -0x0000019F, 0x0000019C, 0x0000019E, 0x00060050, 0x0000000C, 0x000001A0, 0x0000019F, 0x0000019F, -0x0000019F, 0x00050081, 0x0000000C, 0x000001A1, 0x0000019B, 0x000001A0, 0x000200FE, 0x000001A1, -0x00010038, 0x00050036, 0x00000006, 0x00000054, 0x00000000, 0x00000008, 0x00030037, 0x00000007, -0x00000053, 0x000200F8, 0x00000055, 0x0004003D, 0x00000006, 0x000001A5, 0x00000053, 0x00050085, -0x00000006, 0x000001A6, 0x000001A4, 0x000001A5, 0x0004003D, 0x00000006, 0x000001A7, 0x00000053, -0x00050085, 0x00000006, 0x000001A8, 0x000001A6, 0x000001A7, 0x000200FE, 0x000001A8, 0x00010038, -0x00050036, 0x00000006, 0x00000057, 0x00000000, 0x00000008, 0x00030037, 0x00000007, 0x00000056, -0x000200F8, 0x00000058, 0x0004003D, 0x00000006, 0x000001AB, 0x00000056, 0x0004003D, 0x00000006, -0x000001AC, 0x00000056, 0x00050085, 0x00000006, 0x000001AD, 0x000001AB, 0x000001AC, 0x000200FE, -0x000001AD, 0x00010038, 0x00050036, 0x00000006, 0x0000005D, 0x00000000, 0x0000001B, 0x00030037, -0x00000007, 0x00000059, 0x00030037, 0x00000007, 0x0000005A, 0x00030037, 0x0000000C, 0x0000005B, -0x00030037, 0x0000000C, 0x0000005C, 0x000200F8, 0x0000005E, 0x0004003B, 0x00000007, 0x000001B0, -0x00000007, 0x0004003B, 0x00000007, 0x000001B2, 0x00000007, 0x0004003D, 0x00000006, 0x000001B1, -0x00000059, 0x0003003E, 0x000001B0, 0x000001B1, 0x0004003D, 0x00000006, 0x000001B3, 0x0000005A, -0x0003003E, 0x000001B2, 0x000001B3, 0x00080039, 0x00000006, 0x000001B4, 0x00000020, 0x000001B0, -0x000001B2, 0x0000005C, 0x0000005B, 0x000200FE, 0x000001B4, 0x00010038, 0x00050036, 0x00000006, -0x00000062, 0x00000000, 0x00000028, 0x00030037, 0x00000007, 0x0000005F, 0x00030037, 0x00000007, -0x00000060, 0x00030037, 0x00000007, 0x00000061, 0x000200F8, 0x00000063, 0x0004003B, 0x00000007, -0x000001B7, 0x00000007, 0x0004003B, 0x00000007, 0x000001B9, 0x00000007, 0x0004003B, 0x00000007, -0x000001BB, 0x00000007, 0x0004003D, 0x00000006, 0x000001B8, 0x0000005F, 0x0003003E, 0x000001B7, -0x000001B8, 0x0004003D, 0x00000006, 0x000001BA, 0x00000060, 0x0003003E, 0x000001B9, 0x000001BA, -0x0004003D, 0x00000006, 0x000001BC, 0x00000061, 0x0003003E, 0x000001BB, 0x000001BC, 0x00070039, -0x00000006, 0x000001BD, 0x00000038, 0x000001B7, 0x000001B9, 0x000001BB, 0x000200FE, 0x000001BD, -0x00010038, 0x00050036, 0x0000000C, 0x00000067, 0x00000000, 0x00000064, 0x00030037, 0x0000000C, -0x00000065, 0x00030037, 0x00000007, 0x00000066, 0x000200F8, 0x00000068, 0x0004003B, 0x00000007, -0x000001C0, 0x00000007, 0x0004003B, 0x00000007, 0x000001C4, 0x00000007, 0x0004003B, 0x00000007, -0x000001C6, 0x00000007, 0x0004003B, 0x00000007, 0x000001C8, 0x00000007, 0x00050094, 0x00000006, -0x000001C3, 0x00000065, 0x000001C2, 0x0003003E, 0x000001C4, 0x000001C3, 0x00050039, 0x00000006, -0x000001C5, 0x00000019, 0x000001C4, 0x0003003E, 0x000001C0, 0x000001C5, 0x0004003D, 0x00000006, -0x000001C7, 0x000001C0, 0x0003003E, 0x000001C6, 0x000001C7, 0x0004003D, 0x00000006, 0x000001C9, -0x00000066, 0x0003003E, 0x000001C8, 0x000001C9, 0x00070039, 0x0000000C, 0x000001CA, 0x00000026, -0x00000065, 0x000001C6, 0x000001C8, 0x000200FE, 0x000001CA, 0x00010038, 0x00050036, 0x0000000C, -0x0000006D, 0x00000000, 0x00000069, 0x00030037, 0x0000000D, 0x0000006A, 0x00030037, 0x00000007, -0x0000006B, 0x00030037, 0x00000007, 0x0000006C, 0x000200F8, 0x0000006E, 0x0004003D, 0x0000000C, -0x000001CD, 0x0000006A, 0x0004003D, 0x00000006, 0x000001CE, 0x0000006C, 0x00050083, 0x00000006, -0x000001CF, 0x000000D5, 0x000001CE, 0x00060050, 0x0000000C, 0x000001D0, 0x000001CF, 0x000001CF, -0x000001CF, 0x0004003D, 0x0000000C, 0x000001D1, 0x0000006A, 0x0007000C, 0x0000000C, 0x000001D2, -0x00000001, 0x00000028, 0x000001D0, 0x000001D1, 0x0004003D, 0x0000000C, 0x000001D3, 0x0000006A, -0x00050083, 0x0000000C, 0x000001D4, 0x000001D2, 0x000001D3, 0x0004003D, 0x00000006, 0x000001D5, -0x0000006B, 0x00050083, 0x00000006, 0x000001D6, 0x000000D5, 0x000001D5, 0x0007000C, 0x00000006, -0x000001D7, 0x00000001, 0x00000028, 0x000001D6, 0x000000F8, 0x0007000C, 0x00000006, 0x000001D8, -0x00000001, 0x0000001A, 0x000001D7, 0x00000128, 0x0005008E, 0x0000000C, 0x000001D9, 0x000001D4, -0x000001D8, 0x00050081, 0x0000000C, 0x000001DA, 0x000001CD, 0x000001D9, 0x000200FE, 0x000001DA, -0x00010038, 0x00050036, 0x00000012, 0x00000070, 0x00000000, 0x0000006F, 0x000200F8, 0x00000071, -0x0004003B, 0x00000013, 0x00000204, 0x00000007, 0x00050041, 0x000001E1, 0x000001E2, 0x000001DF, -0x000001E0, 0x0004003D, 0x00000006, 0x000001E3, 0x000001E2, 0x000500B8, 0x000001E5, 0x000001E6, -0x000001E3, 0x000001E4, 0x000300F7, 0x000001E8, 0x00000000, 0x000400FA, 0x000001E6, 0x000001E7, -0x000001E8, 0x000200F8, 0x000001E7, 0x00050041, 0x000001EA, 0x000001EB, 0x000001DF, 0x000001E9, -0x0004003D, 0x00000012, 0x000001EC, 0x000001EB, 0x000200FE, 0x000001EC, 0x000200F8, 0x000001E8, -0x00050041, 0x000001E1, 0x000001EE, 0x000001DF, 0x000001E0, 0x0004003D, 0x00000006, 0x000001EF, -0x000001EE, 0x00050083, 0x00000006, 0x000001F0, 0x000000D5, 0x000001EF, 0x00050041, 0x000001EA, -0x000001F1, 0x000001DF, 0x000001E9, 0x0004003D, 0x00000012, 0x000001F2, 0x000001F1, 0x0005008E, -0x00000012, 0x000001F3, 0x000001F2, 0x000001F0, 0x00050041, 0x000001E1, 0x000001F4, 0x000001DF, -0x000001E0, 0x0004003D, 0x00000006, 0x000001F5, 0x000001F4, 0x0004003D, 0x000001F7, 0x000001FA, -0x000001F9, 0x00050041, 0x00000200, 0x00000201, 0x000001FE, 0x000001FF, 0x0004003D, 0x0000007F, -0x00000202, 0x00000201, 0x00050057, 0x00000012, 0x00000203, 0x000001FA, 0x00000202, 0x0003003E, -0x00000204, 0x00000203, 0x00050039, 0x00000012, 0x00000205, 0x00000016, 0x00000204, 0x0005008E, -0x00000012, 0x00000206, 0x00000205, 0x000001F5, 0x00050081, 0x00000012, 0x00000207, 0x000001F3, -0x00000206, 0x000200FE, 0x00000207, 0x00010038, 0x00050036, 0x0000000C, 0x00000073, 0x00000000, -0x00000072, 0x000200F8, 0x00000074, 0x00050041, 0x000001E1, 0x0000020B, 0x000001DF, 0x0000020A, -0x0004003D, 0x00000006, 0x0000020C, 0x0000020B, 0x000500B8, 0x000001E5, 0x0000020D, 0x0000020C, -0x000001E4, 0x000300F7, 0x0000020F, 0x00000000, 0x000400FA, 0x0000020D, 0x0000020E, 0x0000020F, -0x000200F8, 0x0000020E, 0x00050041, 0x000001E1, 0x00000211, 0x000001DF, 0x00000210, 0x0004003D, -0x00000006, 0x00000212, 0x00000211, 0x00060050, 0x0000000C, 0x00000213, 0x00000212, 0x00000212, -0x00000212, 0x000200FE, 0x00000213, 0x000200F8, 0x0000020F, 0x00050041, 0x000001E1, 0x00000215, -0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, 0x00000216, 0x00000215, 0x00050083, 0x00000006, -0x00000217, 0x000000D5, 0x00000216, 0x00050041, 0x000001E1, 0x00000218, 0x000001DF, 0x00000210, -0x0004003D, 0x00000006, 0x00000219, 0x00000218, 0x00050085, 0x00000006, 0x0000021A, 0x00000217, -0x00000219, 0x00050041, 0x000001E1, 0x0000021B, 0x000001DF, 0x0000020A, 0x0004003D, 0x00000006, -0x0000021C, 0x0000021B, 0x0004003D, 0x000001F7, 0x0000021E, 0x0000021D, 0x00050041, 0x00000200, -0x0000021F, 0x000001FE, 0x000001FF, 0x0004003D, 0x0000007F, 0x00000220, 0x0000021F, 0x00050057, -0x00000012, 0x00000221, 0x0000021E, 0x00000220, 0x0008004F, 0x0000000C, 0x00000222, 0x00000221, -0x00000221, 0x00000000, 0x00000001, 0x00000002, 0x0005008E, 0x0000000C, 0x00000223, 0x00000222, -0x0000021C, 0x00060050, 0x0000000C, 0x00000224, 0x0000021A, 0x0000021A, 0x0000021A, 0x00050081, -0x0000000C, 0x00000225, 0x00000224, 0x00000223, 0x000200FE, 0x00000225, 0x00010038, 0x00050036, -0x00000006, 0x00000076, 0x00000000, 0x00000075, 0x000200F8, 0x00000077, 0x00050041, 0x000001E1, -0x00000229, 0x000001DF, 0x00000228, 0x0004003D, 0x00000006, 0x0000022A, 0x00000229, 0x000500B8, -0x000001E5, 0x0000022B, 0x0000022A, 0x000001E4, 0x000300F7, 0x0000022D, 0x00000000, 0x000400FA, -0x0000022B, 0x0000022C, 0x0000022D, 0x000200F8, 0x0000022C, 0x00050041, 0x000001E1, 0x0000022E, -0x000001DF, 0x000001FF, 0x0004003D, 0x00000006, 0x0000022F, 0x0000022E, 0x000200FE, 0x0000022F, -0x000200F8, 0x0000022D, 0x00050041, 0x000001E1, 0x00000231, 0x000001DF, 0x00000228, 0x0004003D, -0x00000006, 0x00000232, 0x00000231, 0x00050083, 0x00000006, 0x00000233, 0x000000D5, 0x00000232, -0x00050041, 0x000001E1, 0x00000234, 0x000001DF, 0x000001FF, 0x0004003D, 0x00000006, 0x00000235, -0x00000234, 0x00050085, 0x00000006, 0x00000236, 0x00000233, 0x00000235, 0x00050041, 0x000001E1, -0x00000237, 0x000001DF, 0x00000228, 0x0004003D, 0x00000006, 0x00000238, 0x00000237, 0x0004003D, -0x000001F7, 0x0000023A, 0x00000239, 0x00050041, 0x00000200, 0x0000023B, 0x000001FE, 0x000001FF, -0x0004003D, 0x0000007F, 0x0000023C, 0x0000023B, 0x00050057, 0x00000012, 0x0000023D, 0x0000023A, -0x0000023C, 0x00050051, 0x00000006, 0x0000023F, 0x0000023D, 0x00000000, 0x00050085, 0x00000006, -0x00000240, 0x00000238, 0x0000023F, 0x00050081, 0x00000006, 0x00000241, 0x00000236, 0x00000240, -0x000200FE, 0x00000241, 0x00010038, 0x00050036, 0x00000006, 0x00000078, 0x00000000, 0x00000075, -0x000200F8, 0x00000079, 0x00050041, 0x000001E1, 0x00000245, 0x000001DF, 0x00000244, 0x0004003D, -0x00000006, 0x00000246, 0x00000245, 0x000500B8, 0x000001E5, 0x00000247, 0x00000246, 0x000001E4, -0x000300F7, 0x00000249, 0x00000000, 0x000400FA, 0x00000247, 0x00000248, 0x00000249, 0x000200F8, -0x00000248, 0x000200FE, 0x000000D5, 0x000200F8, 0x00000249, 0x00050041, 0x000001E1, 0x0000024B, -0x000001DF, 0x00000244, 0x0004003D, 0x00000006, 0x0000024C, 0x0000024B, 0x00050083, 0x00000006, -0x0000024D, 0x000000D5, 0x0000024C, 0x00050041, 0x000001E1, 0x0000024E, 0x000001DF, 0x00000244, -0x0004003D, 0x00000006, 0x0000024F, 0x0000024E, 0x0004003D, 0x000001F7, 0x00000251, 0x00000250, -0x00050041, 0x00000200, 0x00000252, 0x000001FE, 0x000001FF, 0x0004003D, 0x0000007F, 0x00000253, -0x00000252, 0x00050057, 0x00000012, 0x00000254, 0x00000251, 0x00000253, 0x00050051, 0x00000006, -0x00000255, 0x00000254, 0x00000000, 0x00050085, 0x00000006, 0x00000256, 0x0000024F, 0x00000255, -0x00050081, 0x00000006, 0x00000257, 0x0000024D, 0x00000256, 0x000200FE, 0x00000257, 0x00010038, -0x00050036, 0x0000000C, 0x0000007B, 0x00000000, 0x0000000E, 0x00030037, 0x0000000D, 0x0000007A, -0x000200F8, 0x0000007C, 0x0004003B, 0x0000000D, 0x00000271, 0x00000007, 0x00050041, 0x000001E1, -0x0000025B, 0x000001DF, 0x0000025A, 0x0004003D, 0x00000006, 0x0000025C, 0x0000025B, 0x000500B8, -0x000001E5, 0x0000025D, 0x0000025C, 0x000001E4, 0x000300F7, 0x0000025F, 0x00000000, 0x000400FA, -0x0000025D, 0x0000025E, 0x0000025F, 0x000200F8, 0x0000025E, 0x00050041, 0x000001E1, 0x00000261, -0x000001DF, 0x00000260, 0x0004003D, 0x00000006, 0x00000262, 0x00000261, 0x0004003D, 0x0000000C, -0x00000263, 0x0000007A, 0x0005008E, 0x0000000C, 0x00000264, 0x00000263, 0x00000262, 0x000200FE, -0x00000264, 0x000200F8, 0x0000025F, 0x00050041, 0x000001E1, 0x00000266, 0x000001DF, 0x00000260, -0x0004003D, 0x00000006, 0x00000267, 0x00000266, 0x0004003D, 0x0000000C, 0x00000268, 0x0000007A, -0x0005008E, 0x0000000C, 0x00000269, 0x00000268, 0x00000267, 0x00050041, 0x000001E1, 0x0000026A, -0x000001DF, 0x0000025A, 0x0004003D, 0x00000006, 0x0000026B, 0x0000026A, 0x0004003D, 0x000001F7, -0x0000026D, 0x0000026C, 0x00050041, 0x00000200, 0x0000026E, 0x000001FE, 0x000001FF, 0x0004003D, -0x0000007F, 0x0000026F, 0x0000026E, 0x00050057, 0x00000012, 0x00000270, 0x0000026D, 0x0000026F, -0x0008004F, 0x0000000C, 0x00000272, 0x00000270, 0x00000270, 0x00000000, 0x00000001, 0x00000002, -0x0003003E, 0x00000271, 0x00000272, 0x00050039, 0x0000000C, 0x00000273, 0x00000010, 0x00000271, -0x0005008E, 0x0000000C, 0x00000274, 0x00000273, 0x0000026B, 0x00050081, 0x0000000C, 0x00000275, -0x00000269, 0x00000274, 0x000200FE, 0x00000275, 0x00010038, 0x00050036, 0x0000000C, 0x0000007D, -0x00000000, 0x00000072, 0x000200F8, 0x0000007E, 0x0004003B, 0x0000000D, 0x00000284, 0x00000007, -0x00050041, 0x000001E1, 0x00000279, 0x000001DF, 0x00000278, 0x0004003D, 0x00000006, 0x0000027A, -0x00000279, 0x000500B8, 0x000001E5, 0x0000027B, 0x0000027A, 0x000001E4, 0x000300F7, 0x0000027D, -0x00000000, 0x000400FA, 0x0000027B, 0x0000027C, 0x0000027D, 0x000200F8, 0x0000027C, 0x00050041, -0x0000027F, 0x00000280, 0x000001FE, 0x0000027E, 0x0004003D, 0x0000000C, 0x00000281, 0x00000280, -0x0006000C, 0x0000000C, 0x00000282, 0x00000001, 0x00000045, 0x00000281, 0x000200FE, 0x00000282, -0x000200F8, 0x0000027D, 0x0004003D, 0x000001F7, 0x00000286, 0x00000285, 0x00050041, 0x00000200, -0x00000287, 0x000001FE, 0x000001FF, 0x0004003D, 0x0000007F, 0x00000288, 0x00000287, 0x00050057, -0x00000012, 0x00000289, 0x00000286, 0x00000288, 0x0008004F, 0x0000000C, 0x0000028A, 0x00000289, -0x00000289, 0x00000000, 0x00000001, 0x00000002, 0x0005008E, 0x0000000C, 0x0000028B, 0x0000028A, -0x00000130, 0x00060050, 0x0000000C, 0x0000028C, 0x000000D5, 0x000000D5, 0x000000D5, 0x00050083, -0x0000000C, 0x0000028D, 0x0000028B, 0x0000028C, 0x0006000C, 0x0000000C, 0x0000028E, 0x00000001, -0x00000045, 0x0000028D, 0x0003003E, 0x00000284, 0x0000028E, 0x00050041, 0x0000028F, 0x00000290, -0x000001FE, 0x00000260, 0x0004003D, 0x000001FB, 0x00000291, 0x00000290, 0x0004003D, 0x0000000C, -0x00000292, 0x00000284, 0x00050091, 0x0000000C, 0x00000293, 0x00000291, 0x00000292, 0x0006000C, -0x0000000C, 0x00000294, 0x00000001, 0x00000045, 0x00000293, 0x000200FE, 0x00000294, 0x00010038, -0x00050036, 0x00000006, 0x00000083, 0x00000000, 0x00000081, 0x00030037, 0x00000080, 0x00000082, -0x000200F8, 0x00000084, 0x0004003D, 0x0000007F, 0x00000297, 0x00000082, 0x00050094, 0x00000006, -0x0000029B, 0x00000297, 0x0000029A, 0x0006000C, 0x00000006, 0x0000029C, 0x00000001, 0x0000000D, -0x0000029B, 0x00050085, 0x00000006, 0x0000029E, 0x0000029C, 0x0000029D, 0x0006000C, 0x00000006, -0x0000029F, 0x00000001, 0x0000000A, 0x0000029E, 0x000200FE, 0x0000029F, 0x00010038, 0x00050036, -0x0000007F, 0x0000008B, 0x00000000, 0x00000087, 0x00030037, 0x00000086, 0x00000088, 0x00030037, -0x00000086, 0x00000089, 0x00030037, 0x00000007, 0x0000008A, 0x000200F8, 0x0000008C, 0x0004003B, -0x00000007, 0x000002A2, 0x00000007, 0x0004003B, 0x00000007, 0x000002A4, 0x00000007, 0x0004003B, -0x00000007, 0x000002AD, 0x00000007, 0x0004003B, 0x00000007, 0x000002B4, 0x00000007, 0x0004003B, -0x00000007, 0x000002B7, 0x00000007, 0x0003003E, 0x000002A2, 0x000002A3, 0x0004003D, 0x00000085, -0x000002A5, 0x00000088, 0x0004006F, 0x00000006, 0x000002A6, 0x000002A5, 0x00050081, 0x00000006, -0x000002A7, 0x000002A6, 0x0000012F, 0x0006000C, 0x00000006, 0x000002A8, 0x00000001, 0x0000001F, -0x000002A7, 0x0004003D, 0x00000085, 0x000002A9, 0x00000089, 0x0004006F, 0x00000006, 0x000002AA, -0x000002A9, 0x0006000C, 0x00000006, 0x000002AB, 0x00000001, 0x0000001F, 0x000002AA, 0x00050088, -0x00000006, 0x000002AC, 0x000002A8, 0x000002AB, 0x0003003E, 0x000002A4, 0x000002AC, 0x0004003D, -0x00000085, 0x000002AE, 0x00000088, 0x0004006F, 0x00000006, 0x000002AF, 0x000002AE, 0x0004003D, -0x00000006, 0x000002B0, 0x000002A2, 0x00050085, 0x00000006, 0x000002B1, 0x000002AF, 0x000002B0, -0x0004003D, 0x00000006, 0x000002B2, 0x0000008A, 0x00050081, 0x00000006, 0x000002B3, 0x000002B1, -0x000002B2, 0x0003003E, 0x000002AD, 0x000002B3, 0x0004003D, 0x00000006, 0x000002B5, 0x000002AD, -0x0006000C, 0x00000006, 0x000002B6, 0x00000001, 0x0000000D, 0x000002B5, 0x0003003E, 0x000002B4, -0x000002B6, 0x0004003D, 0x00000006, 0x000002B8, 0x000002AD, 0x0006000C, 0x00000006, 0x000002B9, -0x00000001, 0x0000000E, 0x000002B8, 0x0003003E, 0x000002B7, 0x000002B9, 0x0004003D, 0x00000006, -0x000002BA, 0x000002A4, 0x0004003D, 0x00000006, 0x000002BB, 0x000002B7, 0x00050085, 0x00000006, -0x000002BC, 0x000002BA, 0x000002BB, 0x0004003D, 0x00000006, 0x000002BD, 0x000002A4, 0x0004003D, -0x00000006, 0x000002BE, 0x000002B4, 0x00050085, 0x00000006, 0x000002BF, 0x000002BD, 0x000002BE, -0x00050050, 0x0000007F, 0x000002C0, 0x000002BC, 0x000002BF, 0x000200FE, 0x000002C0, 0x00010038, -0x00050036, 0x00000006, 0x00000091, 0x00000000, 0x0000008D, 0x00030037, 0x0000000D, 0x0000008E, -0x00030037, 0x0000000D, 0x0000008F, 0x00030037, 0x00000086, 0x00000090, 0x000200F8, 0x00000092, -0x0004003B, 0x00000007, 0x000002C3, 0x00000007, 0x0004003B, 0x00000007, 0x000002D1, 0x00000007, -0x00050041, 0x000001E1, 0x000002CF, 0x000002CD, 0x000002CE, 0x0004003D, 0x00000006, 0x000002D0, -0x000002CF, 0x0003003E, 0x000002C3, 0x000002D0, 0x0004003D, 0x00000006, 0x000002D2, 0x000002C3, -0x0004003D, 0x0000000C, 0x000002D3, 0x0000008F, 0x0004003D, 0x0000000C, 0x000002D4, 0x0000008E, -0x00050094, 0x00000006, 0x000002D5, 0x000002D3, 0x000002D4, 0x00050083, 0x00000006, 0x000002D6, -0x000000D5, 0x000002D5, 0x00050085, 0x00000006, 0x000002D7, 0x000002D2, 0x000002D6, 0x0004003D, -0x00000006, 0x000002D8, 0x000002C3, 0x0007000C, 0x00000006, 0x000002D9, 0x00000001, 0x00000028, -0x000002D7, 0x000002D8, 0x0003003E, 0x000002D1, 0x000002D9, 0x0004003D, 0x00000006, 0x000002DA, -0x000002D1, 0x000200FE, 0x000002DA, 0x00010038, 0x00050036, 0x00000006, 0x0000009E, 0x00000000, -0x00000096, 0x00030037, 0x00000095, 0x00000097, 0x00030037, 0x00000013, 0x00000098, 0x00030037, -0x00000007, 0x00000099, 0x00030037, 0x0000000D, 0x0000009A, 0x00030037, 0x0000000D, 0x0000009B, -0x00030037, 0x0000000D, 0x0000009C, 0x00030037, 0x00000086, 0x0000009D, 0x000200F8, 0x0000009F, -0x0004003B, 0x00000007, 0x000002DD, 0x00000007, 0x0004003B, 0x0000000D, 0x000002DE, 0x00000007, -0x0004003B, 0x0000000D, 0x000002E0, 0x00000007, 0x0004003B, 0x00000086, 0x000002E2, 0x00000007, -0x0004003B, 0x00000007, 0x000002E5, 0x00000007, 0x0004003B, 0x00000007, 0x000002E6, 0x00000007, -0x0004003B, 0x00000080, 0x000002E7, 0x00000007, 0x0004003B, 0x00000086, 0x000002EB, 0x00000007, -0x0004003B, 0x00000080, 0x000002F3, 0x00000007, 0x0004003B, 0x00000086, 0x000002F4, 0x00000007, -0x0004003B, 0x00000086, 0x000002F6, 0x00000007, 0x0004003B, 0x00000007, 0x000002F7, 0x00000007, -0x0004003B, 0x00000007, 0x000002FD, 0x00000007, 0x0004003D, 0x0000000C, 0x000002DF, 0x0000009A, -0x0003003E, 0x000002DE, 0x000002DF, 0x0004003D, 0x0000000C, 0x000002E1, 0x0000009B, 0x0003003E, -0x000002E0, 0x000002E1, 0x0004003D, 0x00000085, 0x000002E3, 0x0000009D, 0x0003003E, 0x000002E2, -0x000002E3, 0x00070039, 0x00000006, 0x000002E4, 0x00000091, 0x000002DE, 0x000002E0, 0x000002E2, -0x0003003E, 0x000002DD, 0x000002E4, 0x0003003E, 0x000002E5, 0x000000F8, 0x0004003D, 0x0000000C, -0x000002E8, 0x0000009C, 0x0007004F, 0x0000007F, 0x000002E9, 0x000002E8, 0x000002E8, 0x00000000, -0x00000001, 0x0003003E, 0x000002E7, 0x000002E9, 0x00050039, 0x00000006, 0x000002EA, 0x00000083, -0x000002E7, 0x0003003E, 0x000002E6, 0x000002EA, 0x0003003E, 0x000002EB, 0x000001E9, 0x000200F9, -0x000002EC, 0x000200F8, 0x000002EC, 0x000400F6, 0x000002EE, 0x000002EF, 0x00000000, 0x000200F9, -0x000002F0, 0x000200F8, 0x000002F0, 0x0004003D, 0x00000085, 0x000002F1, 0x000002EB, 0x000500B1, -0x000001E5, 0x000002F2, 0x000002F1, 0x00000278, 0x000400FA, 0x000002F2, 0x000002ED, 0x000002EE, -0x000200F8, 0x000002ED, 0x0004003D, 0x00000085, 0x000002F5, 0x000002EB, 0x0003003E, 0x000002F4, -0x000002F5, 0x0003003E, 0x000002F6, 0x00000278, 0x0004003D, 0x00000006, 0x000002F8, 0x000002E6, -0x0003003E, 0x000002F7, 0x000002F8, 0x00070039, 0x0000007F, 0x000002F9, 0x0000008B, 0x000002F4, -0x000002F6, 0x000002F7, 0x00050050, 0x0000007F, 0x000002FB, 0x000002FA, 0x000002FA, 0x00050088, -0x0000007F, 0x000002FC, 0x000002F9, 0x000002FB, 0x0003003E, 0x000002F3, 0x000002FC, 0x0004003D, -0x00000094, 0x000002FE, 0x00000097, 0x0004003D, 0x00000012, 0x000002FF, 0x00000098, 0x0007004F, -0x0000007F, 0x00000300, 0x000002FF, 0x000002FF, 0x00000000, 0x00000001, 0x0004003D, 0x0000007F, -0x00000301, 0x000002F3, 0x00050081, 0x0000007F, 0x00000302, 0x00000300, 0x00000301, 0x0004003D, -0x00000085, 0x00000303, 0x0000009D, 0x0004006F, 0x00000006, 0x00000304, 0x00000303, 0x00050051, -0x00000006, 0x00000305, 0x00000302, 0x00000000, 0x00050051, 0x00000006, 0x00000306, 0x00000302, -0x00000001, 0x00060050, 0x0000000C, 0x00000307, 0x00000305, 0x00000306, 0x00000304, 0x00050057, -0x00000012, 0x00000308, 0x000002FE, 0x00000307, 0x00050051, 0x00000006, 0x00000309, 0x00000308, -0x00000000, 0x0003003E, 0x000002FD, 0x00000309, 0x00050041, 0x00000007, 0x0000030B, 0x00000098, -0x0000030A, 0x0004003D, 0x00000006, 0x0000030C, 0x0000030B, 0x0004003D, 0x00000006, 0x0000030D, -0x000002DD, 0x00050083, 0x00000006, 0x0000030E, 0x0000030C, 0x0000030D, 0x0004003D, 0x00000006, -0x0000030F, 0x000002FD, 0x0007000C, 0x00000006, 0x00000310, 0x00000001, 0x00000030, 0x0000030E, -0x0000030F, 0x0004003D, 0x00000006, 0x00000311, 0x000002E5, 0x00050081, 0x00000006, 0x00000312, -0x00000311, 0x00000310, 0x0003003E, 0x000002E5, 0x00000312, 0x000200F9, 0x000002EF, 0x000200F8, -0x000002EF, 0x0004003D, 0x00000085, 0x00000313, 0x000002EB, 0x00050080, 0x00000085, 0x00000314, -0x00000313, 0x000001FF, 0x0003003E, 0x000002EB, 0x00000314, 0x000200F9, 0x000002EC, 0x000200F8, -0x000002EE, 0x0004003D, 0x00000006, 0x00000315, 0x000002E5, 0x00050088, 0x00000006, 0x00000317, -0x00000315, 0x00000316, 0x000200FE, 0x00000317, 0x00010038, 0x00050036, 0x00000085, 0x000000A2, -0x00000000, 0x000000A0, 0x00030037, 0x0000000D, 0x000000A1, 0x000200F8, 0x000000A3, 0x0004003B, -0x00000086, 0x0000031A, 0x00000007, 0x0004003B, 0x00000013, 0x0000031B, 0x00000007, 0x0004003B, -0x00000086, 0x00000325, 0x00000007, 0x0003003E, 0x0000031A, 0x000001E9, 0x00050041, 0x0000031C, -0x0000031D, 0x000002CD, 0x00000210, 0x0004003D, 0x000002C7, 0x0000031E, 0x0000031D, 0x0004003D, -0x0000000C, 0x0000031F, 0x000000A1, 0x00050051, 0x00000006, 0x00000320, 0x0000031F, 0x00000000, -0x00050051, 0x00000006, 0x00000321, 0x0000031F, 0x00000001, 0x00050051, 0x00000006, 0x00000322, -0x0000031F, 0x00000002, 0x00070050, 0x00000012, 0x00000323, 0x00000320, 0x00000321, 0x00000322, -0x000000D5, 0x00050091, 0x00000012, 0x00000324, 0x0000031E, 0x00000323, 0x0003003E, 0x0000031B, -0x00000324, 0x0003003E, 0x00000325, 0x000001E9, 0x000200F9, 0x00000326, 0x000200F8, 0x00000326, -0x000400F6, 0x00000328, 0x00000329, 0x00000000, 0x000200F9, 0x0000032A, 0x000200F8, 0x0000032A, -0x0004003D, 0x00000085, 0x0000032B, 0x00000325, 0x00050041, 0x0000032D, 0x0000032E, 0x000002CD, -0x0000032C, 0x0004003D, 0x00000085, 0x0000032F, 0x0000032E, 0x00050082, 0x00000085, 0x00000330, -0x0000032F, 0x000001FF, 0x000500B1, 0x000001E5, 0x00000331, 0x0000032B, 0x00000330, 0x000400FA, -0x00000331, 0x00000327, 0x00000328, 0x000200F8, 0x00000327, 0x00050041, 0x00000007, 0x00000332, -0x0000031B, 0x0000030A, 0x0004003D, 0x00000006, 0x00000333, 0x00000332, 0x0004003D, 0x00000085, -0x00000334, 0x00000325, 0x00070041, 0x000001E1, 0x00000335, 0x000002CD, 0x0000020A, 0x00000334, -0x0000023E, 0x0004003D, 0x00000006, 0x00000336, 0x00000335, 0x000500B8, 0x000001E5, 0x00000337, -0x00000333, 0x00000336, 0x000300F7, 0x00000339, 0x00000000, 0x000400FA, 0x00000337, 0x00000338, -0x00000339, 0x000200F8, 0x00000338, 0x0004003D, 0x00000085, 0x0000033A, 0x00000325, 0x00050080, -0x00000085, 0x0000033B, 0x0000033A, 0x000001FF, 0x0003003E, 0x0000031A, 0x0000033B, 0x000200F9, -0x00000339, 0x000200F8, 0x00000339, 0x000200F9, 0x00000329, 0x000200F8, 0x00000329, 0x0004003D, -0x00000085, 0x0000033C, 0x00000325, 0x00050080, 0x00000085, 0x0000033D, 0x0000033C, 0x000001FF, -0x0003003E, 0x00000325, 0x0000033D, 0x000200F9, 0x00000326, 0x000200F8, 0x00000328, 0x0004003D, -0x00000085, 0x0000033E, 0x0000031A, 0x000200FE, 0x0000033E, 0x00010038, 0x00050036, 0x00000006, -0x000000A9, 0x00000000, 0x000000A4, 0x00030037, 0x0000000D, 0x000000A5, 0x00030037, 0x00000086, -0x000000A6, 0x00030037, 0x0000000D, 0x000000A7, 0x00030037, 0x0000000D, 0x000000A8, 0x000200F8, -0x000000AA, 0x0004003B, 0x00000013, 0x00000341, 0x00000007, 0x0004003B, 0x00000007, 0x00000353, -0x00000007, 0x0004003B, 0x00000007, 0x00000355, 0x00000007, 0x0004003B, 0x00000013, 0x00000360, -0x00000007, 0x0004003B, 0x00000007, 0x00000369, 0x00000007, 0x0004003B, 0x00000013, 0x0000036B, -0x00000007, 0x0004003B, 0x00000007, 0x0000036D, 0x00000007, 0x0004003B, 0x0000000D, 0x0000036F, -0x00000007, 0x0004003B, 0x0000000D, 0x00000371, 0x00000007, 0x0004003B, 0x0000000D, 0x00000373, -0x00000007, 0x0004003B, 0x00000086, 0x00000375, 0x00000007, 0x0004003B, 0x00000007, 0x00000378, -0x00000007, 0x0004003B, 0x00000086, 0x00000385, 0x00000007, 0x0004003B, 0x00000007, 0x0000039F, -0x00000007, 0x0004003B, 0x00000013, 0x000003A0, 0x00000007, 0x0004003B, 0x00000007, 0x000003A2, -0x00000007, 0x0004003B, 0x0000000D, 0x000003A4, 0x00000007, 0x0004003B, 0x0000000D, 0x000003A6, -0x00000007, 0x0004003B, 0x0000000D, 0x000003A8, 0x00000007, 0x0004003B, 0x00000086, 0x000003AA, -0x00000007, 0x00050041, 0x0000031C, 0x00000342, 0x000002CD, 0x00000260, 0x0004003D, 0x000002C7, -0x00000343, 0x00000342, 0x0004003D, 0x00000085, 0x00000344, 0x000000A6, 0x00060041, 0x0000031C, -0x00000345, 0x000002CD, 0x000001FF, 0x00000344, 0x0004003D, 0x000002C7, 0x00000346, 0x00000345, -0x00050092, 0x000002C7, 0x00000347, 0x00000343, 0x00000346, 0x0004003D, 0x0000000C, 0x00000348, -0x000000A5, 0x00050051, 0x00000006, 0x00000349, 0x00000348, 0x00000000, 0x00050051, 0x00000006, -0x0000034A, 0x00000348, 0x00000001, 0x00050051, 0x00000006, 0x0000034B, 0x00000348, 0x00000002, -0x00070050, 0x00000012, 0x0000034C, 0x00000349, 0x0000034A, 0x0000034B, 0x000000D5, 0x00050091, -0x00000012, 0x0000034D, 0x00000347, 0x0000034C, 0x0003003E, 0x00000341, 0x0000034D, 0x0004003D, -0x00000012, 0x0000034E, 0x00000341, 0x00050041, 0x00000007, 0x0000034F, 0x00000341, 0x000000EE, -0x0004003D, 0x00000006, 0x00000350, 0x0000034F, 0x00050088, 0x00000006, 0x00000351, 0x000000D5, -0x00000350, 0x0005008E, 0x00000012, 0x00000352, 0x0000034E, 0x00000351, 0x0003003E, 0x00000341, -0x00000352, 0x0003003E, 0x00000353, 0x00000354, 0x00050041, 0x000001E1, 0x00000356, 0x000002CD, -0x00000228, 0x0004003D, 0x00000006, 0x00000357, 0x00000356, 0x0004003D, 0x00000006, 0x00000358, -0x00000353, 0x00050085, 0x00000006, 0x00000359, 0x00000357, 0x00000358, 0x00050041, 0x00000007, -0x0000035A, 0x00000341, 0x0000030A, 0x0004003D, 0x00000006, 0x0000035B, 0x0000035A, 0x00050088, -0x00000006, 0x0000035C, 0x00000359, 0x0000035B, 0x0003003E, 0x00000355, 0x0000035C, 0x0004003D, -0x00000006, 0x0000035D, 0x00000355, 0x0007000C, 0x00000006, 0x0000035F, 0x00000001, 0x00000025, -0x0000035D, 0x0000035E, 0x0003003E, 0x00000355, 0x0000035F, 0x00050041, 0x0000031C, 0x00000361, -0x000002CD, 0x00000210, 0x0004003D, 0x000002C7, 0x00000362, 0x00000361, 0x0004003D, 0x0000000C, -0x00000363, 0x000000A5, 0x00050051, 0x00000006, 0x00000364, 0x00000363, 0x00000000, 0x00050051, -0x00000006, 0x00000365, 0x00000363, 0x00000001, 0x00050051, 0x00000006, 0x00000366, 0x00000363, -0x00000002, 0x00070050, 0x00000012, 0x00000367, 0x00000364, 0x00000365, 0x00000366, 0x000000D5, -0x00050091, 0x00000012, 0x00000368, 0x00000362, 0x00000367, 0x0003003E, 0x00000360, 0x00000368, -0x0003003E, 0x00000369, 0x000000D5, 0x0004003D, 0x00000012, 0x0000036C, 0x00000341, 0x0003003E, -0x0000036B, 0x0000036C, 0x0004003D, 0x00000006, 0x0000036E, 0x00000355, 0x0003003E, 0x0000036D, -0x0000036E, 0x0004003D, 0x0000000C, 0x00000370, 0x000000A7, 0x0003003E, 0x0000036F, 0x00000370, -0x0004003D, 0x0000000C, 0x00000372, 0x000000A8, 0x0003003E, 0x00000371, 0x00000372, 0x0004003D, -0x0000000C, 0x00000374, 0x000000A5, 0x0003003E, 0x00000373, 0x00000374, 0x0004003D, 0x00000085, -0x00000376, 0x000000A6, 0x0003003E, 0x00000375, 0x00000376, 0x000B0039, 0x00000006, 0x00000377, -0x0000009E, 0x0000036A, 0x0000036B, 0x0000036D, 0x0000036F, 0x00000371, 0x00000373, 0x00000375, -0x0003003E, 0x00000369, 0x00000377, 0x0004003D, 0x00000085, 0x00000379, 0x000000A6, 0x00070041, -0x000001E1, 0x0000037A, 0x000002CD, 0x0000020A, 0x00000379, 0x0000023E, 0x0004003D, 0x00000006, -0x0000037B, 0x0000037A, 0x00050041, 0x000001E1, 0x0000037C, 0x000002CD, 0x00000244, 0x0004003D, -0x00000006, 0x0000037D, 0x0000037C, 0x00050081, 0x00000006, 0x0000037E, 0x0000037B, 0x0000037D, -0x0004003D, 0x00000085, 0x0000037F, 0x000000A6, 0x00070041, 0x000001E1, 0x00000380, 0x000002CD, -0x0000020A, 0x0000037F, 0x0000023E, 0x0004003D, 0x00000006, 0x00000381, 0x00000380, 0x00050041, -0x00000007, 0x00000382, 0x00000360, 0x0000030A, 0x0004003D, 0x00000006, 0x00000383, 0x00000382, -0x0008000C, 0x00000006, 0x00000384, 0x00000001, 0x00000031, 0x0000037E, 0x00000381, 0x00000383, -0x0003003E, 0x00000378, 0x00000384, 0x0004003D, 0x00000085, 0x00000386, 0x000000A6, 0x00050080, -0x00000085, 0x00000387, 0x00000386, 0x000001FF, 0x0003003E, 0x00000385, 0x00000387, 0x0004003D, -0x00000006, 0x00000388, 0x00000378, 0x000500BA, 0x000001E5, 0x00000389, 0x00000388, 0x000000F8, -0x000300F7, 0x0000038B, 0x00000000, 0x000400FA, 0x00000389, 0x0000038A, 0x0000038B, 0x000200F8, -0x0000038A, 0x0004003D, 0x00000085, 0x0000038C, 0x00000385, 0x00050041, 0x0000032D, 0x0000038D, -0x000002CD, 0x0000032C, 0x0004003D, 0x00000085, 0x0000038E, 0x0000038D, 0x000500B1, 0x000001E5, -0x0000038F, 0x0000038C, 0x0000038E, 0x000200F9, 0x0000038B, 0x000200F8, 0x0000038B, 0x000700F5, -0x000001E5, 0x00000390, 0x00000389, 0x000000AA, 0x0000038F, 0x0000038A, 0x000300F7, 0x00000392, -0x00000000, 0x000400FA, 0x00000390, 0x00000391, 0x00000392, 0x000200F8, 0x00000391, 0x00050041, -0x0000031C, 0x00000393, 0x000002CD, 0x00000260, 0x0004003D, 0x000002C7, 0x00000394, 0x00000393, -0x0004003D, 0x00000085, 0x00000395, 0x00000385, 0x00060041, 0x0000031C, 0x00000396, 0x000002CD, -0x000001FF, 0x00000395, 0x0004003D, 0x000002C7, 0x00000397, 0x00000396, 0x00050092, 0x000002C7, -0x00000398, 0x00000394, 0x00000397, 0x0004003D, 0x0000000C, 0x00000399, 0x000000A5, 0x00050051, -0x00000006, 0x0000039A, 0x00000399, 0x00000000, 0x00050051, 0x00000006, 0x0000039B, 0x00000399, -0x00000001, 0x00050051, 0x00000006, 0x0000039C, 0x00000399, 0x00000002, 0x00070050, 0x00000012, -0x0000039D, 0x0000039A, 0x0000039B, 0x0000039C, 0x000000D5, 0x00050091, 0x00000012, 0x0000039E, -0x00000398, 0x0000039D, 0x0003003E, 0x00000341, 0x0000039E, 0x0004003D, 0x00000012, 0x000003A1, -0x00000341, 0x0003003E, 0x000003A0, 0x000003A1, 0x0004003D, 0x00000006, 0x000003A3, 0x00000355, -0x0003003E, 0x000003A2, 0x000003A3, 0x0004003D, 0x0000000C, 0x000003A5, 0x000000A7, 0x0003003E, -0x000003A4, 0x000003A5, 0x0004003D, 0x0000000C, 0x000003A7, 0x000000A8, 0x0003003E, 0x000003A6, -0x000003A7, 0x0004003D, 0x0000000C, 0x000003A9, 0x000000A5, 0x0003003E, 0x000003A8, 0x000003A9, -0x0004003D, 0x00000085, 0x000003AB, 0x00000385, 0x0003003E, 0x000003AA, 0x000003AB, 0x000B0039, -0x00000006, 0x000003AC, 0x0000009E, 0x0000036A, 0x000003A0, 0x000003A2, 0x000003A4, 0x000003A6, -0x000003A8, 0x000003AA, 0x0003003E, 0x0000039F, 0x000003AC, 0x0004003D, 0x00000006, 0x000003AD, -0x00000369, 0x0004003D, 0x00000006, 0x000003AE, 0x0000039F, 0x0004003D, 0x00000006, 0x000003AF, -0x00000378, 0x0008000C, 0x00000006, 0x000003B0, 0x00000001, 0x0000002E, 0x000003AD, 0x000003AE, -0x000003AF, 0x0003003E, 0x00000369, 0x000003B0, 0x000200F9, 0x00000392, 0x000200F8, 0x00000392, -0x0004003D, 0x00000006, 0x000003B1, 0x00000369, 0x00050083, 0x00000006, 0x000003B2, 0x000000D5, -0x000003B1, 0x0004003D, 0x00000006, 0x000003B3, 0x000000D4, 0x00050085, 0x00000006, 0x000003B4, -0x000003B2, 0x000003B3, 0x00050083, 0x00000006, 0x000003B5, 0x000000D5, 0x000003B4, 0x000200FE, -0x000003B5, 0x00010038, 0x00050036, 0x0000000C, 0x000000B5, 0x00000000, 0x000000AD, 0x00030037, -0x000000AB, 0x000000AE, 0x00030037, 0x000000AC, 0x000000AF, 0x00030037, 0x0000000C, 0x000000B0, -0x00030037, 0x00000007, 0x000000B1, 0x00030037, 0x00000007, 0x000000B2, 0x00030037, 0x00000007, -0x000000B3, 0x00030037, 0x00000007, 0x000000B4, 0x000200F8, 0x000000B6, 0x0004003B, 0x00000007, -0x000003B8, 0x00000007, 0x0004003B, 0x00000007, 0x000003BA, 0x00000007, 0x0004003B, 0x00000007, -0x000003BC, 0x00000007, 0x0004003B, 0x00000007, 0x000003BF, 0x00000007, 0x0004003B, 0x00000007, -0x000003C0, 0x00000007, 0x0004003B, 0x00000007, 0x000003C2, 0x00000007, 0x0004003B, 0x00000007, -0x000003C4, 0x00000007, 0x0004003B, 0x0000000D, 0x000003C7, 0x00000007, 0x0004003B, 0x00000007, -0x000003C9, 0x00000007, 0x00050051, 0x0000000C, 0x000003B9, 0x000000AE, 0x00000006, 0x00050051, -0x00000006, 0x000003BB, 0x000000AE, 0x00000002, 0x0003003E, 0x000003BA, 0x000003BB, 0x0004003D, -0x00000006, 0x000003BD, 0x000000B3, 0x0003003E, 0x000003BC, 0x000003BD, 0x00080039, 0x00000006, -0x000003BE, 0x0000005D, 0x000003BA, 0x000003BC, 0x000003B9, 0x000000B0, 0x0003003E, 0x000003B8, -0x000003BE, 0x00050051, 0x00000006, 0x000003C1, 0x000000AE, 0x00000002, 0x0003003E, 0x000003C0, -0x000003C1, 0x0004003D, 0x00000006, 0x000003C3, 0x000000B1, 0x0003003E, 0x000003C2, 0x000003C3, -0x0004003D, 0x00000006, 0x000003C5, 0x000000B2, 0x0003003E, 0x000003C4, 0x000003C5, 0x00070039, -0x00000006, 0x000003C6, 0x00000062, 0x000003C0, 0x000003C2, 0x000003C4, 0x0003003E, 0x000003BF, -0x000003C6, 0x00050051, 0x0000000C, 0x000003C8, 0x000000AE, 0x0000000A, 0x0004003D, 0x00000006, -0x000003CA, 0x000000B4, 0x0003003E, 0x000003C9, 0x000003CA, 0x00060039, 0x0000000C, 0x000003CB, -0x00000067, 0x000003C8, 0x000003C9, 0x0003003E, 0x000003C7, 0x000003CB, 0x0004003D, 0x00000006, -0x000003CC, 0x000003B8, 0x0004003D, 0x00000006, 0x000003CD, 0x000003BF, 0x00050085, 0x00000006, -0x000003CE, 0x000003CC, 0x000003CD, 0x0004003D, 0x0000000C, 0x000003CF, 0x000003C7, 0x0005008E, -0x0000000C, 0x000003D0, 0x000003CF, 0x000003CE, 0x000200FE, 0x000003D0, 0x00010038, 0x00050036, -0x0000000C, 0x000000BC, 0x00000000, 0x000000B7, 0x00030037, 0x000000AB, 0x000000B8, 0x00030037, -0x00000007, 0x000000B9, 0x00030037, 0x00000007, 0x000000BA, 0x00030037, 0x00000007, 0x000000BB, -0x000200F8, 0x000000BD, 0x0004003B, 0x00000007, 0x000003D5, 0x00000007, 0x0004003B, 0x00000007, -0x000003D7, 0x00000007, 0x0004003B, 0x00000007, 0x000003D9, 0x00000007, 0x0004003B, 0x00000007, -0x000003DB, 0x00000007, 0x00050051, 0x00000012, 0x000003D3, 0x000000B8, 0x00000000, 0x0008004F, -0x0000000C, 0x000003D4, 0x000003D3, 0x000003D3, 0x00000000, 0x00000001, 0x00000002, 0x00050051, -0x00000006, 0x000003D6, 0x000000B8, 0x00000002, 0x0003003E, 0x000003D5, 0x000003D6, 0x0004003D, -0x00000006, 0x000003D8, 0x000000B9, 0x0003003E, 0x000003D7, 0x000003D8, 0x0004003D, 0x00000006, -0x000003DA, 0x000000BA, 0x0003003E, 0x000003D9, 0x000003DA, 0x0004003D, 0x00000006, 0x000003DC, -0x000000BB, 0x0003003E, 0x000003DB, 0x000003DC, 0x00080039, 0x00000006, 0x000003DD, 0x00000043, -0x000003D5, 0x000003D7, 0x000003D9, 0x000003DB, 0x0005008E, 0x0000000C, 0x000003DE, 0x000003D4, -0x000003DD, 0x000200FE, 0x000003DE, 0x00010038, 0x00050036, 0x0000000C, 0x000000C5, 0x00000000, -0x000000AD, 0x00030037, 0x000000AB, 0x000000BE, 0x00030037, 0x000000AC, 0x000000BF, 0x00030037, -0x0000000C, 0x000000C0, 0x00030037, 0x00000007, 0x000000C1, 0x00030037, 0x00000007, 0x000000C2, -0x00030037, 0x00000007, 0x000000C3, 0x00030037, 0x00000007, 0x000000C4, 0x000200F8, 0x000000C6, -0x0004003B, 0x00000007, 0x000003E1, 0x00000007, 0x0004003B, 0x00000007, 0x000003E3, 0x00000007, -0x0004003B, 0x00000007, 0x000003E5, 0x00000007, 0x0004003B, 0x00000007, 0x000003E7, 0x00000007, -0x0004003D, 0x00000006, 0x000003E2, 0x000000C1, 0x0003003E, 0x000003E1, 0x000003E2, 0x0004003D, -0x00000006, 0x000003E4, 0x000000C2, 0x0003003E, 0x000003E3, 0x000003E4, 0x0004003D, 0x00000006, -0x000003E6, 0x000000C3, 0x0003003E, 0x000003E5, 0x000003E6, 0x0004003D, 0x00000006, 0x000003E8, -0x000000C4, 0x0003003E, 0x000003E7, 0x000003E8, 0x000B0039, 0x0000000C, 0x000003E9, 0x000000B5, -0x000000BE, 0x000000BF, 0x000000C0, 0x000003E1, 0x000003E3, 0x000003E5, 0x000003E7, 0x000200FE, -0x000003E9, 0x00010038, 0x00050036, 0x0000000C, 0x000000CC, 0x00000000, 0x000000C8, 0x00030037, -0x0000000D, 0x000000C9, 0x00030037, 0x0000000D, 0x000000CA, 0x00030037, 0x000000C7, 0x000000CB, -0x000200F8, 0x000000CD, 0x0004003B, 0x0000000D, 0x000003EC, 0x00000007, 0x0004003B, 0x00000086, -0x000003EE, 0x00000007, 0x0004003B, 0x000003F9, 0x000003FA, 0x00000007, 0x0004003B, 0x00000007, -0x0000040D, 0x00000007, 0x0004003B, 0x0000000D, 0x00000413, 0x00000007, 0x0004003B, 0x00000007, -0x00000419, 0x00000007, 0x0004003B, 0x00000007, 0x0000041E, 0x00000007, 0x0004003B, 0x00000007, -0x00000425, 0x00000007, 0x0004003B, 0x0000000D, 0x0000043E, 0x00000007, 0x0004003B, 0x00000007, -0x00000444, 0x00000007, 0x0004003B, 0x00000007, 0x00000448, 0x00000007, 0x0004003B, 0x00000007, -0x0000044D, 0x00000007, 0x0004003B, 0x00000007, 0x00000453, 0x00000007, 0x0004003B, 0x00000007, -0x00000459, 0x00000007, 0x0004003B, 0x00000086, 0x0000046A, 0x00000007, 0x0004003B, 0x0000000D, -0x0000046B, 0x00000007, 0x0004003B, 0x0000000D, 0x00000474, 0x00000007, 0x0004003B, 0x00000086, -0x00000476, 0x00000007, 0x0004003B, 0x0000000D, 0x00000478, 0x00000007, 0x0004003B, 0x0000000D, -0x0000047C, 0x00000007, 0x0004003B, 0x0000000D, 0x00000481, 0x00000007, 0x0004003B, 0x0000000D, -0x00000485, 0x00000007, 0x0004003B, 0x0000000D, 0x0000048C, 0x00000007, 0x0004003B, 0x00000007, -0x00000492, 0x00000007, 0x0004003B, 0x00000007, 0x00000497, 0x00000007, 0x0004003B, 0x0000000D, -0x00000499, 0x00000007, 0x0004003B, 0x00000007, 0x0000049F, 0x00000007, 0x0004003B, 0x00000007, -0x000004A5, 0x00000007, 0x0004003B, 0x00000007, 0x000004A7, 0x00000007, 0x0004003B, 0x00000007, -0x000004A9, 0x00000007, 0x0004003B, 0x00000007, 0x000004AA, 0x00000007, 0x0004003B, 0x00000007, -0x000004AD, 0x00000007, 0x0004003B, 0x00000007, 0x000004B2, 0x00000007, 0x0004003B, 0x00000007, -0x000004B4, 0x00000007, 0x0004003B, 0x00000007, 0x000004B8, 0x00000007, 0x0004003B, 0x0000000D, -0x000004BA, 0x00000007, 0x0004003B, 0x00000007, 0x000004BC, 0x00000007, 0x0004003B, 0x00000007, -0x000004BE, 0x00000007, 0x0004003B, 0x00000007, 0x000004C0, 0x00000007, 0x0004003B, 0x0000000D, -0x000004C3, 0x00000007, 0x0004003B, 0x00000007, 0x000004C7, 0x00000007, 0x0004003B, 0x00000007, -0x000004C9, 0x00000007, 0x0004003B, 0x00000007, 0x000004CB, 0x00000007, 0x0004003B, 0x00000007, -0x000004CD, 0x00000007, 0x0004003B, 0x0000000D, 0x000004D0, 0x00000007, 0x0004003B, 0x00000007, -0x000004DA, 0x00000007, 0x0004003B, 0x00000007, 0x000004DC, 0x00000007, 0x0003003E, 0x000003EC, -0x000003ED, 0x0003003E, 0x000003EE, 0x000001E9, 0x000200F9, 0x000003EF, 0x000200F8, 0x000003EF, -0x000400F6, 0x000003F1, 0x000003F2, 0x00000000, 0x000200F9, 0x000003F3, 0x000200F8, 0x000003F3, -0x0004003D, 0x00000085, 0x000003F4, 0x000003EE, 0x00050041, 0x0000032D, 0x000003F6, 0x000002CD, -0x000003F5, 0x0004003D, 0x00000085, 0x000003F7, 0x000003F6, 0x000500B1, 0x000001E5, 0x000003F8, -0x000003F4, 0x000003F7, 0x000400FA, 0x000003F8, 0x000003F0, 0x000003F1, 0x000200F8, 0x000003F0, -0x0004003D, 0x00000085, 0x000003FB, 0x000003EE, 0x00060041, 0x000003FC, 0x000003FD, 0x000002CD, -0x000001E9, 0x000003FB, 0x0004003D, 0x000002C4, 0x000003FE, 0x000003FD, 0x00050051, 0x00000012, -0x000003FF, 0x000003FE, 0x00000000, 0x00050041, 0x00000013, 0x00000400, 0x000003FA, 0x000001E9, -0x0003003E, 0x00000400, 0x000003FF, 0x00050051, 0x00000012, 0x00000401, 0x000003FE, 0x00000001, -0x00050041, 0x00000013, 0x00000402, 0x000003FA, 0x000001FF, 0x0003003E, 0x00000402, 0x00000401, -0x00050051, 0x00000012, 0x00000403, 0x000003FE, 0x00000002, 0x00050041, 0x00000013, 0x00000404, -0x000003FA, 0x00000210, 0x0003003E, 0x00000404, 0x00000403, 0x00050051, 0x00000006, 0x00000405, -0x000003FE, 0x00000003, 0x00050041, 0x00000007, 0x00000406, 0x000003FA, 0x0000027E, 0x0003003E, -0x00000406, 0x00000405, 0x00050051, 0x00000006, 0x00000407, 0x000003FE, 0x00000004, 0x00050041, -0x00000007, 0x00000408, 0x000003FA, 0x00000260, 0x0003003E, 0x00000408, 0x00000407, 0x00050051, -0x00000006, 0x00000409, 0x000003FE, 0x00000005, 0x00050041, 0x00000007, 0x0000040A, 0x000003FA, -0x000001E0, 0x0003003E, 0x0000040A, 0x00000409, 0x00050051, 0x00000006, 0x0000040B, 0x000003FE, -0x00000006, 0x00050041, 0x00000007, 0x0000040C, 0x000003FA, 0x0000020A, 0x0003003E, 0x0000040C, -0x0000040B, 0x0003003E, 0x0000040D, 0x000000F8, 0x00050041, 0x00000007, 0x0000040E, 0x000003FA, -0x000001E0, 0x0004003D, 0x00000006, 0x0000040F, 0x0000040E, 0x000500B4, 0x000001E5, 0x00000410, -0x0000040F, 0x00000130, 0x000300F7, 0x00000412, 0x00000000, 0x000400FA, 0x00000410, 0x00000411, -0x00000438, 0x000200F8, 0x00000411, 0x00050041, 0x00000013, 0x00000414, 0x000003FA, 0x000001FF, -0x0004003D, 0x00000012, 0x00000415, 0x00000414, 0x0008004F, 0x0000000C, 0x00000416, 0x00000415, -0x00000415, 0x00000000, 0x00000001, 0x00000002, 0x0004003D, 0x0000000C, 0x00000417, 0x000000CA, -0x00050083, 0x0000000C, 0x00000418, 0x00000416, 0x00000417, 0x0003003E, 0x00000413, 0x00000418, -0x0004003D, 0x0000000C, 0x0000041A, 0x00000413, 0x0006000C, 0x00000006, 0x0000041B, 0x00000001, -0x00000042, 0x0000041A, 0x0003003E, 0x00000419, 0x0000041B, 0x0004003D, 0x0000000C, 0x0000041C, -0x00000413, 0x0006000C, 0x0000000C, 0x0000041D, 0x00000001, 0x00000045, 0x0000041C, 0x0003003E, -0x00000413, 0x0000041D, 0x00050041, 0x00000007, 0x0000041F, 0x000003FA, 0x00000260, 0x0004003D, -0x00000006, 0x00000420, 0x0000041F, 0x0004003D, 0x00000006, 0x00000421, 0x00000419, 0x0007000C, -0x00000006, 0x00000422, 0x00000001, 0x0000001A, 0x00000421, 0x00000130, 0x00050081, 0x00000006, -0x00000423, 0x00000422, 0x000000D5, 0x00050088, 0x00000006, 0x00000424, 0x00000420, 0x00000423, -0x0003003E, 0x0000041E, 0x00000424, 0x0004003D, 0x00000006, 0x00000426, 0x00000419, 0x0004003D, -0x00000006, 0x00000427, 0x00000419, 0x00050085, 0x00000006, 0x00000428, 0x00000426, 0x00000427, -0x00050041, 0x00000007, 0x00000429, 0x000003FA, 0x00000260, 0x0004003D, 0x00000006, 0x0000042A, -0x00000429, 0x00050041, 0x00000007, 0x0000042B, 0x000003FA, 0x00000260, 0x0004003D, 0x00000006, -0x0000042C, 0x0000042B, 0x00050085, 0x00000006, 0x0000042D, 0x0000042A, 0x0000042C, 0x00050088, -0x00000006, 0x0000042E, 0x00000428, 0x0000042D, 0x00050083, 0x00000006, 0x0000042F, 0x000000D5, -0x0000042E, 0x0008000C, 0x00000006, 0x00000430, 0x00000001, 0x0000002B, 0x0000042F, 0x000000F8, -0x000000D5, 0x0003003E, 0x00000425, 0x00000430, 0x0004003D, 0x00000006, 0x00000431, 0x00000425, -0x0003003E, 0x0000040D, 0x00000431, 0x0004003D, 0x0000000C, 0x00000432, 0x00000413, 0x00050051, -0x00000006, 0x00000433, 0x00000432, 0x00000000, 0x00050051, 0x00000006, 0x00000434, 0x00000432, -0x00000001, 0x00050051, 0x00000006, 0x00000435, 0x00000432, 0x00000002, 0x00070050, 0x00000012, -0x00000436, 0x00000433, 0x00000434, 0x00000435, 0x000000D5, 0x00050041, 0x00000013, 0x00000437, -0x000003FA, 0x00000210, 0x0003003E, 0x00000437, 0x00000436, 0x000200F9, 0x00000412, 0x000200F8, -0x00000438, 0x00050041, 0x00000007, 0x00000439, 0x000003FA, 0x000001E0, 0x0004003D, 0x00000006, -0x0000043A, 0x00000439, 0x000500B4, 0x000001E5, 0x0000043B, 0x0000043A, 0x000000D5, 0x000300F7, -0x0000043D, 0x00000000, 0x000400FA, 0x0000043B, 0x0000043C, 0x00000469, 0x000200F8, 0x0000043C, -0x00050041, 0x00000013, 0x0000043F, 0x000003FA, 0x000001FF, 0x0004003D, 0x00000012, 0x00000440, -0x0000043F, 0x0008004F, 0x0000000C, 0x00000441, 0x00000440, 0x00000440, 0x00000000, 0x00000001, -0x00000002, 0x0004003D, 0x0000000C, 0x00000442, 0x000000CA, 0x00050083, 0x0000000C, 0x00000443, -0x00000441, 0x00000442, 0x0003003E, 0x0000043E, 0x00000443, 0x00050041, 0x00000007, 0x00000445, -0x000003FA, 0x0000020A, 0x0004003D, 0x00000006, 0x00000446, 0x00000445, 0x00050083, 0x00000006, -0x00000447, 0x000000D5, 0x00000446, 0x0003003E, 0x00000444, 0x00000447, 0x0004003D, 0x0000000C, -0x00000449, 0x0000043E, 0x0006000C, 0x00000006, 0x0000044A, 0x00000001, 0x00000042, 0x00000449, -0x0003003E, 0x00000448, 0x0000044A, 0x0004003D, 0x0000000C, 0x0000044B, 0x0000043E, 0x0006000C, -0x0000000C, 0x0000044C, 0x00000001, 0x00000045, 0x0000044B, 0x0003003E, 0x0000043E, 0x0000044C, -0x0004003D, 0x0000000C, 0x0000044E, 0x0000043E, 0x00050041, 0x00000013, 0x0000044F, 0x000003FA, -0x00000210, 0x0004003D, 0x00000012, 0x00000450, 0x0000044F, 0x0008004F, 0x0000000C, 0x00000451, -0x00000450, 0x00000450, 0x00000000, 0x00000001, 0x00000002, 0x00050094, 0x00000006, 0x00000452, -0x0000044E, 0x00000451, 0x0003003E, 0x0000044D, 0x00000452, 0x0004003D, 0x00000006, 0x00000454, -0x00000444, 0x0004003D, 0x00000006, 0x00000455, 0x00000444, 0x00050085, 0x00000006, 0x00000457, -0x00000455, 0x00000456, 0x00050083, 0x00000006, 0x00000458, 0x00000454, 0x00000457, 0x0003003E, -0x00000453, 0x00000458, 0x0004003D, 0x00000006, 0x0000045A, 0x0000044D, 0x0004003D, 0x00000006, -0x0000045B, 0x00000444, 0x00050083, 0x00000006, 0x0000045C, 0x0000045A, 0x0000045B, 0x0004003D, -0x00000006, 0x0000045D, 0x00000453, 0x00050088, 0x00000006, 0x0000045E, 0x0000045C, 0x0000045D, -0x0003003E, 0x00000459, 0x0000045E, 0x00050041, 0x00000007, 0x0000045F, 0x000003FA, 0x00000260, -0x0004003D, 0x00000006, 0x00000460, 0x0000045F, 0x0004003D, 0x00000006, 0x00000461, 0x00000448, -0x0007000C, 0x00000006, 0x00000462, 0x00000001, 0x0000001A, 0x00000461, 0x00000130, 0x00050081, -0x00000006, 0x00000463, 0x00000462, 0x000000D5, 0x00050088, 0x00000006, 0x00000464, 0x00000460, -0x00000463, 0x0004003D, 0x00000006, 0x00000465, 0x00000459, 0x00050085, 0x00000006, 0x00000466, -0x00000465, 0x00000464, 0x0003003E, 0x00000459, 0x00000466, 0x0004003D, 0x00000006, 0x00000467, -0x00000459, 0x0008000C, 0x00000006, 0x00000468, 0x00000001, 0x0000002B, 0x00000467, 0x000000F8, -0x000000D5, 0x0003003E, 0x0000040D, 0x00000468, 0x000200F9, 0x0000043D, 0x000200F8, 0x00000469, -0x0004003D, 0x0000000C, 0x0000046C, 0x000000CA, 0x0003003E, 0x0000046B, 0x0000046C, 0x00050039, -0x00000085, 0x0000046D, 0x000000A2, 0x0000046B, 0x0003003E, 0x0000046A, 0x0000046D, 0x00050041, -0x0000032D, 0x0000046F, 0x000002CD, 0x0000046E, 0x0004003D, 0x00000085, 0x00000470, 0x0000046F, -0x000500AD, 0x000001E5, 0x00000471, 0x00000470, 0x000001E9, 0x000300F7, 0x00000473, 0x00000000, -0x000400FA, 0x00000471, 0x00000472, 0x00000480, 0x000200F8, 0x00000472, 0x0004003D, 0x0000000C, -0x00000475, 0x000000CA, 0x0003003E, 0x00000474, 0x00000475, 0x0004003D, 0x00000085, 0x00000477, -0x0000046A, 0x0003003E, 0x00000476, 0x00000477, 0x00050041, 0x00000013, 0x00000479, 0x000003FA, -0x00000210, 0x0004003D, 0x00000012, 0x0000047A, 0x00000479, 0x0008004F, 0x0000000C, 0x0000047B, -0x0000047A, 0x0000047A, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000478, 0x0000047B, -0x00050041, 0x0000000D, 0x0000047D, 0x000000CB, 0x0000020A, 0x0004003D, 0x0000000C, 0x0000047E, -0x0000047D, 0x0003003E, 0x0000047C, 0x0000047E, 0x00080039, 0x00000006, 0x0000047F, 0x000000A9, -0x00000474, 0x00000476, 0x00000478, 0x0000047C, 0x0003003E, 0x0000040D, 0x0000047F, 0x000200F9, -0x00000473, 0x000200F8, 0x00000480, 0x0003003E, 0x0000040D, 0x000000D5, 0x000200F9, 0x00000473, -0x000200F8, 0x00000473, 0x000200F9, 0x0000043D, 0x000200F8, 0x0000043D, 0x000200F9, 0x00000412, -0x000200F8, 0x00000412, 0x00050041, 0x00000013, 0x00000482, 0x000003FA, 0x00000210, 0x0004003D, -0x00000012, 0x00000483, 0x00000482, 0x0008004F, 0x0000000C, 0x00000484, 0x00000483, 0x00000483, -0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000481, 0x00000484, 0x00050041, 0x00000013, -0x00000486, 0x000003FA, 0x000001E9, 0x0004003D, 0x00000012, 0x00000487, 0x00000486, 0x0008004F, -0x0000000C, 0x00000488, 0x00000487, 0x00000487, 0x00000000, 0x00000001, 0x00000002, 0x00050041, -0x00000007, 0x00000489, 0x000003FA, 0x0000027E, 0x0004003D, 0x00000006, 0x0000048A, 0x00000489, -0x0005008E, 0x0000000C, 0x0000048B, 0x00000488, 0x0000048A, 0x0003003E, 0x00000485, 0x0000048B, -0x0004003D, 0x0000000C, 0x0000048D, 0x00000481, 0x00050041, 0x0000000D, 0x0000048E, 0x000000CB, -0x00000278, 0x0004003D, 0x0000000C, 0x0000048F, 0x0000048E, 0x00050081, 0x0000000C, 0x00000490, -0x0000048D, 0x0000048F, 0x0006000C, 0x0000000C, 0x00000491, 0x00000001, 0x00000045, 0x00000490, -0x0003003E, 0x0000048C, 0x00000491, 0x00050041, 0x0000000D, 0x00000493, 0x000000CB, 0x0000020A, -0x0004003D, 0x0000000C, 0x00000494, 0x00000493, 0x0004003D, 0x0000000C, 0x00000495, 0x00000481, -0x00050094, 0x00000006, 0x00000496, 0x00000494, 0x00000495, 0x0003003E, 0x00000497, 0x00000496, -0x00050039, 0x00000006, 0x00000498, 0x00000019, 0x00000497, 0x0003003E, 0x00000492, 0x00000498, -0x00050041, 0x0000000D, 0x0000049A, 0x000000CB, 0x00000278, 0x0004003D, 0x0000000C, 0x0000049B, -0x0000049A, 0x0004003D, 0x0000000C, 0x0000049C, 0x00000481, 0x00050081, 0x0000000C, 0x0000049D, -0x0000049B, 0x0000049C, 0x0006000C, 0x0000000C, 0x0000049E, 0x00000001, 0x00000045, 0x0000049D, -0x0003003E, 0x00000499, 0x0000049E, 0x00050041, 0x0000000D, 0x000004A0, 0x000000CB, 0x0000020A, -0x0004003D, 0x0000000C, 0x000004A1, 0x000004A0, 0x00050041, 0x0000000D, 0x000004A2, 0x000000CB, -0x00000278, 0x0004003D, 0x0000000C, 0x000004A3, 0x000004A2, 0x00050094, 0x00000006, 0x000004A4, -0x000004A1, 0x000004A3, 0x0003003E, 0x000004A5, 0x000004A4, 0x00050039, 0x00000006, 0x000004A6, -0x00000046, 0x000004A5, 0x0003003E, 0x0000049F, 0x000004A6, 0x0004003D, 0x00000006, 0x000004A8, -0x0000049F, 0x0003003E, 0x000004A7, 0x000004A8, 0x0004003D, 0x00000006, 0x000004AB, 0x00000492, -0x0003003E, 0x000004AA, 0x000004AB, 0x00050039, 0x00000006, 0x000004AC, 0x00000019, 0x000004AA, -0x0003003E, 0x000004A9, 0x000004AC, 0x00050041, 0x0000000D, 0x000004AE, 0x000000CB, 0x0000020A, -0x0004003D, 0x0000000C, 0x000004AF, 0x000004AE, 0x0004003D, 0x0000000C, 0x000004B0, 0x00000499, -0x00050094, 0x00000006, 0x000004B1, 0x000004AF, 0x000004B0, 0x0003003E, 0x000004B2, 0x000004B1, -0x00050039, 0x00000006, 0x000004B3, 0x00000019, 0x000004B2, 0x0003003E, 0x000004AD, 0x000004B3, -0x0004003D, 0x0000000C, 0x000004B5, 0x00000481, 0x0004003D, 0x0000000C, 0x000004B6, 0x00000499, -0x00050094, 0x00000006, 0x000004B7, 0x000004B5, 0x000004B6, 0x0003003E, 0x000004B8, 0x000004B7, -0x00050039, 0x00000006, 0x000004B9, 0x00000019, 0x000004B8, 0x0003003E, 0x000004B4, 0x000004B9, -0x0004003D, 0x000000AB, 0x000004BB, 0x000000CB, 0x0004003D, 0x00000006, 0x000004BD, 0x000004A7, -0x0003003E, 0x000004BC, 0x000004BD, 0x0004003D, 0x00000006, 0x000004BF, 0x000004A9, 0x0003003E, -0x000004BE, 0x000004BF, 0x0004003D, 0x00000006, 0x000004C1, 0x000004B4, 0x0003003E, 0x000004C0, -0x000004C1, 0x00080039, 0x0000000C, 0x000004C2, 0x000000BC, 0x000004BB, 0x000004BC, 0x000004BE, -0x000004C0, 0x0003003E, 0x000004BA, 0x000004C2, 0x0004003D, 0x000000AB, 0x000004C4, 0x000000CB, -0x0004003D, 0x000000AC, 0x000004C5, 0x000003FA, 0x0004003D, 0x0000000C, 0x000004C6, 0x00000499, -0x0004003D, 0x00000006, 0x000004C8, 0x000004A7, 0x0003003E, 0x000004C7, 0x000004C8, 0x0004003D, -0x00000006, 0x000004CA, 0x000004A9, 0x0003003E, 0x000004C9, 0x000004CA, 0x0004003D, 0x00000006, -0x000004CC, 0x000004AD, 0x0003003E, 0x000004CB, 0x000004CC, 0x0004003D, 0x00000006, 0x000004CE, -0x000004B4, 0x0003003E, 0x000004CD, 0x000004CE, 0x000B0039, 0x0000000C, 0x000004CF, 0x000000C5, -0x000004C4, 0x000004C5, 0x000004C6, 0x000004C7, 0x000004C9, 0x000004CB, 0x000004CD, 0x0003003E, -0x000004C3, 0x000004CF, 0x0004003D, 0x0000000C, 0x000004D1, 0x000004BA, 0x0004003D, 0x0000000C, -0x000004D2, 0x000004C3, 0x00050081, 0x0000000C, 0x000004D3, 0x000004D1, 0x000004D2, 0x0003003E, -0x000004D0, 0x000004D3, 0x0004003D, 0x0000000C, 0x000004D4, 0x000004D0, 0x0004003D, 0x0000000C, -0x000004D5, 0x00000485, 0x00050085, 0x0000000C, 0x000004D6, 0x000004D4, 0x000004D5, 0x0004003D, -0x00000006, 0x000004D7, 0x0000040D, 0x0004003D, 0x00000006, 0x000004D8, 0x000004A9, 0x00050085, -0x00000006, 0x000004D9, 0x000004D7, 0x000004D8, 0x0004003D, 0x00000006, 0x000004DB, 0x000004A9, -0x0003003E, 0x000004DA, 0x000004DB, 0x00050041, 0x00000007, 0x000004DD, 0x000000CB, 0x00000228, -0x0004003D, 0x00000006, 0x000004DE, 0x000004DD, 0x0003003E, 0x000004DC, 0x000004DE, 0x00060039, -0x00000006, 0x000004DF, 0x0000003D, 0x000004DA, 0x000004DC, 0x00050085, 0x00000006, 0x000004E0, -0x000004D9, 0x000004DF, 0x0005008E, 0x0000000C, 0x000004E1, 0x000004D6, 0x000004E0, 0x0004003D, -0x0000000C, 0x000004E2, 0x000003EC, 0x00050081, 0x0000000C, 0x000004E3, 0x000004E2, 0x000004E1, -0x0003003E, 0x000003EC, 0x000004E3, 0x000200F9, 0x000003F2, 0x000200F8, 0x000003F2, 0x0004003D, -0x00000085, 0x000004E4, 0x000003EE, 0x00050080, 0x00000085, 0x000004E5, 0x000004E4, 0x000001FF, -0x0003003E, 0x000003EE, 0x000004E5, 0x000200F9, 0x000003EF, 0x000200F8, 0x000003F1, 0x0004003D, -0x0000000C, 0x000004E6, 0x000003EC, 0x000200FE, 0x000004E6, 0x00010038, 0x00050036, 0x0000000C, -0x000000D1, 0x00000000, 0x000000C8, 0x00030037, 0x0000000D, 0x000000CE, 0x00030037, 0x0000000D, -0x000000CF, 0x00030037, 0x000000C7, 0x000000D0, 0x000200F8, 0x000000D2, 0x0004003B, 0x0000000D, -0x000004E9, 0x00000007, 0x0004003B, 0x0000000D, 0x000004F3, 0x00000007, 0x0004003B, 0x0000000D, -0x000004F4, 0x00000007, 0x0004003B, 0x00000007, 0x000004F6, 0x00000007, 0x0004003B, 0x00000007, -0x000004F9, 0x00000007, 0x0004003B, 0x0000000D, 0x000004FD, 0x00000007, 0x0004003B, 0x0000000D, -0x00000505, 0x00000007, 0x0004003B, 0x00000086, 0x0000050B, 0x00000007, 0x0004003B, 0x0000000D, -0x0000050F, 0x00000007, 0x0004003B, 0x0000000D, 0x0000051A, 0x00000007, 0x0004003D, 0x000004EB, -0x000004EE, 0x000004ED, 0x00050041, 0x0000000D, 0x000004EF, 0x000000D0, 0x0000020A, 0x0004003D, -0x0000000C, 0x000004F0, 0x000004EF, 0x00050057, 0x00000012, 0x000004F1, 0x000004EE, 0x000004F0, -0x0008004F, 0x0000000C, 0x000004F2, 0x000004F1, 0x000004F1, 0x00000000, 0x00000001, 0x00000002, -0x0003003E, 0x000004E9, 0x000004F2, 0x0004003D, 0x0000000C, 0x000004F5, 0x000000CE, 0x0003003E, -0x000004F4, 0x000004F5, 0x00050041, 0x00000007, 0x000004F7, 0x000000D0, 0x0000025A, 0x0004003D, -0x00000006, 0x000004F8, 0x000004F7, 0x0003003E, 0x000004F6, 0x000004F8, 0x00050041, 0x00000007, -0x000004FA, 0x000000D0, 0x00000210, 0x0004003D, 0x00000006, 0x000004FB, 0x000004FA, 0x0003003E, -0x000004F9, 0x000004FB, 0x00070039, 0x0000000C, 0x000004FC, 0x0000006D, 0x000004F4, 0x000004F6, -0x000004F9, 0x0003003E, 0x000004F3, 0x000004FC, 0x0004003D, 0x0000000C, 0x000004FE, 0x000004F3, -0x00060050, 0x0000000C, 0x000004FF, 0x000000D5, 0x000000D5, 0x000000D5, 0x00050083, 0x0000000C, -0x00000500, 0x000004FF, 0x000004FE, 0x00050041, 0x00000007, 0x00000501, 0x000000D0, 0x000001FF, -0x0004003D, 0x00000006, 0x00000502, 0x00000501, 0x00050083, 0x00000006, 0x00000503, 0x000000D5, -0x00000502, 0x0005008E, 0x0000000C, 0x00000504, 0x00000500, 0x00000503, 0x0003003E, 0x000004FD, -0x00000504, 0x00050041, 0x00000013, 0x00000506, 0x000000D0, 0x000001E9, 0x0004003D, 0x00000012, -0x00000507, 0x00000506, 0x0008004F, 0x0000000C, 0x00000508, 0x00000507, 0x00000507, 0x00000000, -0x00000001, 0x00000002, 0x0004003D, 0x0000000C, 0x00000509, 0x000004E9, 0x00050085, 0x0000000C, -0x0000050A, 0x00000508, 0x00000509, 0x0003003E, 0x00000505, 0x0000050A, 0x00050041, 0x0000032D, -0x0000050D, 0x000002CD, 0x0000050C, 0x0004003D, 0x00000085, 0x0000050E, 0x0000050D, 0x0003003E, -0x0000050B, 0x0000050E, 0x0004003D, 0x000004EB, 0x00000511, 0x00000510, 0x0004003D, 0x0000000C, -0x00000512, 0x000000CF, 0x00050041, 0x00000007, 0x00000513, 0x000000D0, 0x0000027E, 0x0004003D, -0x00000006, 0x00000514, 0x00000513, 0x0004003D, 0x00000085, 0x00000515, 0x0000050B, 0x0004006F, -0x00000006, 0x00000516, 0x00000515, 0x00050085, 0x00000006, 0x00000517, 0x00000514, 0x00000516, -0x00070058, 0x00000012, 0x00000518, 0x00000511, 0x00000512, 0x00000002, 0x00000517, 0x0008004F, -0x0000000C, 0x00000519, 0x00000518, 0x00000518, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, -0x0000050F, 0x00000519, 0x0004003D, 0x0000000C, 0x0000051B, 0x0000050F, 0x0004003D, 0x0000000C, -0x0000051C, 0x000004F3, 0x00060041, 0x00000007, 0x0000051D, 0x000000D0, 0x0000032C, 0x0000023E, -0x0004003D, 0x00000006, 0x0000051E, 0x0000051D, 0x0005008E, 0x0000000C, 0x0000051F, 0x0000051C, -0x0000051E, 0x00060041, 0x00000007, 0x00000521, 0x000000D0, 0x0000032C, 0x00000520, 0x0004003D, -0x00000006, 0x00000522, 0x00000521, 0x00060050, 0x0000000C, 0x00000523, 0x00000522, 0x00000522, -0x00000522, 0x00050081, 0x0000000C, 0x00000524, 0x0000051F, 0x00000523, 0x00050085, 0x0000000C, -0x00000525, 0x0000051B, 0x00000524, 0x0003003E, 0x0000051A, 0x00000525, 0x0004003D, 0x0000000C, -0x00000526, 0x000004FD, 0x0004003D, 0x0000000C, 0x00000527, 0x00000505, 0x00050085, 0x0000000C, -0x00000528, 0x00000526, 0x00000527, 0x0004003D, 0x0000000C, 0x00000529, 0x0000051A, 0x00050081, -0x0000000C, 0x0000052A, 0x00000528, 0x00000529, 0x000200FE, 0x0000052A, 0x00010038, +0x00000556, 0x00050041, 0x000001DF, 0x00000558, 0x000001DD, 0x00000208, 0x0004003D, 0x00000006, +0x00000559, 0x00000558, 0x00050041, 0x00000007, 0x0000055A, 0x0000054C, 0x000002EA, 0x0004003D, +0x00000006, 0x0000055B, 0x0000055A, 0x00050085, 0x00000006, 0x0000055C, 0x00000559, 0x0000055B, +0x00050081, 0x00000006, 0x0000055D, 0x00000557, 0x0000055C, 0x0003003E, 0x00000518, 0x0000055D, +0x00050041, 0x000001DF, 0x0000055E, 0x000001DD, 0x00000208, 0x0004003D, 0x00000006, 0x0000055F, +0x0000055E, 0x00050083, 0x00000006, 0x00000560, 0x000000D3, 0x0000055F, 0x00050041, 0x000001DF, +0x00000561, 0x000001DD, 0x000001FD, 0x0004003D, 0x00000006, 0x00000562, 0x00000561, 0x00050085, +0x00000006, 0x00000563, 0x00000560, 0x00000562, 0x00050041, 0x000001DF, 0x00000564, 0x000001DD, +0x00000208, 0x0004003D, 0x00000006, 0x00000565, 0x00000564, 0x00050041, 0x00000007, 0x00000566, +0x0000054C, 0x00000501, 0x0004003D, 0x00000006, 0x00000567, 0x00000566, 0x00050085, 0x00000006, +0x00000568, 0x00000565, 0x00000567, 0x00050081, 0x00000006, 0x00000569, 0x00000563, 0x00000568, +0x0003003E, 0x00000519, 0x00000569, 0x000200F9, 0x0000054B, 0x000200F8, 0x0000054B, 0x000200F9, +0x00000527, 0x000200F8, 0x00000527, 0x000200F9, 0x0000051E, 0x000200F8, 0x0000051E, 0x0004003D, +0x00000012, 0x0000056B, 0x0000050E, 0x00050041, 0x00000013, 0x0000056C, 0x0000056A, 0x000001E7, +0x0003003E, 0x0000056C, 0x0000056B, 0x0004003D, 0x00000006, 0x0000056D, 0x00000518, 0x00050041, +0x00000007, 0x0000056E, 0x0000056A, 0x000001FD, 0x0003003E, 0x0000056E, 0x0000056D, 0x0004003D, +0x00000006, 0x0000056F, 0x00000519, 0x00050041, 0x00000007, 0x00000570, 0x0000056A, 0x000003E6, +0x0003003E, 0x00000570, 0x0000056F, 0x00050041, 0x000001DF, 0x00000571, 0x000001DD, 0x000003E6, +0x0004003D, 0x00000006, 0x00000572, 0x00000571, 0x00050041, 0x00000007, 0x00000573, 0x0000056A, +0x0000025E, 0x0003003E, 0x00000573, 0x00000572, 0x00050041, 0x00000574, 0x00000575, 0x000001FC, +0x000003E6, 0x0004003D, 0x0000000C, 0x00000576, 0x00000575, 0x0006000C, 0x0000000C, 0x00000577, +0x00000001, 0x00000045, 0x00000576, 0x00050041, 0x0000000D, 0x00000578, 0x0000056A, 0x00000208, +0x0003003E, 0x00000578, 0x00000577, 0x00050041, 0x000001DF, 0x00000579, 0x000001DD, 0x000002D1, +0x0004003D, 0x00000006, 0x0000057A, 0x00000579, 0x000500BA, 0x000001E3, 0x0000057C, 0x0000057A, +0x0000057B, 0x000300F7, 0x0000057E, 0x00000000, 0x000400FA, 0x0000057C, 0x0000057D, 0x0000057E, +0x000200F8, 0x0000057D, 0x0004003D, 0x000001F5, 0x00000580, 0x0000057F, 0x00050041, 0x000001FE, +0x00000581, 0x000001FC, 0x000001FD, 0x0004003D, 0x0000007D, 0x00000582, 0x00000581, 0x00050057, +0x00000012, 0x00000583, 0x00000580, 0x00000582, 0x0008004F, 0x0000000C, 0x00000584, 0x00000583, +0x00000583, 0x00000000, 0x00000001, 0x00000002, 0x0005008E, 0x0000000C, 0x00000585, 0x00000584, +0x0000012E, 0x00060050, 0x0000000C, 0x00000586, 0x000000D3, 0x000000D3, 0x000000D3, 0x00050083, +0x0000000C, 0x00000587, 0x00000585, 0x00000586, 0x0006000C, 0x0000000C, 0x00000588, 0x00000001, +0x00000045, 0x00000587, 0x00050041, 0x0000000D, 0x00000589, 0x0000056A, 0x00000208, 0x0003003E, +0x00000589, 0x00000588, 0x00050041, 0x0000058A, 0x0000058B, 0x000001FC, 0x0000025E, 0x0004003D, +0x000001F9, 0x0000058C, 0x0000058B, 0x00050041, 0x0000000D, 0x0000058D, 0x0000056A, 0x00000208, +0x0004003D, 0x0000000C, 0x0000058E, 0x0000058D, 0x00050091, 0x0000000C, 0x0000058F, 0x0000058C, +0x0000058E, 0x0006000C, 0x0000000C, 0x00000590, 0x00000001, 0x00000045, 0x0000058F, 0x00050041, +0x0000000D, 0x00000591, 0x0000056A, 0x00000208, 0x0003003E, 0x00000591, 0x00000590, 0x00050041, +0x0000000D, 0x00000592, 0x0000056A, 0x00000208, 0x0004003D, 0x0000000C, 0x00000593, 0x00000592, +0x0006000C, 0x0000000C, 0x00000594, 0x00000001, 0x00000045, 0x00000593, 0x00050041, 0x0000000D, +0x00000595, 0x0000056A, 0x00000208, 0x0003003E, 0x00000595, 0x00000594, 0x000200F9, 0x0000057E, +0x000200F8, 0x0000057E, 0x00040039, 0x00000006, 0x00000596, 0x00000078, 0x00050041, 0x00000007, +0x00000597, 0x0000056A, 0x00000226, 0x0003003E, 0x00000597, 0x00000596, 0x00050041, 0x00000013, +0x00000599, 0x0000056A, 0x000001E7, 0x0004003D, 0x00000012, 0x0000059A, 0x00000599, 0x0008004F, +0x0000000C, 0x0000059B, 0x0000059A, 0x0000059A, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, +0x00000598, 0x0000059B, 0x00050039, 0x0000000C, 0x0000059C, 0x0000007B, 0x00000598, 0x00050041, +0x0000000D, 0x0000059D, 0x0000056A, 0x000001DE, 0x0003003E, 0x0000059D, 0x0000059C, 0x0004003D, +0x00000012, 0x000005A1, 0x000005A0, 0x0007004F, 0x0000007D, 0x000005A2, 0x000005A1, 0x000005A1, +0x00000000, 0x00000001, 0x00050041, 0x000001DF, 0x000005A4, 0x000002AC, 0x000005A3, 0x0004003D, +0x00000006, 0x000005A5, 0x000005A4, 0x00050041, 0x000001DF, 0x000005A7, 0x000002AC, 0x000005A6, +0x0004003D, 0x00000006, 0x000005A8, 0x000005A7, 0x00050050, 0x0000007D, 0x000005A9, 0x000005A5, +0x000005A8, 0x00050088, 0x0000007D, 0x000005AA, 0x000005A2, 0x000005A9, 0x0003003E, 0x0000059E, +0x000005AA, 0x0004003D, 0x000001F5, 0x000005AD, 0x000005AC, 0x0004003D, 0x0000007D, 0x000005AE, +0x0000059E, 0x00050057, 0x00000012, 0x000005AF, 0x000005AD, 0x000005AE, 0x00050051, 0x00000006, +0x000005B0, 0x000005AF, 0x00000000, 0x0003003E, 0x000005AB, 0x000005B0, 0x0004003D, 0x00000006, +0x000005B1, 0x000005AB, 0x00050041, 0x00000013, 0x000005B2, 0x0000056A, 0x000001E7, 0x0004003D, +0x00000012, 0x000005B3, 0x000005B2, 0x0005008E, 0x00000012, 0x000005B4, 0x000005B3, 0x000005B1, +0x00050041, 0x00000013, 0x000005B5, 0x0000056A, 0x000001E7, 0x0003003E, 0x000005B5, 0x000005B4, +0x00050041, 0x00000007, 0x000005B6, 0x0000056A, 0x000003E6, 0x0004003D, 0x00000006, 0x000005B7, +0x000005B6, 0x0008000C, 0x00000006, 0x000005B9, 0x00000001, 0x0000002B, 0x000005B7, 0x000005B8, +0x000000D3, 0x00050041, 0x00000007, 0x000005BA, 0x0000056A, 0x000003E6, 0x0003003E, 0x000005BA, +0x000005B9, 0x00050041, 0x00000007, 0x000005BC, 0x0000056A, 0x0000020E, 0x0004003D, 0x00000006, +0x000005BD, 0x000005BC, 0x0003003E, 0x000005BB, 0x000005BD, 0x00050039, 0x00000006, 0x000005BE, +0x00000057, 0x000005BB, 0x00050041, 0x00000007, 0x000005BF, 0x0000056A, 0x0000020E, 0x0003003E, +0x000005BF, 0x000005BE, 0x0004003D, 0x00000006, 0x000005C1, 0x00000519, 0x0004003D, 0x00000006, +0x000005C2, 0x00000519, 0x00050085, 0x00000006, 0x000005C3, 0x000005C1, 0x000005C2, 0x0003003E, +0x000005C0, 0x000005C3, 0x00050041, 0x0000000D, 0x000005C5, 0x0000056A, 0x00000208, 0x0004003D, +0x0000000C, 0x000005C6, 0x000005C5, 0x000400CF, 0x0000000C, 0x000005C7, 0x000005C6, 0x0003003E, +0x000005C4, 0x000005C7, 0x00050041, 0x0000000D, 0x000005C9, 0x0000056A, 0x00000208, 0x0004003D, +0x0000000C, 0x000005CA, 0x000005C9, 0x000400D0, 0x0000000C, 0x000005CB, 0x000005CA, 0x0003003E, +0x000005C8, 0x000005CB, 0x0004003D, 0x0000000C, 0x000005CD, 0x000005C4, 0x0004003D, 0x0000000C, +0x000005CE, 0x000005C4, 0x00050094, 0x00000006, 0x000005CF, 0x000005CD, 0x000005CE, 0x0004003D, +0x0000000C, 0x000005D0, 0x000005C8, 0x0004003D, 0x0000000C, 0x000005D1, 0x000005C8, 0x00050094, +0x00000006, 0x000005D2, 0x000005D0, 0x000005D1, 0x00050081, 0x00000006, 0x000005D3, 0x000005CF, +0x000005D2, 0x0003003E, 0x000005CC, 0x000005D3, 0x0004003D, 0x00000006, 0x000005D5, 0x000005CC, +0x00050085, 0x00000006, 0x000005D6, 0x000005D5, 0x000000D3, 0x0007000C, 0x00000006, 0x000005D8, +0x00000001, 0x00000025, 0x000005D6, 0x000005D7, 0x0003003E, 0x000005D4, 0x000005D8, 0x0004003D, +0x00000006, 0x000005DA, 0x000005C0, 0x0004003D, 0x00000006, 0x000005DB, 0x000005D4, 0x00050081, +0x00000006, 0x000005DC, 0x000005DA, 0x000005DB, 0x0003003E, 0x000005DD, 0x000005DC, 0x00050039, +0x00000006, 0x000005DE, 0x00000019, 0x000005DD, 0x0003003E, 0x000005D9, 0x000005DE, 0x0004003D, +0x00000006, 0x000005DF, 0x000005D9, 0x0006000C, 0x00000006, 0x000005E0, 0x00000001, 0x0000001F, +0x000005DF, 0x00050041, 0x00000007, 0x000005E1, 0x0000056A, 0x0000020E, 0x0003003E, 0x000005E1, +0x000005E0, 0x00050041, 0x00000007, 0x000005E2, 0x0000056A, 0x0000020E, 0x0004003D, 0x00000006, +0x000005E3, 0x000005E2, 0x0008000C, 0x00000006, 0x000005E5, 0x00000001, 0x0000002B, 0x000005E3, +0x000005E4, 0x000000D3, 0x00050041, 0x00000007, 0x000005E6, 0x0000056A, 0x0000020E, 0x0003003E, +0x000005E6, 0x000005E5, 0x00050041, 0x0000059F, 0x000005E8, 0x000001FC, 0x0000020E, 0x0004003D, +0x00000012, 0x000005E9, 0x000005E8, 0x0008004F, 0x0000000C, 0x000005EA, 0x000005E9, 0x000005E9, +0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x000005E7, 0x000005EA, 0x00050041, 0x000001E8, +0x000005EB, 0x000002AC, 0x000001DE, 0x0004003D, 0x00000012, 0x000005EC, 0x000005EB, 0x0008004F, +0x0000000C, 0x000005ED, 0x000005EC, 0x000005EC, 0x00000000, 0x00000001, 0x00000002, 0x0004003D, +0x0000000C, 0x000005EE, 0x000005E7, 0x00050083, 0x0000000C, 0x000005EF, 0x000005ED, 0x000005EE, +0x0006000C, 0x0000000C, 0x000005F0, 0x00000001, 0x00000045, 0x000005EF, 0x00050041, 0x0000000D, +0x000005F1, 0x0000056A, 0x000002D1, 0x0003003E, 0x000005F1, 0x000005F0, 0x00050041, 0x0000000D, +0x000005F2, 0x0000056A, 0x00000208, 0x0004003D, 0x0000000C, 0x000005F3, 0x000005F2, 0x00050041, +0x0000000D, 0x000005F4, 0x0000056A, 0x000002D1, 0x0004003D, 0x0000000C, 0x000005F5, 0x000005F4, +0x00050094, 0x00000006, 0x000005F6, 0x000005F3, 0x000005F5, 0x0007000C, 0x00000006, 0x000005F7, +0x00000001, 0x00000028, 0x000005F6, 0x0000018D, 0x00050041, 0x00000007, 0x000005F8, 0x0000056A, +0x00000258, 0x0003003E, 0x000005F8, 0x000005F7, 0x0004003D, 0x000001F5, 0x000005FA, 0x000005F9, +0x00050041, 0x00000007, 0x000005FB, 0x0000056A, 0x00000258, 0x0004003D, 0x00000006, 0x000005FC, +0x000005FB, 0x00050041, 0x00000007, 0x000005FD, 0x0000056A, 0x000003E6, 0x0004003D, 0x00000006, +0x000005FE, 0x000005FD, 0x00050050, 0x0000007D, 0x000005FF, 0x000005FC, 0x000005FE, 0x00050057, +0x00000012, 0x00000600, 0x000005FA, 0x000005FF, 0x0007004F, 0x0000007D, 0x00000601, 0x00000600, +0x00000600, 0x00000000, 0x00000001, 0x00050041, 0x0000007E, 0x00000602, 0x0000056A, 0x0000030C, +0x0003003E, 0x00000602, 0x00000601, 0x00050041, 0x00000007, 0x00000605, 0x0000056A, 0x0000025E, +0x0004003D, 0x00000006, 0x00000606, 0x00000605, 0x0003003E, 0x00000604, 0x00000606, 0x00050039, +0x00000006, 0x00000607, 0x00000054, 0x00000604, 0x0003003E, 0x00000603, 0x00000607, 0x00050041, +0x00000013, 0x00000609, 0x0000056A, 0x000001E7, 0x0004003D, 0x00000012, 0x0000060A, 0x00000609, +0x00050041, 0x00000007, 0x0000060C, 0x0000056A, 0x000001FD, 0x0004003D, 0x00000006, 0x0000060D, +0x0000060C, 0x0003003E, 0x0000060B, 0x0000060D, 0x0004003D, 0x00000006, 0x0000060F, 0x00000603, +0x0003003E, 0x0000060E, 0x0000060F, 0x00070039, 0x0000000C, 0x00000610, 0x00000051, 0x0000060A, +0x0000060B, 0x0000060E, 0x0003003E, 0x00000608, 0x00000610, 0x0004003D, 0x0000000C, 0x00000611, +0x00000608, 0x00050041, 0x0000000D, 0x00000612, 0x0000056A, 0x00000242, 0x0003003E, 0x00000612, +0x00000611, 0x00050041, 0x0000000D, 0x00000613, 0x0000056A, 0x00000242, 0x0004003D, 0x0000000C, +0x00000614, 0x00000613, 0x00060041, 0x00000007, 0x00000616, 0x0000056A, 0x0000030C, 0x00000501, +0x0004003D, 0x00000006, 0x00000617, 0x00000616, 0x0007000C, 0x00000006, 0x00000618, 0x00000001, +0x00000028, 0x00000615, 0x00000617, 0x00050088, 0x00000006, 0x00000619, 0x000000D3, 0x00000618, +0x00050083, 0x00000006, 0x0000061A, 0x00000619, 0x000000D3, 0x0005008E, 0x0000000C, 0x0000061B, +0x00000614, 0x0000061A, 0x00060050, 0x0000000C, 0x0000061C, 0x000000D3, 0x000000D3, 0x000000D3, +0x00050081, 0x0000000C, 0x0000061D, 0x0000061C, 0x0000061B, 0x00050041, 0x0000000D, 0x0000061E, +0x0000056A, 0x000003D5, 0x0003003E, 0x0000061E, 0x0000061D, 0x00050041, 0x00000013, 0x0000061F, +0x0000056A, 0x000001E7, 0x0004003D, 0x00000012, 0x00000620, 0x0000061F, 0x00050041, 0x00000007, +0x00000622, 0x0000056A, 0x000001FD, 0x0004003D, 0x00000006, 0x00000623, 0x00000622, 0x0003003E, +0x00000621, 0x00000623, 0x00060039, 0x0000000C, 0x00000624, 0x0000004B, 0x00000620, 0x00000621, +0x00060041, 0x00000007, 0x00000625, 0x0000056A, 0x000001E7, 0x0000023C, 0x00050051, 0x00000006, +0x00000626, 0x00000624, 0x00000000, 0x0003003E, 0x00000625, 0x00000626, 0x00060041, 0x00000007, +0x00000627, 0x0000056A, 0x000001E7, 0x00000501, 0x00050051, 0x00000006, 0x00000628, 0x00000624, +0x00000001, 0x0003003E, 0x00000627, 0x00000628, 0x00060041, 0x00000007, 0x00000629, 0x0000056A, +0x000001E7, 0x000002EA, 0x00050051, 0x00000006, 0x0000062A, 0x00000624, 0x00000002, 0x0003003E, +0x00000629, 0x0000062A, 0x00050041, 0x000001DF, 0x0000062C, 0x000002AC, 0x000002D1, 0x0004003D, +0x00000006, 0x0000062D, 0x0000062C, 0x0003003E, 0x0000062B, 0x0000062D, 0x00050041, 0x000001DF, +0x0000062F, 0x000002AC, 0x00000258, 0x0004003D, 0x00000006, 0x00000630, 0x0000062F, 0x0003003E, +0x0000062E, 0x00000630, 0x00050041, 0x000002FC, 0x00000632, 0x000002AC, 0x0000020E, 0x0004003D, +0x000002A6, 0x00000633, 0x00000632, 0x0004003D, 0x0000000C, 0x00000634, 0x000005E7, 0x00050051, +0x00000006, 0x00000635, 0x00000634, 0x00000000, 0x00050051, 0x00000006, 0x00000636, 0x00000634, +0x00000001, 0x00050051, 0x00000006, 0x00000637, 0x00000634, 0x00000002, 0x00070050, 0x00000012, +0x00000638, 0x00000635, 0x00000636, 0x00000637, 0x000000D3, 0x00050091, 0x00000012, 0x00000639, +0x00000633, 0x00000638, 0x0003003E, 0x00000631, 0x00000639, 0x0004003D, 0x00000012, 0x0000063B, +0x00000631, 0x0006000C, 0x00000006, 0x0000063C, 0x00000001, 0x00000042, 0x0000063B, 0x0003003E, +0x0000063A, 0x0000063C, 0x0004003D, 0x00000006, 0x0000063D, 0x0000063A, 0x0004003D, 0x00000006, +0x0000063E, 0x0000062B, 0x0004003D, 0x00000006, 0x0000063F, 0x0000062E, 0x00050083, 0x00000006, +0x00000640, 0x0000063E, 0x0000063F, 0x00050083, 0x00000006, 0x00000641, 0x0000063D, 0x00000640, +0x0003003E, 0x000000D2, 0x00000641, 0x0004003D, 0x00000006, 0x00000642, 0x0000062E, 0x0004003D, +0x00000006, 0x00000643, 0x000000D2, 0x00050088, 0x00000006, 0x00000644, 0x00000643, 0x00000642, +0x0003003E, 0x000000D2, 0x00000644, 0x0004003D, 0x00000006, 0x00000645, 0x000000D2, 0x00050083, +0x00000006, 0x00000646, 0x000000D3, 0x00000645, 0x0008000C, 0x00000006, 0x00000647, 0x00000001, +0x0000002B, 0x00000646, 0x000000F6, 0x000000D3, 0x0003003E, 0x000000D2, 0x00000647, 0x00050041, +0x00000007, 0x00000649, 0x0000056A, 0x00000258, 0x0004003D, 0x00000006, 0x0000064A, 0x00000649, +0x00050085, 0x00000006, 0x0000064B, 0x0000012E, 0x0000064A, 0x00050041, 0x0000000D, 0x0000064C, +0x0000056A, 0x00000208, 0x0004003D, 0x0000000C, 0x0000064D, 0x0000064C, 0x0005008E, 0x0000000C, +0x0000064E, 0x0000064D, 0x0000064B, 0x00050041, 0x0000000D, 0x0000064F, 0x0000056A, 0x000002D1, +0x0004003D, 0x0000000C, 0x00000650, 0x0000064F, 0x00050083, 0x0000000C, 0x00000651, 0x0000064E, +0x00000650, 0x0003003E, 0x00000648, 0x00000651, 0x00050041, 0x0000000D, 0x00000654, 0x0000056A, +0x00000242, 0x0004003D, 0x0000000C, 0x00000655, 0x00000654, 0x0003003E, 0x00000653, 0x00000655, +0x0004003D, 0x0000000C, 0x00000657, 0x000005E7, 0x0003003E, 0x00000656, 0x00000657, 0x0004003D, +0x000000A9, 0x00000659, 0x0000056A, 0x0003003E, 0x00000658, 0x00000659, 0x00070039, 0x0000000C, +0x0000065A, 0x000000CA, 0x00000653, 0x00000656, 0x00000658, 0x0003003E, 0x00000652, 0x0000065A, +0x00050041, 0x0000000D, 0x0000065D, 0x0000056A, 0x00000242, 0x0004003D, 0x0000000C, 0x0000065E, +0x0000065D, 0x0003003E, 0x0000065C, 0x0000065E, 0x0004003D, 0x0000000C, 0x00000660, 0x00000648, +0x0003003E, 0x0000065F, 0x00000660, 0x0004003D, 0x000000A9, 0x00000662, 0x0000056A, 0x0003003E, +0x00000661, 0x00000662, 0x00070039, 0x0000000C, 0x00000663, 0x000000CF, 0x0000065C, 0x0000065F, +0x00000661, 0x0003003E, 0x0000065B, 0x00000663, 0x0004003D, 0x0000000C, 0x00000665, 0x00000652, +0x0004003D, 0x0000000C, 0x00000666, 0x0000065B, 0x00050081, 0x0000000C, 0x00000667, 0x00000665, +0x00000666, 0x00050041, 0x0000000D, 0x00000668, 0x0000056A, 0x000001DE, 0x0004003D, 0x0000000C, +0x00000669, 0x00000668, 0x00050081, 0x0000000C, 0x0000066A, 0x00000667, 0x00000669, 0x0003003E, +0x00000664, 0x0000066A, 0x0004003D, 0x0000000C, 0x0000066D, 0x00000664, 0x00050051, 0x00000006, +0x0000066E, 0x0000066D, 0x00000000, 0x00050051, 0x00000006, 0x0000066F, 0x0000066D, 0x00000001, +0x00050051, 0x00000006, 0x00000670, 0x0000066D, 0x00000002, 0x00070050, 0x00000012, 0x00000671, +0x0000066E, 0x0000066F, 0x00000670, 0x000000D3, 0x0003003E, 0x0000066C, 0x00000671, 0x00050041, +0x0000030D, 0x00000673, 0x000002AC, 0x00000672, 0x0004003D, 0x00000083, 0x00000674, 0x00000673, +0x000500AD, 0x000001E3, 0x00000675, 0x00000674, 0x000001E7, 0x000300F7, 0x00000677, 0x00000000, +0x000400FA, 0x00000675, 0x00000676, 0x00000677, 0x000200F8, 0x00000676, 0x00050041, 0x0000030D, +0x00000678, 0x000002AC, 0x00000672, 0x0004003D, 0x00000083, 0x00000679, 0x00000678, 0x000300F7, +0x00000681, 0x00000000, 0x001100FB, 0x00000679, 0x00000681, 0x00000001, 0x0000067A, 0x00000002, +0x0000067B, 0x00000003, 0x0000067C, 0x00000004, 0x0000067D, 0x00000005, 0x0000067E, 0x00000006, +0x0000067F, 0x00000007, 0x00000680, 0x000200F8, 0x0000067A, 0x00050041, 0x00000013, 0x00000682, +0x0000056A, 0x000001E7, 0x0004003D, 0x00000012, 0x00000683, 0x00000682, 0x0003003E, 0x0000066C, +0x00000683, 0x000200F9, 0x00000681, 0x000200F8, 0x0000067B, 0x00050041, 0x00000007, 0x00000685, +0x0000056A, 0x000001FD, 0x0004003D, 0x00000006, 0x00000686, 0x00000685, 0x00060050, 0x0000000C, +0x00000687, 0x00000686, 0x00000686, 0x00000686, 0x00050051, 0x00000006, 0x00000688, 0x00000687, +0x00000000, 0x00050051, 0x00000006, 0x00000689, 0x00000687, 0x00000001, 0x00050051, 0x00000006, +0x0000068A, 0x00000687, 0x00000002, 0x00070050, 0x00000012, 0x0000068B, 0x00000688, 0x00000689, +0x0000068A, 0x000000D3, 0x0003003E, 0x0000066C, 0x0000068B, 0x000200F9, 0x00000681, 0x000200F8, +0x0000067C, 0x00050041, 0x00000007, 0x0000068D, 0x0000056A, 0x000003E6, 0x0004003D, 0x00000006, +0x0000068E, 0x0000068D, 0x00060050, 0x0000000C, 0x0000068F, 0x0000068E, 0x0000068E, 0x0000068E, +0x00050051, 0x00000006, 0x00000690, 0x0000068F, 0x00000000, 0x00050051, 0x00000006, 0x00000691, +0x0000068F, 0x00000001, 0x00050051, 0x00000006, 0x00000692, 0x0000068F, 0x00000002, 0x00070050, +0x00000012, 0x00000693, 0x00000690, 0x00000691, 0x00000692, 0x000000D3, 0x0003003E, 0x0000066C, +0x00000693, 0x000200F9, 0x00000681, 0x000200F8, 0x0000067D, 0x00050041, 0x00000007, 0x00000695, +0x0000056A, 0x00000226, 0x0004003D, 0x00000006, 0x00000696, 0x00000695, 0x00060050, 0x0000000C, +0x00000697, 0x00000696, 0x00000696, 0x00000696, 0x00050051, 0x00000006, 0x00000698, 0x00000697, +0x00000000, 0x00050051, 0x00000006, 0x00000699, 0x00000697, 0x00000001, 0x00050051, 0x00000006, +0x0000069A, 0x00000697, 0x00000002, 0x00070050, 0x00000012, 0x0000069B, 0x00000698, 0x00000699, +0x0000069A, 0x000000D3, 0x0003003E, 0x0000066C, 0x0000069B, 0x000200F9, 0x00000681, 0x000200F8, +0x0000067E, 0x00050041, 0x0000000D, 0x0000069D, 0x0000056A, 0x000001DE, 0x0004003D, 0x0000000C, +0x0000069E, 0x0000069D, 0x00050051, 0x00000006, 0x0000069F, 0x0000069E, 0x00000000, 0x00050051, +0x00000006, 0x000006A0, 0x0000069E, 0x00000001, 0x00050051, 0x00000006, 0x000006A1, 0x0000069E, +0x00000002, 0x00070050, 0x00000012, 0x000006A2, 0x0000069F, 0x000006A0, 0x000006A1, 0x000000D3, +0x0003003E, 0x0000066C, 0x000006A2, 0x000200F9, 0x00000681, 0x000200F8, 0x0000067F, 0x00050041, +0x0000000D, 0x000006A4, 0x0000056A, 0x00000208, 0x0004003D, 0x0000000C, 0x000006A5, 0x000006A4, +0x00050051, 0x00000006, 0x000006A6, 0x000006A5, 0x00000000, 0x00050051, 0x00000006, 0x000006A7, +0x000006A5, 0x00000001, 0x00050051, 0x00000006, 0x000006A8, 0x000006A5, 0x00000002, 0x00070050, +0x00000012, 0x000006A9, 0x000006A6, 0x000006A7, 0x000006A8, 0x000000D3, 0x0003003E, 0x0000066C, +0x000006A9, 0x000200F9, 0x00000681, 0x000200F8, 0x00000680, 0x0004003D, 0x0000000C, 0x000006AD, +0x000005E7, 0x0003003E, 0x000006AC, 0x000006AD, 0x00050039, 0x00000083, 0x000006AE, 0x000000A0, +0x000006AC, 0x0003003E, 0x000006AB, 0x000006AE, 0x0004003D, 0x00000083, 0x000006AF, 0x000006AB, +0x000300F7, 0x000006B4, 0x00000000, 0x000B00FB, 0x000006AF, 0x000006B4, 0x00000000, 0x000006B0, +0x00000001, 0x000006B1, 0x00000002, 0x000006B2, 0x00000003, 0x000006B3, 0x000200F8, 0x000006B0, +0x0004003D, 0x00000012, 0x000006B5, 0x0000066C, 0x00050085, 0x00000012, 0x000006B9, 0x000006B5, +0x000006B8, 0x0003003E, 0x0000066C, 0x000006B9, 0x000200F9, 0x000006B4, 0x000200F8, 0x000006B1, +0x0004003D, 0x00000012, 0x000006BB, 0x0000066C, 0x00050085, 0x00000012, 0x000006BD, 0x000006BB, +0x000006BC, 0x0003003E, 0x0000066C, 0x000006BD, 0x000200F9, 0x000006B4, 0x000200F8, 0x000006B2, +0x0004003D, 0x00000012, 0x000006BF, 0x0000066C, 0x00050085, 0x00000012, 0x000006C1, 0x000006BF, +0x000006C0, 0x0003003E, 0x0000066C, 0x000006C1, 0x000200F9, 0x000006B4, 0x000200F8, 0x000006B3, +0x0004003D, 0x00000012, 0x000006C3, 0x0000066C, 0x00050085, 0x00000012, 0x000006C5, 0x000006C3, +0x000006C4, 0x0003003E, 0x0000066C, 0x000006C5, 0x000200F9, 0x000006B4, 0x000200F8, 0x000006B4, +0x000200F9, 0x00000681, 0x000200F8, 0x00000681, 0x000200F9, 0x00000677, 0x000200F8, 0x00000677, +0x000100FD, 0x00010038, 0x00050036, 0x00000006, 0x0000000A, 0x00000000, 0x00000008, 0x00030037, +0x00000007, 0x00000009, 0x000200F8, 0x0000000B, 0x0004003B, 0x00000007, 0x000000D6, 0x00000007, +0x0004003D, 0x00000006, 0x000000D7, 0x00000009, 0x0004003D, 0x00000006, 0x000000D8, 0x00000009, +0x00050085, 0x00000006, 0x000000D9, 0x000000D7, 0x000000D8, 0x0003003E, 0x000000D6, 0x000000D9, +0x0004003D, 0x00000006, 0x000000DA, 0x000000D6, 0x0004003D, 0x00000006, 0x000000DB, 0x000000D6, +0x00050085, 0x00000006, 0x000000DC, 0x000000DA, 0x000000DB, 0x0004003D, 0x00000006, 0x000000DD, +0x00000009, 0x00050085, 0x00000006, 0x000000DE, 0x000000DC, 0x000000DD, 0x000200FE, 0x000000DE, +0x00010038, 0x00050036, 0x0000000C, 0x00000010, 0x00000000, 0x0000000E, 0x00030037, 0x0000000D, +0x0000000F, 0x000200F8, 0x00000011, 0x0004003D, 0x0000000C, 0x000000E1, 0x0000000F, 0x0007000C, +0x0000000C, 0x000000E4, 0x00000001, 0x0000001A, 0x000000E1, 0x000000E3, 0x000200FE, 0x000000E4, +0x00010038, 0x00050036, 0x00000012, 0x00000016, 0x00000000, 0x00000014, 0x00030037, 0x00000013, +0x00000015, 0x000200F8, 0x00000017, 0x0004003B, 0x0000000D, 0x000000E7, 0x00000007, 0x0004003D, +0x00000012, 0x000000E8, 0x00000015, 0x0008004F, 0x0000000C, 0x000000E9, 0x000000E8, 0x000000E8, +0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x000000E7, 0x000000E9, 0x00050039, 0x0000000C, +0x000000EA, 0x00000010, 0x000000E7, 0x00050041, 0x00000007, 0x000000ED, 0x00000015, 0x000000EC, +0x0004003D, 0x00000006, 0x000000EE, 0x000000ED, 0x00050051, 0x00000006, 0x000000EF, 0x000000EA, +0x00000000, 0x00050051, 0x00000006, 0x000000F0, 0x000000EA, 0x00000001, 0x00050051, 0x00000006, +0x000000F1, 0x000000EA, 0x00000002, 0x00070050, 0x00000012, 0x000000F2, 0x000000EF, 0x000000F0, +0x000000F1, 0x000000EE, 0x000200FE, 0x000000F2, 0x00010038, 0x00050036, 0x00000006, 0x00000019, +0x00000000, 0x00000008, 0x00030037, 0x00000007, 0x00000018, 0x000200F8, 0x0000001A, 0x0004003D, +0x00000006, 0x000000F5, 0x00000018, 0x0008000C, 0x00000006, 0x000000F7, 0x00000001, 0x0000002B, +0x000000F5, 0x000000F6, 0x000000D3, 0x000200FE, 0x000000F7, 0x00010038, 0x00050036, 0x00000006, +0x00000020, 0x00000000, 0x0000001B, 0x00030037, 0x00000007, 0x0000001C, 0x00030037, 0x00000007, +0x0000001D, 0x00030037, 0x0000000C, 0x0000001E, 0x00030037, 0x0000000C, 0x0000001F, 0x000200F8, +0x00000021, 0x0004003B, 0x0000000D, 0x000000FA, 0x00000007, 0x0004003B, 0x00000007, 0x000000FC, +0x00000007, 0x0004003B, 0x00000007, 0x00000100, 0x00000007, 0x0004003B, 0x00000007, 0x0000010A, +0x00000007, 0x0007000C, 0x0000000C, 0x000000FB, 0x00000001, 0x00000044, 0x0000001E, 0x0000001F, +0x0003003E, 0x000000FA, 0x000000FB, 0x0004003D, 0x00000006, 0x000000FD, 0x0000001D, 0x0004003D, +0x00000006, 0x000000FE, 0x0000001C, 0x00050085, 0x00000006, 0x000000FF, 0x000000FD, 0x000000FE, +0x0003003E, 0x000000FC, 0x000000FF, 0x0004003D, 0x00000006, 0x00000101, 0x0000001C, 0x0004003D, +0x0000000C, 0x00000102, 0x000000FA, 0x0004003D, 0x0000000C, 0x00000103, 0x000000FA, 0x00050094, +0x00000006, 0x00000104, 0x00000102, 0x00000103, 0x0004003D, 0x00000006, 0x00000105, 0x000000FC, +0x0004003D, 0x00000006, 0x00000106, 0x000000FC, 0x00050085, 0x00000006, 0x00000107, 0x00000105, +0x00000106, 0x00050081, 0x00000006, 0x00000108, 0x00000104, 0x00000107, 0x00050088, 0x00000006, +0x00000109, 0x00000101, 0x00000108, 0x0003003E, 0x00000100, 0x00000109, 0x0004003D, 0x00000006, +0x0000010B, 0x00000100, 0x0004003D, 0x00000006, 0x0000010C, 0x00000100, 0x00050085, 0x00000006, +0x0000010D, 0x0000010B, 0x0000010C, 0x00050085, 0x00000006, 0x0000010F, 0x0000010D, 0x0000010E, +0x0003003E, 0x0000010A, 0x0000010F, 0x0004003D, 0x00000006, 0x00000110, 0x0000010A, 0x0007000C, +0x00000006, 0x00000112, 0x00000001, 0x00000025, 0x00000110, 0x00000111, 0x000200FE, 0x00000112, +0x00010038, 0x00050036, 0x0000000C, 0x00000026, 0x00000000, 0x00000022, 0x00030037, 0x0000000C, +0x00000023, 0x00030037, 0x00000007, 0x00000024, 0x00030037, 0x00000007, 0x00000025, 0x000200F8, +0x00000027, 0x0004003B, 0x00000007, 0x0000011A, 0x00000007, 0x0004003D, 0x00000006, 0x00000115, +0x00000024, 0x00060050, 0x0000000C, 0x00000116, 0x00000115, 0x00000115, 0x00000115, 0x00050083, +0x0000000C, 0x00000117, 0x00000116, 0x00000023, 0x0004003D, 0x00000006, 0x00000118, 0x00000025, +0x00050083, 0x00000006, 0x00000119, 0x000000D3, 0x00000118, 0x0003003E, 0x0000011A, 0x00000119, +0x00050039, 0x00000006, 0x0000011B, 0x0000000A, 0x0000011A, 0x0005008E, 0x0000000C, 0x0000011C, +0x00000117, 0x0000011B, 0x00050081, 0x0000000C, 0x0000011D, 0x00000023, 0x0000011C, 0x000200FE, +0x0000011D, 0x00010038, 0x00050036, 0x00000006, 0x0000002C, 0x00000000, 0x00000028, 0x00030037, +0x00000007, 0x00000029, 0x00030037, 0x00000007, 0x0000002A, 0x00030037, 0x00000007, 0x0000002B, +0x000200F8, 0x0000002D, 0x0004003D, 0x00000006, 0x00000120, 0x0000002A, 0x0004003D, 0x00000006, +0x00000121, 0x0000002B, 0x0004003D, 0x00000006, 0x00000122, 0x0000002A, 0x00050083, 0x00000006, +0x00000123, 0x00000121, 0x00000122, 0x0004003D, 0x00000006, 0x00000124, 0x00000029, 0x00050083, +0x00000006, 0x00000125, 0x000000D3, 0x00000124, 0x0007000C, 0x00000006, 0x00000127, 0x00000001, +0x0000001A, 0x00000125, 0x00000126, 0x00050085, 0x00000006, 0x00000128, 0x00000123, 0x00000127, +0x00050081, 0x00000006, 0x00000129, 0x00000120, 0x00000128, 0x000200FE, 0x00000129, 0x00010038, +0x00050036, 0x00000006, 0x00000033, 0x00000000, 0x0000002E, 0x00030037, 0x00000007, 0x0000002F, +0x00030037, 0x00000007, 0x00000030, 0x00030037, 0x00000007, 0x00000031, 0x00030037, 0x00000007, +0x00000032, 0x000200F8, 0x00000034, 0x0004003B, 0x00000007, 0x0000012C, 0x00000007, 0x0004003B, +0x00000007, 0x00000136, 0x00000007, 0x0004003B, 0x00000007, 0x00000137, 0x00000007, 0x0004003B, +0x00000007, 0x00000138, 0x00000007, 0x0004003B, 0x00000007, 0x0000013A, 0x00000007, 0x0004003B, +0x00000007, 0x0000013D, 0x00000007, 0x0004003B, 0x00000007, 0x0000013E, 0x00000007, 0x0004003B, +0x00000007, 0x0000013F, 0x00000007, 0x0004003B, 0x00000007, 0x00000141, 0x00000007, 0x0004003D, +0x00000006, 0x0000012F, 0x0000002F, 0x00050085, 0x00000006, 0x00000130, 0x0000012E, 0x0000012F, +0x0004003D, 0x00000006, 0x00000131, 0x00000032, 0x00050085, 0x00000006, 0x00000132, 0x00000130, +0x00000131, 0x0004003D, 0x00000006, 0x00000133, 0x00000032, 0x00050085, 0x00000006, 0x00000134, +0x00000132, 0x00000133, 0x00050081, 0x00000006, 0x00000135, 0x0000012D, 0x00000134, 0x0003003E, +0x0000012C, 0x00000135, 0x0003003E, 0x00000137, 0x000000D3, 0x0004003D, 0x00000006, 0x00000139, +0x0000012C, 0x0003003E, 0x00000138, 0x00000139, 0x0004003D, 0x00000006, 0x0000013B, 0x00000031, +0x0003003E, 0x0000013A, 0x0000013B, 0x00070039, 0x00000006, 0x0000013C, 0x0000002C, 0x00000137, +0x00000138, 0x0000013A, 0x0003003E, 0x00000136, 0x0000013C, 0x0003003E, 0x0000013E, 0x000000D3, +0x0004003D, 0x00000006, 0x00000140, 0x0000012C, 0x0003003E, 0x0000013F, 0x00000140, 0x0004003D, +0x00000006, 0x00000142, 0x00000030, 0x0003003E, 0x00000141, 0x00000142, 0x00070039, 0x00000006, +0x00000143, 0x0000002C, 0x0000013E, 0x0000013F, 0x00000141, 0x0003003E, 0x0000013D, 0x00000143, +0x0004003D, 0x00000006, 0x00000144, 0x00000136, 0x0004003D, 0x00000006, 0x00000145, 0x0000013D, +0x00050085, 0x00000006, 0x00000146, 0x00000144, 0x00000145, 0x00050085, 0x00000006, 0x00000147, +0x00000146, 0x0000010E, 0x000200FE, 0x00000147, 0x00010038, 0x00050036, 0x00000006, 0x00000038, +0x00000000, 0x00000028, 0x00030037, 0x00000007, 0x00000035, 0x00030037, 0x00000007, 0x00000036, +0x00030037, 0x00000007, 0x00000037, 0x000200F8, 0x00000039, 0x0004003B, 0x00000007, 0x0000014A, +0x00000007, 0x0004003B, 0x00000007, 0x0000014E, 0x00000007, 0x0004003B, 0x00000007, 0x0000015C, +0x00000007, 0x0004003D, 0x00000006, 0x0000014B, 0x00000037, 0x0004003D, 0x00000006, 0x0000014C, +0x00000037, 0x00050085, 0x00000006, 0x0000014D, 0x0000014B, 0x0000014C, 0x0003003E, 0x0000014A, +0x0000014D, 0x0004003D, 0x00000006, 0x0000014F, 0x00000035, 0x0004003D, 0x00000006, 0x00000150, +0x00000036, 0x0004007F, 0x00000006, 0x00000151, 0x00000150, 0x0004003D, 0x00000006, 0x00000152, +0x0000014A, 0x00050085, 0x00000006, 0x00000153, 0x00000151, 0x00000152, 0x0004003D, 0x00000006, +0x00000154, 0x00000036, 0x00050081, 0x00000006, 0x00000155, 0x00000153, 0x00000154, 0x0004003D, +0x00000006, 0x00000156, 0x00000036, 0x00050085, 0x00000006, 0x00000157, 0x00000155, 0x00000156, +0x0004003D, 0x00000006, 0x00000158, 0x0000014A, 0x00050081, 0x00000006, 0x00000159, 0x00000157, +0x00000158, 0x0006000C, 0x00000006, 0x0000015A, 0x00000001, 0x0000001F, 0x00000159, 0x00050085, +0x00000006, 0x0000015B, 0x0000014F, 0x0000015A, 0x0003003E, 0x0000014E, 0x0000015B, 0x0004003D, +0x00000006, 0x0000015D, 0x00000036, 0x0004003D, 0x00000006, 0x0000015E, 0x00000035, 0x0004007F, +0x00000006, 0x0000015F, 0x0000015E, 0x0004003D, 0x00000006, 0x00000160, 0x0000014A, 0x00050085, +0x00000006, 0x00000161, 0x0000015F, 0x00000160, 0x0004003D, 0x00000006, 0x00000162, 0x00000035, +0x00050081, 0x00000006, 0x00000163, 0x00000161, 0x00000162, 0x0004003D, 0x00000006, 0x00000164, +0x00000035, 0x00050085, 0x00000006, 0x00000165, 0x00000163, 0x00000164, 0x0004003D, 0x00000006, +0x00000166, 0x0000014A, 0x00050081, 0x00000006, 0x00000167, 0x00000165, 0x00000166, 0x0006000C, +0x00000006, 0x00000168, 0x00000001, 0x0000001F, 0x00000167, 0x00050085, 0x00000006, 0x00000169, +0x0000015D, 0x00000168, 0x0003003E, 0x0000015C, 0x00000169, 0x0004003D, 0x00000006, 0x0000016A, +0x0000015C, 0x0004003D, 0x00000006, 0x0000016B, 0x0000014E, 0x00050081, 0x00000006, 0x0000016C, +0x0000016A, 0x0000016B, 0x00050088, 0x00000006, 0x0000016D, 0x0000012D, 0x0000016C, 0x000200FE, +0x0000016D, 0x00010038, 0x00050036, 0x00000006, 0x0000003D, 0x00000000, 0x0000003A, 0x00030037, +0x00000007, 0x0000003B, 0x00030037, 0x00000007, 0x0000003C, 0x000200F8, 0x0000003E, 0x0004003B, +0x00000007, 0x00000170, 0x00000007, 0x0004003B, 0x00000007, 0x00000176, 0x00000007, 0x0004003B, +0x00000007, 0x0000017A, 0x00000007, 0x0004003D, 0x00000006, 0x00000171, 0x0000003C, 0x0007000C, +0x00000006, 0x00000173, 0x00000001, 0x00000025, 0x00000171, 0x00000172, 0x00050083, 0x00000006, +0x00000174, 0x000000D3, 0x00000173, 0x0006000C, 0x00000006, 0x00000175, 0x00000001, 0x00000020, +0x00000174, 0x0003003E, 0x00000170, 0x00000175, 0x0004003D, 0x00000006, 0x00000177, 0x0000003B, +0x0004003D, 0x00000006, 0x00000178, 0x00000170, 0x00050085, 0x00000006, 0x00000179, 0x00000177, +0x00000178, 0x0003003E, 0x0000017A, 0x00000179, 0x00050039, 0x00000006, 0x0000017B, 0x00000019, +0x0000017A, 0x0003003E, 0x00000176, 0x0000017B, 0x0004003D, 0x00000006, 0x0000017C, 0x00000176, +0x0004003D, 0x00000006, 0x0000017D, 0x00000176, 0x00050085, 0x00000006, 0x0000017E, 0x0000017C, +0x0000017D, 0x000200FE, 0x0000017E, 0x00010038, 0x00050036, 0x00000006, 0x00000043, 0x00000000, +0x0000002E, 0x00030037, 0x00000007, 0x0000003F, 0x00030037, 0x00000007, 0x00000040, 0x00030037, +0x00000007, 0x00000041, 0x00030037, 0x00000007, 0x00000042, 0x000200F8, 0x00000044, 0x0004003B, +0x00000007, 0x00000181, 0x00000007, 0x0004003B, 0x00000007, 0x00000183, 0x00000007, 0x0004003B, +0x00000007, 0x00000185, 0x00000007, 0x0004003B, 0x00000007, 0x00000187, 0x00000007, 0x0004003D, +0x00000006, 0x00000182, 0x0000003F, 0x0003003E, 0x00000181, 0x00000182, 0x0004003D, 0x00000006, +0x00000184, 0x00000040, 0x0003003E, 0x00000183, 0x00000184, 0x0004003D, 0x00000006, 0x00000186, +0x00000041, 0x0003003E, 0x00000185, 0x00000186, 0x0004003D, 0x00000006, 0x00000188, 0x00000042, +0x0003003E, 0x00000187, 0x00000188, 0x00080039, 0x00000006, 0x00000189, 0x00000033, 0x00000181, +0x00000183, 0x00000185, 0x00000187, 0x000200FE, 0x00000189, 0x00010038, 0x00050036, 0x00000006, +0x00000046, 0x00000000, 0x00000008, 0x00030037, 0x00000007, 0x00000045, 0x000200F8, 0x00000047, +0x0004003D, 0x00000006, 0x0000018C, 0x00000045, 0x0007000C, 0x00000006, 0x0000018E, 0x00000001, +0x00000028, 0x0000018C, 0x0000018D, 0x000200FE, 0x0000018E, 0x00010038, 0x00050036, 0x0000000C, +0x0000004B, 0x00000000, 0x00000048, 0x00030037, 0x00000012, 0x00000049, 0x00030037, 0x00000007, +0x0000004A, 0x000200F8, 0x0000004C, 0x0008004F, 0x0000000C, 0x00000191, 0x00000049, 0x00000049, +0x00000000, 0x00000001, 0x00000002, 0x0004003D, 0x00000006, 0x00000192, 0x0000004A, 0x00050083, +0x00000006, 0x00000193, 0x000000D3, 0x00000192, 0x0005008E, 0x0000000C, 0x00000194, 0x00000191, +0x00000193, 0x000200FE, 0x00000194, 0x00010038, 0x00050036, 0x0000000C, 0x00000051, 0x00000000, +0x0000004D, 0x00030037, 0x00000012, 0x0000004E, 0x00030037, 0x00000007, 0x0000004F, 0x00030037, +0x00000007, 0x00000050, 0x000200F8, 0x00000052, 0x0008004F, 0x0000000C, 0x00000197, 0x0000004E, +0x0000004E, 0x00000000, 0x00000001, 0x00000002, 0x0004003D, 0x00000006, 0x00000198, 0x0000004F, +0x0005008E, 0x0000000C, 0x00000199, 0x00000197, 0x00000198, 0x0004003D, 0x00000006, 0x0000019A, +0x00000050, 0x0004003D, 0x00000006, 0x0000019B, 0x0000004F, 0x00050083, 0x00000006, 0x0000019C, +0x000000D3, 0x0000019B, 0x00050085, 0x00000006, 0x0000019D, 0x0000019A, 0x0000019C, 0x00060050, +0x0000000C, 0x0000019E, 0x0000019D, 0x0000019D, 0x0000019D, 0x00050081, 0x0000000C, 0x0000019F, +0x00000199, 0x0000019E, 0x000200FE, 0x0000019F, 0x00010038, 0x00050036, 0x00000006, 0x00000054, +0x00000000, 0x00000008, 0x00030037, 0x00000007, 0x00000053, 0x000200F8, 0x00000055, 0x0004003D, +0x00000006, 0x000001A3, 0x00000053, 0x00050085, 0x00000006, 0x000001A4, 0x000001A2, 0x000001A3, +0x0004003D, 0x00000006, 0x000001A5, 0x00000053, 0x00050085, 0x00000006, 0x000001A6, 0x000001A4, +0x000001A5, 0x000200FE, 0x000001A6, 0x00010038, 0x00050036, 0x00000006, 0x00000057, 0x00000000, +0x00000008, 0x00030037, 0x00000007, 0x00000056, 0x000200F8, 0x00000058, 0x0004003D, 0x00000006, +0x000001A9, 0x00000056, 0x0004003D, 0x00000006, 0x000001AA, 0x00000056, 0x00050085, 0x00000006, +0x000001AB, 0x000001A9, 0x000001AA, 0x000200FE, 0x000001AB, 0x00010038, 0x00050036, 0x00000006, +0x0000005D, 0x00000000, 0x0000001B, 0x00030037, 0x00000007, 0x00000059, 0x00030037, 0x00000007, +0x0000005A, 0x00030037, 0x0000000C, 0x0000005B, 0x00030037, 0x0000000C, 0x0000005C, 0x000200F8, +0x0000005E, 0x0004003B, 0x00000007, 0x000001AE, 0x00000007, 0x0004003B, 0x00000007, 0x000001B0, +0x00000007, 0x0004003D, 0x00000006, 0x000001AF, 0x00000059, 0x0003003E, 0x000001AE, 0x000001AF, +0x0004003D, 0x00000006, 0x000001B1, 0x0000005A, 0x0003003E, 0x000001B0, 0x000001B1, 0x00080039, +0x00000006, 0x000001B2, 0x00000020, 0x000001AE, 0x000001B0, 0x0000005C, 0x0000005B, 0x000200FE, +0x000001B2, 0x00010038, 0x00050036, 0x00000006, 0x00000062, 0x00000000, 0x00000028, 0x00030037, +0x00000007, 0x0000005F, 0x00030037, 0x00000007, 0x00000060, 0x00030037, 0x00000007, 0x00000061, +0x000200F8, 0x00000063, 0x0004003B, 0x00000007, 0x000001B5, 0x00000007, 0x0004003B, 0x00000007, +0x000001B7, 0x00000007, 0x0004003B, 0x00000007, 0x000001B9, 0x00000007, 0x0004003D, 0x00000006, +0x000001B6, 0x0000005F, 0x0003003E, 0x000001B5, 0x000001B6, 0x0004003D, 0x00000006, 0x000001B8, +0x00000060, 0x0003003E, 0x000001B7, 0x000001B8, 0x0004003D, 0x00000006, 0x000001BA, 0x00000061, +0x0003003E, 0x000001B9, 0x000001BA, 0x00070039, 0x00000006, 0x000001BB, 0x00000038, 0x000001B5, +0x000001B7, 0x000001B9, 0x000200FE, 0x000001BB, 0x00010038, 0x00050036, 0x0000000C, 0x00000067, +0x00000000, 0x00000064, 0x00030037, 0x0000000C, 0x00000065, 0x00030037, 0x00000007, 0x00000066, +0x000200F8, 0x00000068, 0x0004003B, 0x00000007, 0x000001BE, 0x00000007, 0x0004003B, 0x00000007, +0x000001C2, 0x00000007, 0x0004003B, 0x00000007, 0x000001C4, 0x00000007, 0x0004003B, 0x00000007, +0x000001C6, 0x00000007, 0x00050094, 0x00000006, 0x000001C1, 0x00000065, 0x000001C0, 0x0003003E, +0x000001C2, 0x000001C1, 0x00050039, 0x00000006, 0x000001C3, 0x00000019, 0x000001C2, 0x0003003E, +0x000001BE, 0x000001C3, 0x0004003D, 0x00000006, 0x000001C5, 0x000001BE, 0x0003003E, 0x000001C4, +0x000001C5, 0x0004003D, 0x00000006, 0x000001C7, 0x00000066, 0x0003003E, 0x000001C6, 0x000001C7, +0x00070039, 0x0000000C, 0x000001C8, 0x00000026, 0x00000065, 0x000001C4, 0x000001C6, 0x000200FE, +0x000001C8, 0x00010038, 0x00050036, 0x0000000C, 0x0000006D, 0x00000000, 0x00000069, 0x00030037, +0x0000000D, 0x0000006A, 0x00030037, 0x00000007, 0x0000006B, 0x00030037, 0x00000007, 0x0000006C, +0x000200F8, 0x0000006E, 0x0004003D, 0x0000000C, 0x000001CB, 0x0000006A, 0x0004003D, 0x00000006, +0x000001CC, 0x0000006C, 0x00050083, 0x00000006, 0x000001CD, 0x000000D3, 0x000001CC, 0x00060050, +0x0000000C, 0x000001CE, 0x000001CD, 0x000001CD, 0x000001CD, 0x0004003D, 0x0000000C, 0x000001CF, +0x0000006A, 0x0007000C, 0x0000000C, 0x000001D0, 0x00000001, 0x00000028, 0x000001CE, 0x000001CF, +0x0004003D, 0x0000000C, 0x000001D1, 0x0000006A, 0x00050083, 0x0000000C, 0x000001D2, 0x000001D0, +0x000001D1, 0x0004003D, 0x00000006, 0x000001D3, 0x0000006B, 0x00050083, 0x00000006, 0x000001D4, +0x000000D3, 0x000001D3, 0x0007000C, 0x00000006, 0x000001D5, 0x00000001, 0x00000028, 0x000001D4, +0x000000F6, 0x0007000C, 0x00000006, 0x000001D6, 0x00000001, 0x0000001A, 0x000001D5, 0x00000126, +0x0005008E, 0x0000000C, 0x000001D7, 0x000001D2, 0x000001D6, 0x00050081, 0x0000000C, 0x000001D8, +0x000001CB, 0x000001D7, 0x000200FE, 0x000001D8, 0x00010038, 0x00050036, 0x00000012, 0x00000070, +0x00000000, 0x0000006F, 0x000200F8, 0x00000071, 0x0004003B, 0x00000013, 0x00000202, 0x00000007, +0x00050041, 0x000001DF, 0x000001E0, 0x000001DD, 0x000001DE, 0x0004003D, 0x00000006, 0x000001E1, +0x000001E0, 0x000500B8, 0x000001E3, 0x000001E4, 0x000001E1, 0x000001E2, 0x000300F7, 0x000001E6, +0x00000000, 0x000400FA, 0x000001E4, 0x000001E5, 0x000001E6, 0x000200F8, 0x000001E5, 0x00050041, +0x000001E8, 0x000001E9, 0x000001DD, 0x000001E7, 0x0004003D, 0x00000012, 0x000001EA, 0x000001E9, +0x000200FE, 0x000001EA, 0x000200F8, 0x000001E6, 0x00050041, 0x000001DF, 0x000001EC, 0x000001DD, +0x000001DE, 0x0004003D, 0x00000006, 0x000001ED, 0x000001EC, 0x00050083, 0x00000006, 0x000001EE, +0x000000D3, 0x000001ED, 0x00050041, 0x000001E8, 0x000001EF, 0x000001DD, 0x000001E7, 0x0004003D, +0x00000012, 0x000001F0, 0x000001EF, 0x0005008E, 0x00000012, 0x000001F1, 0x000001F0, 0x000001EE, +0x00050041, 0x000001DF, 0x000001F2, 0x000001DD, 0x000001DE, 0x0004003D, 0x00000006, 0x000001F3, +0x000001F2, 0x0004003D, 0x000001F5, 0x000001F8, 0x000001F7, 0x00050041, 0x000001FE, 0x000001FF, +0x000001FC, 0x000001FD, 0x0004003D, 0x0000007D, 0x00000200, 0x000001FF, 0x00050057, 0x00000012, +0x00000201, 0x000001F8, 0x00000200, 0x0003003E, 0x00000202, 0x00000201, 0x00050039, 0x00000012, +0x00000203, 0x00000016, 0x00000202, 0x0005008E, 0x00000012, 0x00000204, 0x00000203, 0x000001F3, +0x00050081, 0x00000012, 0x00000205, 0x000001F1, 0x00000204, 0x000200FE, 0x00000205, 0x00010038, +0x00050036, 0x0000000C, 0x00000073, 0x00000000, 0x00000072, 0x000200F8, 0x00000074, 0x00050041, +0x000001DF, 0x00000209, 0x000001DD, 0x00000208, 0x0004003D, 0x00000006, 0x0000020A, 0x00000209, +0x000500B8, 0x000001E3, 0x0000020B, 0x0000020A, 0x000001E2, 0x000300F7, 0x0000020D, 0x00000000, +0x000400FA, 0x0000020B, 0x0000020C, 0x0000020D, 0x000200F8, 0x0000020C, 0x00050041, 0x000001DF, +0x0000020F, 0x000001DD, 0x0000020E, 0x0004003D, 0x00000006, 0x00000210, 0x0000020F, 0x00060050, +0x0000000C, 0x00000211, 0x00000210, 0x00000210, 0x00000210, 0x000200FE, 0x00000211, 0x000200F8, +0x0000020D, 0x00050041, 0x000001DF, 0x00000213, 0x000001DD, 0x00000208, 0x0004003D, 0x00000006, +0x00000214, 0x00000213, 0x00050083, 0x00000006, 0x00000215, 0x000000D3, 0x00000214, 0x00050041, +0x000001DF, 0x00000216, 0x000001DD, 0x0000020E, 0x0004003D, 0x00000006, 0x00000217, 0x00000216, +0x00050085, 0x00000006, 0x00000218, 0x00000215, 0x00000217, 0x00050041, 0x000001DF, 0x00000219, +0x000001DD, 0x00000208, 0x0004003D, 0x00000006, 0x0000021A, 0x00000219, 0x0004003D, 0x000001F5, +0x0000021C, 0x0000021B, 0x00050041, 0x000001FE, 0x0000021D, 0x000001FC, 0x000001FD, 0x0004003D, +0x0000007D, 0x0000021E, 0x0000021D, 0x00050057, 0x00000012, 0x0000021F, 0x0000021C, 0x0000021E, +0x0008004F, 0x0000000C, 0x00000220, 0x0000021F, 0x0000021F, 0x00000000, 0x00000001, 0x00000002, +0x0005008E, 0x0000000C, 0x00000221, 0x00000220, 0x0000021A, 0x00060050, 0x0000000C, 0x00000222, +0x00000218, 0x00000218, 0x00000218, 0x00050081, 0x0000000C, 0x00000223, 0x00000222, 0x00000221, +0x000200FE, 0x00000223, 0x00010038, 0x00050036, 0x00000006, 0x00000076, 0x00000000, 0x00000075, +0x000200F8, 0x00000077, 0x00050041, 0x000001DF, 0x00000227, 0x000001DD, 0x00000226, 0x0004003D, +0x00000006, 0x00000228, 0x00000227, 0x000500B8, 0x000001E3, 0x00000229, 0x00000228, 0x000001E2, +0x000300F7, 0x0000022B, 0x00000000, 0x000400FA, 0x00000229, 0x0000022A, 0x0000022B, 0x000200F8, +0x0000022A, 0x00050041, 0x000001DF, 0x0000022C, 0x000001DD, 0x000001FD, 0x0004003D, 0x00000006, +0x0000022D, 0x0000022C, 0x000200FE, 0x0000022D, 0x000200F8, 0x0000022B, 0x00050041, 0x000001DF, +0x0000022F, 0x000001DD, 0x00000226, 0x0004003D, 0x00000006, 0x00000230, 0x0000022F, 0x00050083, +0x00000006, 0x00000231, 0x000000D3, 0x00000230, 0x00050041, 0x000001DF, 0x00000232, 0x000001DD, +0x000001FD, 0x0004003D, 0x00000006, 0x00000233, 0x00000232, 0x00050085, 0x00000006, 0x00000234, +0x00000231, 0x00000233, 0x00050041, 0x000001DF, 0x00000235, 0x000001DD, 0x00000226, 0x0004003D, +0x00000006, 0x00000236, 0x00000235, 0x0004003D, 0x000001F5, 0x00000238, 0x00000237, 0x00050041, +0x000001FE, 0x00000239, 0x000001FC, 0x000001FD, 0x0004003D, 0x0000007D, 0x0000023A, 0x00000239, +0x00050057, 0x00000012, 0x0000023B, 0x00000238, 0x0000023A, 0x00050051, 0x00000006, 0x0000023D, +0x0000023B, 0x00000000, 0x00050085, 0x00000006, 0x0000023E, 0x00000236, 0x0000023D, 0x00050081, +0x00000006, 0x0000023F, 0x00000234, 0x0000023E, 0x000200FE, 0x0000023F, 0x00010038, 0x00050036, +0x00000006, 0x00000078, 0x00000000, 0x00000075, 0x000200F8, 0x00000079, 0x00050041, 0x000001DF, +0x00000243, 0x000001DD, 0x00000242, 0x0004003D, 0x00000006, 0x00000244, 0x00000243, 0x000500B8, +0x000001E3, 0x00000245, 0x00000244, 0x000001E2, 0x000300F7, 0x00000247, 0x00000000, 0x000400FA, +0x00000245, 0x00000246, 0x00000247, 0x000200F8, 0x00000246, 0x000200FE, 0x000000D3, 0x000200F8, +0x00000247, 0x00050041, 0x000001DF, 0x00000249, 0x000001DD, 0x00000242, 0x0004003D, 0x00000006, +0x0000024A, 0x00000249, 0x00050083, 0x00000006, 0x0000024B, 0x000000D3, 0x0000024A, 0x00050041, +0x000001DF, 0x0000024C, 0x000001DD, 0x00000242, 0x0004003D, 0x00000006, 0x0000024D, 0x0000024C, +0x0004003D, 0x000001F5, 0x0000024F, 0x0000024E, 0x00050041, 0x000001FE, 0x00000250, 0x000001FC, +0x000001FD, 0x0004003D, 0x0000007D, 0x00000251, 0x00000250, 0x00050057, 0x00000012, 0x00000252, +0x0000024F, 0x00000251, 0x00050051, 0x00000006, 0x00000253, 0x00000252, 0x00000000, 0x00050085, +0x00000006, 0x00000254, 0x0000024D, 0x00000253, 0x00050081, 0x00000006, 0x00000255, 0x0000024B, +0x00000254, 0x000200FE, 0x00000255, 0x00010038, 0x00050036, 0x0000000C, 0x0000007B, 0x00000000, +0x0000000E, 0x00030037, 0x0000000D, 0x0000007A, 0x000200F8, 0x0000007C, 0x0004003B, 0x0000000D, +0x0000026F, 0x00000007, 0x00050041, 0x000001DF, 0x00000259, 0x000001DD, 0x00000258, 0x0004003D, +0x00000006, 0x0000025A, 0x00000259, 0x000500B8, 0x000001E3, 0x0000025B, 0x0000025A, 0x000001E2, +0x000300F7, 0x0000025D, 0x00000000, 0x000400FA, 0x0000025B, 0x0000025C, 0x0000025D, 0x000200F8, +0x0000025C, 0x00050041, 0x000001DF, 0x0000025F, 0x000001DD, 0x0000025E, 0x0004003D, 0x00000006, +0x00000260, 0x0000025F, 0x0004003D, 0x0000000C, 0x00000261, 0x0000007A, 0x0005008E, 0x0000000C, +0x00000262, 0x00000261, 0x00000260, 0x000200FE, 0x00000262, 0x000200F8, 0x0000025D, 0x00050041, +0x000001DF, 0x00000264, 0x000001DD, 0x0000025E, 0x0004003D, 0x00000006, 0x00000265, 0x00000264, +0x0004003D, 0x0000000C, 0x00000266, 0x0000007A, 0x0005008E, 0x0000000C, 0x00000267, 0x00000266, +0x00000265, 0x00050041, 0x000001DF, 0x00000268, 0x000001DD, 0x00000258, 0x0004003D, 0x00000006, +0x00000269, 0x00000268, 0x0004003D, 0x000001F5, 0x0000026B, 0x0000026A, 0x00050041, 0x000001FE, +0x0000026C, 0x000001FC, 0x000001FD, 0x0004003D, 0x0000007D, 0x0000026D, 0x0000026C, 0x00050057, +0x00000012, 0x0000026E, 0x0000026B, 0x0000026D, 0x0008004F, 0x0000000C, 0x00000270, 0x0000026E, +0x0000026E, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x0000026F, 0x00000270, 0x00050039, +0x0000000C, 0x00000271, 0x00000010, 0x0000026F, 0x0005008E, 0x0000000C, 0x00000272, 0x00000271, +0x00000269, 0x00050081, 0x0000000C, 0x00000273, 0x00000267, 0x00000272, 0x000200FE, 0x00000273, +0x00010038, 0x00050036, 0x00000006, 0x00000081, 0x00000000, 0x0000007F, 0x00030037, 0x0000007E, +0x00000080, 0x000200F8, 0x00000082, 0x0004003D, 0x0000007D, 0x00000276, 0x00000080, 0x00050094, +0x00000006, 0x0000027A, 0x00000276, 0x00000279, 0x0006000C, 0x00000006, 0x0000027B, 0x00000001, +0x0000000D, 0x0000027A, 0x00050085, 0x00000006, 0x0000027D, 0x0000027B, 0x0000027C, 0x0006000C, +0x00000006, 0x0000027E, 0x00000001, 0x0000000A, 0x0000027D, 0x000200FE, 0x0000027E, 0x00010038, +0x00050036, 0x0000007D, 0x00000089, 0x00000000, 0x00000085, 0x00030037, 0x00000084, 0x00000086, +0x00030037, 0x00000084, 0x00000087, 0x00030037, 0x00000007, 0x00000088, 0x000200F8, 0x0000008A, +0x0004003B, 0x00000007, 0x00000281, 0x00000007, 0x0004003B, 0x00000007, 0x00000283, 0x00000007, +0x0004003B, 0x00000007, 0x0000028C, 0x00000007, 0x0004003B, 0x00000007, 0x00000293, 0x00000007, +0x0004003B, 0x00000007, 0x00000296, 0x00000007, 0x0003003E, 0x00000281, 0x00000282, 0x0004003D, +0x00000083, 0x00000284, 0x00000086, 0x0004006F, 0x00000006, 0x00000285, 0x00000284, 0x00050081, +0x00000006, 0x00000286, 0x00000285, 0x0000012D, 0x0006000C, 0x00000006, 0x00000287, 0x00000001, +0x0000001F, 0x00000286, 0x0004003D, 0x00000083, 0x00000288, 0x00000087, 0x0004006F, 0x00000006, +0x00000289, 0x00000288, 0x0006000C, 0x00000006, 0x0000028A, 0x00000001, 0x0000001F, 0x00000289, +0x00050088, 0x00000006, 0x0000028B, 0x00000287, 0x0000028A, 0x0003003E, 0x00000283, 0x0000028B, +0x0004003D, 0x00000083, 0x0000028D, 0x00000086, 0x0004006F, 0x00000006, 0x0000028E, 0x0000028D, +0x0004003D, 0x00000006, 0x0000028F, 0x00000281, 0x00050085, 0x00000006, 0x00000290, 0x0000028E, +0x0000028F, 0x0004003D, 0x00000006, 0x00000291, 0x00000088, 0x00050081, 0x00000006, 0x00000292, +0x00000290, 0x00000291, 0x0003003E, 0x0000028C, 0x00000292, 0x0004003D, 0x00000006, 0x00000294, +0x0000028C, 0x0006000C, 0x00000006, 0x00000295, 0x00000001, 0x0000000D, 0x00000294, 0x0003003E, +0x00000293, 0x00000295, 0x0004003D, 0x00000006, 0x00000297, 0x0000028C, 0x0006000C, 0x00000006, +0x00000298, 0x00000001, 0x0000000E, 0x00000297, 0x0003003E, 0x00000296, 0x00000298, 0x0004003D, +0x00000006, 0x00000299, 0x00000283, 0x0004003D, 0x00000006, 0x0000029A, 0x00000296, 0x00050085, +0x00000006, 0x0000029B, 0x00000299, 0x0000029A, 0x0004003D, 0x00000006, 0x0000029C, 0x00000283, +0x0004003D, 0x00000006, 0x0000029D, 0x00000293, 0x00050085, 0x00000006, 0x0000029E, 0x0000029C, +0x0000029D, 0x00050050, 0x0000007D, 0x0000029F, 0x0000029B, 0x0000029E, 0x000200FE, 0x0000029F, +0x00010038, 0x00050036, 0x00000006, 0x0000008F, 0x00000000, 0x0000008B, 0x00030037, 0x0000000D, +0x0000008C, 0x00030037, 0x0000000D, 0x0000008D, 0x00030037, 0x00000084, 0x0000008E, 0x000200F8, +0x00000090, 0x0004003B, 0x00000007, 0x000002A2, 0x00000007, 0x0004003B, 0x00000007, 0x000002B0, +0x00000007, 0x00050041, 0x000001DF, 0x000002AE, 0x000002AC, 0x000002AD, 0x0004003D, 0x00000006, +0x000002AF, 0x000002AE, 0x0003003E, 0x000002A2, 0x000002AF, 0x0004003D, 0x00000006, 0x000002B1, +0x000002A2, 0x0004003D, 0x0000000C, 0x000002B2, 0x0000008D, 0x0004003D, 0x0000000C, 0x000002B3, +0x0000008C, 0x00050094, 0x00000006, 0x000002B4, 0x000002B2, 0x000002B3, 0x00050083, 0x00000006, +0x000002B5, 0x000000D3, 0x000002B4, 0x00050085, 0x00000006, 0x000002B6, 0x000002B1, 0x000002B5, +0x0004003D, 0x00000006, 0x000002B7, 0x000002A2, 0x0007000C, 0x00000006, 0x000002B8, 0x00000001, +0x00000028, 0x000002B6, 0x000002B7, 0x0003003E, 0x000002B0, 0x000002B8, 0x0004003D, 0x00000006, +0x000002B9, 0x000002B0, 0x000200FE, 0x000002B9, 0x00010038, 0x00050036, 0x00000006, 0x0000009C, +0x00000000, 0x00000094, 0x00030037, 0x00000093, 0x00000095, 0x00030037, 0x00000013, 0x00000096, +0x00030037, 0x00000007, 0x00000097, 0x00030037, 0x0000000D, 0x00000098, 0x00030037, 0x0000000D, +0x00000099, 0x00030037, 0x0000000D, 0x0000009A, 0x00030037, 0x00000084, 0x0000009B, 0x000200F8, +0x0000009D, 0x0004003B, 0x00000007, 0x000002BC, 0x00000007, 0x0004003B, 0x0000000D, 0x000002BD, +0x00000007, 0x0004003B, 0x0000000D, 0x000002BF, 0x00000007, 0x0004003B, 0x00000084, 0x000002C1, +0x00000007, 0x0004003B, 0x00000007, 0x000002C4, 0x00000007, 0x0004003B, 0x00000007, 0x000002C5, +0x00000007, 0x0004003B, 0x0000007E, 0x000002C6, 0x00000007, 0x0004003B, 0x00000084, 0x000002CA, +0x00000007, 0x0004003B, 0x0000007E, 0x000002D3, 0x00000007, 0x0004003B, 0x00000084, 0x000002D4, +0x00000007, 0x0004003B, 0x00000084, 0x000002D6, 0x00000007, 0x0004003B, 0x00000007, 0x000002D7, +0x00000007, 0x0004003B, 0x00000007, 0x000002DD, 0x00000007, 0x0004003D, 0x0000000C, 0x000002BE, +0x00000098, 0x0003003E, 0x000002BD, 0x000002BE, 0x0004003D, 0x0000000C, 0x000002C0, 0x00000099, +0x0003003E, 0x000002BF, 0x000002C0, 0x0004003D, 0x00000083, 0x000002C2, 0x0000009B, 0x0003003E, +0x000002C1, 0x000002C2, 0x00070039, 0x00000006, 0x000002C3, 0x0000008F, 0x000002BD, 0x000002BF, +0x000002C1, 0x0003003E, 0x000002BC, 0x000002C3, 0x0003003E, 0x000002C4, 0x000000F6, 0x0004003D, +0x0000000C, 0x000002C7, 0x0000009A, 0x0007004F, 0x0000007D, 0x000002C8, 0x000002C7, 0x000002C7, +0x00000000, 0x00000001, 0x0003003E, 0x000002C6, 0x000002C8, 0x00050039, 0x00000006, 0x000002C9, +0x00000081, 0x000002C6, 0x0003003E, 0x000002C5, 0x000002C9, 0x0003003E, 0x000002CA, 0x000001E7, +0x000200F9, 0x000002CB, 0x000200F8, 0x000002CB, 0x000400F6, 0x000002CD, 0x000002CE, 0x00000000, +0x000200F9, 0x000002CF, 0x000200F8, 0x000002CF, 0x0004003D, 0x00000083, 0x000002D0, 0x000002CA, +0x000500B1, 0x000001E3, 0x000002D2, 0x000002D0, 0x000002D1, 0x000400FA, 0x000002D2, 0x000002CC, +0x000002CD, 0x000200F8, 0x000002CC, 0x0004003D, 0x00000083, 0x000002D5, 0x000002CA, 0x0003003E, +0x000002D4, 0x000002D5, 0x0003003E, 0x000002D6, 0x000002D1, 0x0004003D, 0x00000006, 0x000002D8, +0x000002C5, 0x0003003E, 0x000002D7, 0x000002D8, 0x00070039, 0x0000007D, 0x000002D9, 0x00000089, +0x000002D4, 0x000002D6, 0x000002D7, 0x00050050, 0x0000007D, 0x000002DB, 0x000002DA, 0x000002DA, +0x00050088, 0x0000007D, 0x000002DC, 0x000002D9, 0x000002DB, 0x0003003E, 0x000002D3, 0x000002DC, +0x0004003D, 0x00000092, 0x000002DE, 0x00000095, 0x0004003D, 0x00000012, 0x000002DF, 0x00000096, +0x0007004F, 0x0000007D, 0x000002E0, 0x000002DF, 0x000002DF, 0x00000000, 0x00000001, 0x0004003D, +0x0000007D, 0x000002E1, 0x000002D3, 0x00050081, 0x0000007D, 0x000002E2, 0x000002E0, 0x000002E1, +0x0004003D, 0x00000083, 0x000002E3, 0x0000009B, 0x0004006F, 0x00000006, 0x000002E4, 0x000002E3, +0x00050051, 0x00000006, 0x000002E5, 0x000002E2, 0x00000000, 0x00050051, 0x00000006, 0x000002E6, +0x000002E2, 0x00000001, 0x00060050, 0x0000000C, 0x000002E7, 0x000002E5, 0x000002E6, 0x000002E4, +0x00050057, 0x00000012, 0x000002E8, 0x000002DE, 0x000002E7, 0x00050051, 0x00000006, 0x000002E9, +0x000002E8, 0x00000000, 0x0003003E, 0x000002DD, 0x000002E9, 0x00050041, 0x00000007, 0x000002EB, +0x00000096, 0x000002EA, 0x0004003D, 0x00000006, 0x000002EC, 0x000002EB, 0x0004003D, 0x00000006, +0x000002ED, 0x000002BC, 0x00050083, 0x00000006, 0x000002EE, 0x000002EC, 0x000002ED, 0x0004003D, +0x00000006, 0x000002EF, 0x000002DD, 0x0007000C, 0x00000006, 0x000002F0, 0x00000001, 0x00000030, +0x000002EE, 0x000002EF, 0x0004003D, 0x00000006, 0x000002F1, 0x000002C4, 0x00050081, 0x00000006, +0x000002F2, 0x000002F1, 0x000002F0, 0x0003003E, 0x000002C4, 0x000002F2, 0x000200F9, 0x000002CE, +0x000200F8, 0x000002CE, 0x0004003D, 0x00000083, 0x000002F3, 0x000002CA, 0x00050080, 0x00000083, +0x000002F4, 0x000002F3, 0x000001FD, 0x0003003E, 0x000002CA, 0x000002F4, 0x000200F9, 0x000002CB, +0x000200F8, 0x000002CD, 0x0004003D, 0x00000006, 0x000002F5, 0x000002C4, 0x00050088, 0x00000006, +0x000002F7, 0x000002F5, 0x000002F6, 0x000200FE, 0x000002F7, 0x00010038, 0x00050036, 0x00000083, +0x000000A0, 0x00000000, 0x0000009E, 0x00030037, 0x0000000D, 0x0000009F, 0x000200F8, 0x000000A1, +0x0004003B, 0x00000084, 0x000002FA, 0x00000007, 0x0004003B, 0x00000013, 0x000002FB, 0x00000007, +0x0004003B, 0x00000084, 0x00000305, 0x00000007, 0x0003003E, 0x000002FA, 0x000001E7, 0x00050041, +0x000002FC, 0x000002FD, 0x000002AC, 0x0000020E, 0x0004003D, 0x000002A6, 0x000002FE, 0x000002FD, +0x0004003D, 0x0000000C, 0x000002FF, 0x0000009F, 0x00050051, 0x00000006, 0x00000300, 0x000002FF, +0x00000000, 0x00050051, 0x00000006, 0x00000301, 0x000002FF, 0x00000001, 0x00050051, 0x00000006, +0x00000302, 0x000002FF, 0x00000002, 0x00070050, 0x00000012, 0x00000303, 0x00000300, 0x00000301, +0x00000302, 0x000000D3, 0x00050091, 0x00000012, 0x00000304, 0x000002FE, 0x00000303, 0x0003003E, +0x000002FB, 0x00000304, 0x0003003E, 0x00000305, 0x000001E7, 0x000200F9, 0x00000306, 0x000200F8, +0x00000306, 0x000400F6, 0x00000308, 0x00000309, 0x00000000, 0x000200F9, 0x0000030A, 0x000200F8, +0x0000030A, 0x0004003D, 0x00000083, 0x0000030B, 0x00000305, 0x00050041, 0x0000030D, 0x0000030E, +0x000002AC, 0x0000030C, 0x0004003D, 0x00000083, 0x0000030F, 0x0000030E, 0x00050082, 0x00000083, +0x00000310, 0x0000030F, 0x000001FD, 0x000500B1, 0x000001E3, 0x00000311, 0x0000030B, 0x00000310, +0x000400FA, 0x00000311, 0x00000307, 0x00000308, 0x000200F8, 0x00000307, 0x00050041, 0x00000007, +0x00000312, 0x000002FB, 0x000002EA, 0x0004003D, 0x00000006, 0x00000313, 0x00000312, 0x0004003D, +0x00000083, 0x00000314, 0x00000305, 0x00070041, 0x000001DF, 0x00000315, 0x000002AC, 0x00000208, +0x00000314, 0x0000023C, 0x0004003D, 0x00000006, 0x00000316, 0x00000315, 0x000500B8, 0x000001E3, +0x00000317, 0x00000313, 0x00000316, 0x000300F7, 0x00000319, 0x00000000, 0x000400FA, 0x00000317, +0x00000318, 0x00000319, 0x000200F8, 0x00000318, 0x0004003D, 0x00000083, 0x0000031A, 0x00000305, +0x00050080, 0x00000083, 0x0000031B, 0x0000031A, 0x000001FD, 0x0003003E, 0x000002FA, 0x0000031B, +0x000200F9, 0x00000319, 0x000200F8, 0x00000319, 0x000200F9, 0x00000309, 0x000200F8, 0x00000309, +0x0004003D, 0x00000083, 0x0000031C, 0x00000305, 0x00050080, 0x00000083, 0x0000031D, 0x0000031C, +0x000001FD, 0x0003003E, 0x00000305, 0x0000031D, 0x000200F9, 0x00000306, 0x000200F8, 0x00000308, +0x0004003D, 0x00000083, 0x0000031E, 0x000002FA, 0x000200FE, 0x0000031E, 0x00010038, 0x00050036, +0x00000006, 0x000000A7, 0x00000000, 0x000000A2, 0x00030037, 0x0000000D, 0x000000A3, 0x00030037, +0x00000084, 0x000000A4, 0x00030037, 0x0000000D, 0x000000A5, 0x00030037, 0x0000000D, 0x000000A6, +0x000200F8, 0x000000A8, 0x0004003B, 0x00000013, 0x00000321, 0x00000007, 0x0004003B, 0x00000007, +0x00000333, 0x00000007, 0x0004003B, 0x00000007, 0x00000335, 0x00000007, 0x0004003B, 0x00000013, +0x00000340, 0x00000007, 0x0004003B, 0x00000007, 0x00000349, 0x00000007, 0x0004003B, 0x00000013, +0x0000034B, 0x00000007, 0x0004003B, 0x00000007, 0x0000034D, 0x00000007, 0x0004003B, 0x0000000D, +0x0000034F, 0x00000007, 0x0004003B, 0x0000000D, 0x00000351, 0x00000007, 0x0004003B, 0x0000000D, +0x00000353, 0x00000007, 0x0004003B, 0x00000084, 0x00000355, 0x00000007, 0x0004003B, 0x00000007, +0x00000358, 0x00000007, 0x0004003B, 0x00000084, 0x00000365, 0x00000007, 0x0004003B, 0x00000007, +0x0000037F, 0x00000007, 0x0004003B, 0x00000013, 0x00000380, 0x00000007, 0x0004003B, 0x00000007, +0x00000382, 0x00000007, 0x0004003B, 0x0000000D, 0x00000384, 0x00000007, 0x0004003B, 0x0000000D, +0x00000386, 0x00000007, 0x0004003B, 0x0000000D, 0x00000388, 0x00000007, 0x0004003B, 0x00000084, +0x0000038A, 0x00000007, 0x00050041, 0x000002FC, 0x00000322, 0x000002AC, 0x0000025E, 0x0004003D, +0x000002A6, 0x00000323, 0x00000322, 0x0004003D, 0x00000083, 0x00000324, 0x000000A4, 0x00060041, +0x000002FC, 0x00000325, 0x000002AC, 0x000001FD, 0x00000324, 0x0004003D, 0x000002A6, 0x00000326, +0x00000325, 0x00050092, 0x000002A6, 0x00000327, 0x00000323, 0x00000326, 0x0004003D, 0x0000000C, +0x00000328, 0x000000A3, 0x00050051, 0x00000006, 0x00000329, 0x00000328, 0x00000000, 0x00050051, +0x00000006, 0x0000032A, 0x00000328, 0x00000001, 0x00050051, 0x00000006, 0x0000032B, 0x00000328, +0x00000002, 0x00070050, 0x00000012, 0x0000032C, 0x00000329, 0x0000032A, 0x0000032B, 0x000000D3, +0x00050091, 0x00000012, 0x0000032D, 0x00000327, 0x0000032C, 0x0003003E, 0x00000321, 0x0000032D, +0x0004003D, 0x00000012, 0x0000032E, 0x00000321, 0x00050041, 0x00000007, 0x0000032F, 0x00000321, +0x000000EC, 0x0004003D, 0x00000006, 0x00000330, 0x0000032F, 0x00050088, 0x00000006, 0x00000331, +0x000000D3, 0x00000330, 0x0005008E, 0x00000012, 0x00000332, 0x0000032E, 0x00000331, 0x0003003E, +0x00000321, 0x00000332, 0x0003003E, 0x00000333, 0x00000334, 0x00050041, 0x000001DF, 0x00000336, +0x000002AC, 0x00000226, 0x0004003D, 0x00000006, 0x00000337, 0x00000336, 0x0004003D, 0x00000006, +0x00000338, 0x00000333, 0x00050085, 0x00000006, 0x00000339, 0x00000337, 0x00000338, 0x00050041, +0x00000007, 0x0000033A, 0x00000321, 0x000002EA, 0x0004003D, 0x00000006, 0x0000033B, 0x0000033A, +0x00050088, 0x00000006, 0x0000033C, 0x00000339, 0x0000033B, 0x0003003E, 0x00000335, 0x0000033C, +0x0004003D, 0x00000006, 0x0000033D, 0x00000335, 0x0007000C, 0x00000006, 0x0000033F, 0x00000001, +0x00000025, 0x0000033D, 0x0000033E, 0x0003003E, 0x00000335, 0x0000033F, 0x00050041, 0x000002FC, +0x00000341, 0x000002AC, 0x0000020E, 0x0004003D, 0x000002A6, 0x00000342, 0x00000341, 0x0004003D, +0x0000000C, 0x00000343, 0x000000A3, 0x00050051, 0x00000006, 0x00000344, 0x00000343, 0x00000000, +0x00050051, 0x00000006, 0x00000345, 0x00000343, 0x00000001, 0x00050051, 0x00000006, 0x00000346, +0x00000343, 0x00000002, 0x00070050, 0x00000012, 0x00000347, 0x00000344, 0x00000345, 0x00000346, +0x000000D3, 0x00050091, 0x00000012, 0x00000348, 0x00000342, 0x00000347, 0x0003003E, 0x00000340, +0x00000348, 0x0003003E, 0x00000349, 0x000000D3, 0x0004003D, 0x00000012, 0x0000034C, 0x00000321, +0x0003003E, 0x0000034B, 0x0000034C, 0x0004003D, 0x00000006, 0x0000034E, 0x00000335, 0x0003003E, +0x0000034D, 0x0000034E, 0x0004003D, 0x0000000C, 0x00000350, 0x000000A5, 0x0003003E, 0x0000034F, +0x00000350, 0x0004003D, 0x0000000C, 0x00000352, 0x000000A6, 0x0003003E, 0x00000351, 0x00000352, +0x0004003D, 0x0000000C, 0x00000354, 0x000000A3, 0x0003003E, 0x00000353, 0x00000354, 0x0004003D, +0x00000083, 0x00000356, 0x000000A4, 0x0003003E, 0x00000355, 0x00000356, 0x000B0039, 0x00000006, +0x00000357, 0x0000009C, 0x0000034A, 0x0000034B, 0x0000034D, 0x0000034F, 0x00000351, 0x00000353, +0x00000355, 0x0003003E, 0x00000349, 0x00000357, 0x0004003D, 0x00000083, 0x00000359, 0x000000A4, +0x00070041, 0x000001DF, 0x0000035A, 0x000002AC, 0x00000208, 0x00000359, 0x0000023C, 0x0004003D, +0x00000006, 0x0000035B, 0x0000035A, 0x00050041, 0x000001DF, 0x0000035C, 0x000002AC, 0x00000242, +0x0004003D, 0x00000006, 0x0000035D, 0x0000035C, 0x00050081, 0x00000006, 0x0000035E, 0x0000035B, +0x0000035D, 0x0004003D, 0x00000083, 0x0000035F, 0x000000A4, 0x00070041, 0x000001DF, 0x00000360, +0x000002AC, 0x00000208, 0x0000035F, 0x0000023C, 0x0004003D, 0x00000006, 0x00000361, 0x00000360, +0x00050041, 0x00000007, 0x00000362, 0x00000340, 0x000002EA, 0x0004003D, 0x00000006, 0x00000363, +0x00000362, 0x0008000C, 0x00000006, 0x00000364, 0x00000001, 0x00000031, 0x0000035E, 0x00000361, +0x00000363, 0x0003003E, 0x00000358, 0x00000364, 0x0004003D, 0x00000083, 0x00000366, 0x000000A4, +0x00050080, 0x00000083, 0x00000367, 0x00000366, 0x000001FD, 0x0003003E, 0x00000365, 0x00000367, +0x0004003D, 0x00000006, 0x00000368, 0x00000358, 0x000500BA, 0x000001E3, 0x00000369, 0x00000368, +0x000000F6, 0x000300F7, 0x0000036B, 0x00000000, 0x000400FA, 0x00000369, 0x0000036A, 0x0000036B, +0x000200F8, 0x0000036A, 0x0004003D, 0x00000083, 0x0000036C, 0x00000365, 0x00050041, 0x0000030D, +0x0000036D, 0x000002AC, 0x0000030C, 0x0004003D, 0x00000083, 0x0000036E, 0x0000036D, 0x000500B1, +0x000001E3, 0x0000036F, 0x0000036C, 0x0000036E, 0x000200F9, 0x0000036B, 0x000200F8, 0x0000036B, +0x000700F5, 0x000001E3, 0x00000370, 0x00000369, 0x000000A8, 0x0000036F, 0x0000036A, 0x000300F7, +0x00000372, 0x00000000, 0x000400FA, 0x00000370, 0x00000371, 0x00000372, 0x000200F8, 0x00000371, +0x00050041, 0x000002FC, 0x00000373, 0x000002AC, 0x0000025E, 0x0004003D, 0x000002A6, 0x00000374, +0x00000373, 0x0004003D, 0x00000083, 0x00000375, 0x00000365, 0x00060041, 0x000002FC, 0x00000376, +0x000002AC, 0x000001FD, 0x00000375, 0x0004003D, 0x000002A6, 0x00000377, 0x00000376, 0x00050092, +0x000002A6, 0x00000378, 0x00000374, 0x00000377, 0x0004003D, 0x0000000C, 0x00000379, 0x000000A3, +0x00050051, 0x00000006, 0x0000037A, 0x00000379, 0x00000000, 0x00050051, 0x00000006, 0x0000037B, +0x00000379, 0x00000001, 0x00050051, 0x00000006, 0x0000037C, 0x00000379, 0x00000002, 0x00070050, +0x00000012, 0x0000037D, 0x0000037A, 0x0000037B, 0x0000037C, 0x000000D3, 0x00050091, 0x00000012, +0x0000037E, 0x00000378, 0x0000037D, 0x0003003E, 0x00000321, 0x0000037E, 0x0004003D, 0x00000012, +0x00000381, 0x00000321, 0x0003003E, 0x00000380, 0x00000381, 0x0004003D, 0x00000006, 0x00000383, +0x00000335, 0x0003003E, 0x00000382, 0x00000383, 0x0004003D, 0x0000000C, 0x00000385, 0x000000A5, +0x0003003E, 0x00000384, 0x00000385, 0x0004003D, 0x0000000C, 0x00000387, 0x000000A6, 0x0003003E, +0x00000386, 0x00000387, 0x0004003D, 0x0000000C, 0x00000389, 0x000000A3, 0x0003003E, 0x00000388, +0x00000389, 0x0004003D, 0x00000083, 0x0000038B, 0x00000365, 0x0003003E, 0x0000038A, 0x0000038B, +0x000B0039, 0x00000006, 0x0000038C, 0x0000009C, 0x0000034A, 0x00000380, 0x00000382, 0x00000384, +0x00000386, 0x00000388, 0x0000038A, 0x0003003E, 0x0000037F, 0x0000038C, 0x0004003D, 0x00000006, +0x0000038D, 0x00000349, 0x0004003D, 0x00000006, 0x0000038E, 0x0000037F, 0x0004003D, 0x00000006, +0x0000038F, 0x00000358, 0x0008000C, 0x00000006, 0x00000390, 0x00000001, 0x0000002E, 0x0000038D, +0x0000038E, 0x0000038F, 0x0003003E, 0x00000349, 0x00000390, 0x000200F9, 0x00000372, 0x000200F8, +0x00000372, 0x0004003D, 0x00000006, 0x00000391, 0x00000349, 0x00050083, 0x00000006, 0x00000392, +0x000000D3, 0x00000391, 0x0004003D, 0x00000006, 0x00000393, 0x000000D2, 0x00050085, 0x00000006, +0x00000394, 0x00000392, 0x00000393, 0x00050083, 0x00000006, 0x00000395, 0x000000D3, 0x00000394, +0x000200FE, 0x00000395, 0x00010038, 0x00050036, 0x0000000C, 0x000000B3, 0x00000000, 0x000000AB, +0x00030037, 0x000000A9, 0x000000AC, 0x00030037, 0x000000AA, 0x000000AD, 0x00030037, 0x0000000C, +0x000000AE, 0x00030037, 0x00000007, 0x000000AF, 0x00030037, 0x00000007, 0x000000B0, 0x00030037, +0x00000007, 0x000000B1, 0x00030037, 0x00000007, 0x000000B2, 0x000200F8, 0x000000B4, 0x0004003B, +0x00000007, 0x00000398, 0x00000007, 0x0004003B, 0x00000007, 0x0000039A, 0x00000007, 0x0004003B, +0x00000007, 0x0000039C, 0x00000007, 0x0004003B, 0x00000007, 0x0000039F, 0x00000007, 0x0004003B, +0x00000007, 0x000003A0, 0x00000007, 0x0004003B, 0x00000007, 0x000003A2, 0x00000007, 0x0004003B, +0x00000007, 0x000003A4, 0x00000007, 0x0004003B, 0x0000000D, 0x000003A7, 0x00000007, 0x0004003B, +0x00000007, 0x000003A9, 0x00000007, 0x00050051, 0x0000000C, 0x00000399, 0x000000AC, 0x00000006, +0x00050051, 0x00000006, 0x0000039B, 0x000000AC, 0x00000002, 0x0003003E, 0x0000039A, 0x0000039B, +0x0004003D, 0x00000006, 0x0000039D, 0x000000B1, 0x0003003E, 0x0000039C, 0x0000039D, 0x00080039, +0x00000006, 0x0000039E, 0x0000005D, 0x0000039A, 0x0000039C, 0x00000399, 0x000000AE, 0x0003003E, +0x00000398, 0x0000039E, 0x00050051, 0x00000006, 0x000003A1, 0x000000AC, 0x00000002, 0x0003003E, +0x000003A0, 0x000003A1, 0x0004003D, 0x00000006, 0x000003A3, 0x000000AF, 0x0003003E, 0x000003A2, +0x000003A3, 0x0004003D, 0x00000006, 0x000003A5, 0x000000B0, 0x0003003E, 0x000003A4, 0x000003A5, +0x00070039, 0x00000006, 0x000003A6, 0x00000062, 0x000003A0, 0x000003A2, 0x000003A4, 0x0003003E, +0x0000039F, 0x000003A6, 0x00050051, 0x0000000C, 0x000003A8, 0x000000AC, 0x0000000A, 0x0004003D, +0x00000006, 0x000003AA, 0x000000B2, 0x0003003E, 0x000003A9, 0x000003AA, 0x00060039, 0x0000000C, +0x000003AB, 0x00000067, 0x000003A8, 0x000003A9, 0x0003003E, 0x000003A7, 0x000003AB, 0x0004003D, +0x00000006, 0x000003AC, 0x00000398, 0x0004003D, 0x00000006, 0x000003AD, 0x0000039F, 0x00050085, +0x00000006, 0x000003AE, 0x000003AC, 0x000003AD, 0x0004003D, 0x0000000C, 0x000003AF, 0x000003A7, +0x0005008E, 0x0000000C, 0x000003B0, 0x000003AF, 0x000003AE, 0x000200FE, 0x000003B0, 0x00010038, +0x00050036, 0x0000000C, 0x000000BA, 0x00000000, 0x000000B5, 0x00030037, 0x000000A9, 0x000000B6, +0x00030037, 0x00000007, 0x000000B7, 0x00030037, 0x00000007, 0x000000B8, 0x00030037, 0x00000007, +0x000000B9, 0x000200F8, 0x000000BB, 0x0004003B, 0x00000007, 0x000003B5, 0x00000007, 0x0004003B, +0x00000007, 0x000003B7, 0x00000007, 0x0004003B, 0x00000007, 0x000003B9, 0x00000007, 0x0004003B, +0x00000007, 0x000003BB, 0x00000007, 0x00050051, 0x00000012, 0x000003B3, 0x000000B6, 0x00000000, +0x0008004F, 0x0000000C, 0x000003B4, 0x000003B3, 0x000003B3, 0x00000000, 0x00000001, 0x00000002, +0x00050051, 0x00000006, 0x000003B6, 0x000000B6, 0x00000002, 0x0003003E, 0x000003B5, 0x000003B6, +0x0004003D, 0x00000006, 0x000003B8, 0x000000B7, 0x0003003E, 0x000003B7, 0x000003B8, 0x0004003D, +0x00000006, 0x000003BA, 0x000000B8, 0x0003003E, 0x000003B9, 0x000003BA, 0x0004003D, 0x00000006, +0x000003BC, 0x000000B9, 0x0003003E, 0x000003BB, 0x000003BC, 0x00080039, 0x00000006, 0x000003BD, +0x00000043, 0x000003B5, 0x000003B7, 0x000003B9, 0x000003BB, 0x0005008E, 0x0000000C, 0x000003BE, +0x000003B4, 0x000003BD, 0x000200FE, 0x000003BE, 0x00010038, 0x00050036, 0x0000000C, 0x000000C3, +0x00000000, 0x000000AB, 0x00030037, 0x000000A9, 0x000000BC, 0x00030037, 0x000000AA, 0x000000BD, +0x00030037, 0x0000000C, 0x000000BE, 0x00030037, 0x00000007, 0x000000BF, 0x00030037, 0x00000007, +0x000000C0, 0x00030037, 0x00000007, 0x000000C1, 0x00030037, 0x00000007, 0x000000C2, 0x000200F8, +0x000000C4, 0x0004003B, 0x00000007, 0x000003C1, 0x00000007, 0x0004003B, 0x00000007, 0x000003C3, +0x00000007, 0x0004003B, 0x00000007, 0x000003C5, 0x00000007, 0x0004003B, 0x00000007, 0x000003C7, +0x00000007, 0x0004003D, 0x00000006, 0x000003C2, 0x000000BF, 0x0003003E, 0x000003C1, 0x000003C2, +0x0004003D, 0x00000006, 0x000003C4, 0x000000C0, 0x0003003E, 0x000003C3, 0x000003C4, 0x0004003D, +0x00000006, 0x000003C6, 0x000000C1, 0x0003003E, 0x000003C5, 0x000003C6, 0x0004003D, 0x00000006, +0x000003C8, 0x000000C2, 0x0003003E, 0x000003C7, 0x000003C8, 0x000B0039, 0x0000000C, 0x000003C9, +0x000000B3, 0x000000BC, 0x000000BD, 0x000000BE, 0x000003C1, 0x000003C3, 0x000003C5, 0x000003C7, +0x000200FE, 0x000003C9, 0x00010038, 0x00050036, 0x0000000C, 0x000000CA, 0x00000000, 0x000000C6, +0x00030037, 0x0000000D, 0x000000C7, 0x00030037, 0x0000000D, 0x000000C8, 0x00030037, 0x000000C5, +0x000000C9, 0x000200F8, 0x000000CB, 0x0004003B, 0x0000000D, 0x000003CC, 0x00000007, 0x0004003B, +0x00000084, 0x000003CE, 0x00000007, 0x0004003B, 0x000003D9, 0x000003DA, 0x00000007, 0x0004003B, +0x00000007, 0x000003EE, 0x00000007, 0x0004003B, 0x0000000D, 0x000003F4, 0x00000007, 0x0004003B, +0x00000007, 0x000003FA, 0x00000007, 0x0004003B, 0x00000007, 0x000003FF, 0x00000007, 0x0004003B, +0x00000007, 0x00000406, 0x00000007, 0x0004003B, 0x0000000D, 0x0000041F, 0x00000007, 0x0004003B, +0x00000007, 0x00000425, 0x00000007, 0x0004003B, 0x00000007, 0x00000429, 0x00000007, 0x0004003B, +0x00000007, 0x0000042E, 0x00000007, 0x0004003B, 0x00000007, 0x00000434, 0x00000007, 0x0004003B, +0x00000007, 0x0000043A, 0x00000007, 0x0004003B, 0x00000084, 0x0000044B, 0x00000007, 0x0004003B, +0x0000000D, 0x0000044C, 0x00000007, 0x0004003B, 0x0000000D, 0x00000455, 0x00000007, 0x0004003B, +0x00000084, 0x00000457, 0x00000007, 0x0004003B, 0x0000000D, 0x00000459, 0x00000007, 0x0004003B, +0x0000000D, 0x0000045D, 0x00000007, 0x0004003B, 0x0000000D, 0x00000462, 0x00000007, 0x0004003B, +0x0000000D, 0x00000466, 0x00000007, 0x0004003B, 0x0000000D, 0x0000046D, 0x00000007, 0x0004003B, +0x00000007, 0x00000473, 0x00000007, 0x0004003B, 0x00000007, 0x00000478, 0x00000007, 0x0004003B, +0x0000000D, 0x0000047A, 0x00000007, 0x0004003B, 0x00000007, 0x00000480, 0x00000007, 0x0004003B, +0x00000007, 0x00000486, 0x00000007, 0x0004003B, 0x00000007, 0x00000488, 0x00000007, 0x0004003B, +0x00000007, 0x0000048A, 0x00000007, 0x0004003B, 0x00000007, 0x0000048B, 0x00000007, 0x0004003B, +0x00000007, 0x0000048E, 0x00000007, 0x0004003B, 0x00000007, 0x00000493, 0x00000007, 0x0004003B, +0x00000007, 0x00000495, 0x00000007, 0x0004003B, 0x00000007, 0x00000499, 0x00000007, 0x0004003B, +0x0000000D, 0x0000049B, 0x00000007, 0x0004003B, 0x00000007, 0x0000049D, 0x00000007, 0x0004003B, +0x00000007, 0x0000049F, 0x00000007, 0x0004003B, 0x00000007, 0x000004A1, 0x00000007, 0x0004003B, +0x0000000D, 0x000004A4, 0x00000007, 0x0004003B, 0x00000007, 0x000004A8, 0x00000007, 0x0004003B, +0x00000007, 0x000004AA, 0x00000007, 0x0004003B, 0x00000007, 0x000004AC, 0x00000007, 0x0004003B, +0x00000007, 0x000004AE, 0x00000007, 0x0004003B, 0x0000000D, 0x000004B1, 0x00000007, 0x0004003B, +0x00000007, 0x000004BB, 0x00000007, 0x0004003B, 0x00000007, 0x000004BD, 0x00000007, 0x0003003E, +0x000003CC, 0x000003CD, 0x0003003E, 0x000003CE, 0x000001E7, 0x000200F9, 0x000003CF, 0x000200F8, +0x000003CF, 0x000400F6, 0x000003D1, 0x000003D2, 0x00000000, 0x000200F9, 0x000003D3, 0x000200F8, +0x000003D3, 0x0004003D, 0x00000083, 0x000003D4, 0x000003CE, 0x00050041, 0x0000030D, 0x000003D6, +0x000002AC, 0x000003D5, 0x0004003D, 0x00000083, 0x000003D7, 0x000003D6, 0x000500B1, 0x000001E3, +0x000003D8, 0x000003D4, 0x000003D7, 0x000400FA, 0x000003D8, 0x000003D0, 0x000003D1, 0x000200F8, +0x000003D0, 0x0004003D, 0x00000083, 0x000003DB, 0x000003CE, 0x00060041, 0x000003DC, 0x000003DD, +0x000002AC, 0x000001E7, 0x000003DB, 0x0004003D, 0x000002A3, 0x000003DE, 0x000003DD, 0x00050051, +0x00000012, 0x000003DF, 0x000003DE, 0x00000000, 0x00050041, 0x00000013, 0x000003E0, 0x000003DA, +0x000001E7, 0x0003003E, 0x000003E0, 0x000003DF, 0x00050051, 0x00000012, 0x000003E1, 0x000003DE, +0x00000001, 0x00050041, 0x00000013, 0x000003E2, 0x000003DA, 0x000001FD, 0x0003003E, 0x000003E2, +0x000003E1, 0x00050051, 0x00000012, 0x000003E3, 0x000003DE, 0x00000002, 0x00050041, 0x00000013, +0x000003E4, 0x000003DA, 0x0000020E, 0x0003003E, 0x000003E4, 0x000003E3, 0x00050051, 0x00000006, +0x000003E5, 0x000003DE, 0x00000003, 0x00050041, 0x00000007, 0x000003E7, 0x000003DA, 0x000003E6, +0x0003003E, 0x000003E7, 0x000003E5, 0x00050051, 0x00000006, 0x000003E8, 0x000003DE, 0x00000004, +0x00050041, 0x00000007, 0x000003E9, 0x000003DA, 0x0000025E, 0x0003003E, 0x000003E9, 0x000003E8, +0x00050051, 0x00000006, 0x000003EA, 0x000003DE, 0x00000005, 0x00050041, 0x00000007, 0x000003EB, +0x000003DA, 0x000001DE, 0x0003003E, 0x000003EB, 0x000003EA, 0x00050051, 0x00000006, 0x000003EC, +0x000003DE, 0x00000006, 0x00050041, 0x00000007, 0x000003ED, 0x000003DA, 0x00000208, 0x0003003E, +0x000003ED, 0x000003EC, 0x0003003E, 0x000003EE, 0x000000F6, 0x00050041, 0x00000007, 0x000003EF, +0x000003DA, 0x000001DE, 0x0004003D, 0x00000006, 0x000003F0, 0x000003EF, 0x000500B4, 0x000001E3, +0x000003F1, 0x000003F0, 0x0000012E, 0x000300F7, 0x000003F3, 0x00000000, 0x000400FA, 0x000003F1, +0x000003F2, 0x00000419, 0x000200F8, 0x000003F2, 0x00050041, 0x00000013, 0x000003F5, 0x000003DA, +0x000001FD, 0x0004003D, 0x00000012, 0x000003F6, 0x000003F5, 0x0008004F, 0x0000000C, 0x000003F7, +0x000003F6, 0x000003F6, 0x00000000, 0x00000001, 0x00000002, 0x0004003D, 0x0000000C, 0x000003F8, +0x000000C8, 0x00050083, 0x0000000C, 0x000003F9, 0x000003F7, 0x000003F8, 0x0003003E, 0x000003F4, +0x000003F9, 0x0004003D, 0x0000000C, 0x000003FB, 0x000003F4, 0x0006000C, 0x00000006, 0x000003FC, +0x00000001, 0x00000042, 0x000003FB, 0x0003003E, 0x000003FA, 0x000003FC, 0x0004003D, 0x0000000C, +0x000003FD, 0x000003F4, 0x0006000C, 0x0000000C, 0x000003FE, 0x00000001, 0x00000045, 0x000003FD, +0x0003003E, 0x000003F4, 0x000003FE, 0x00050041, 0x00000007, 0x00000400, 0x000003DA, 0x0000025E, +0x0004003D, 0x00000006, 0x00000401, 0x00000400, 0x0004003D, 0x00000006, 0x00000402, 0x000003FA, +0x0007000C, 0x00000006, 0x00000403, 0x00000001, 0x0000001A, 0x00000402, 0x0000012E, 0x00050081, +0x00000006, 0x00000404, 0x00000403, 0x000000D3, 0x00050088, 0x00000006, 0x00000405, 0x00000401, +0x00000404, 0x0003003E, 0x000003FF, 0x00000405, 0x0004003D, 0x00000006, 0x00000407, 0x000003FA, +0x0004003D, 0x00000006, 0x00000408, 0x000003FA, 0x00050085, 0x00000006, 0x00000409, 0x00000407, +0x00000408, 0x00050041, 0x00000007, 0x0000040A, 0x000003DA, 0x0000025E, 0x0004003D, 0x00000006, +0x0000040B, 0x0000040A, 0x00050041, 0x00000007, 0x0000040C, 0x000003DA, 0x0000025E, 0x0004003D, +0x00000006, 0x0000040D, 0x0000040C, 0x00050085, 0x00000006, 0x0000040E, 0x0000040B, 0x0000040D, +0x00050088, 0x00000006, 0x0000040F, 0x00000409, 0x0000040E, 0x00050083, 0x00000006, 0x00000410, +0x000000D3, 0x0000040F, 0x0008000C, 0x00000006, 0x00000411, 0x00000001, 0x0000002B, 0x00000410, +0x000000F6, 0x000000D3, 0x0003003E, 0x00000406, 0x00000411, 0x0004003D, 0x00000006, 0x00000412, +0x00000406, 0x0003003E, 0x000003EE, 0x00000412, 0x0004003D, 0x0000000C, 0x00000413, 0x000003F4, +0x00050051, 0x00000006, 0x00000414, 0x00000413, 0x00000000, 0x00050051, 0x00000006, 0x00000415, +0x00000413, 0x00000001, 0x00050051, 0x00000006, 0x00000416, 0x00000413, 0x00000002, 0x00070050, +0x00000012, 0x00000417, 0x00000414, 0x00000415, 0x00000416, 0x000000D3, 0x00050041, 0x00000013, +0x00000418, 0x000003DA, 0x0000020E, 0x0003003E, 0x00000418, 0x00000417, 0x000200F9, 0x000003F3, +0x000200F8, 0x00000419, 0x00050041, 0x00000007, 0x0000041A, 0x000003DA, 0x000001DE, 0x0004003D, +0x00000006, 0x0000041B, 0x0000041A, 0x000500B4, 0x000001E3, 0x0000041C, 0x0000041B, 0x000000D3, +0x000300F7, 0x0000041E, 0x00000000, 0x000400FA, 0x0000041C, 0x0000041D, 0x0000044A, 0x000200F8, +0x0000041D, 0x00050041, 0x00000013, 0x00000420, 0x000003DA, 0x000001FD, 0x0004003D, 0x00000012, +0x00000421, 0x00000420, 0x0008004F, 0x0000000C, 0x00000422, 0x00000421, 0x00000421, 0x00000000, +0x00000001, 0x00000002, 0x0004003D, 0x0000000C, 0x00000423, 0x000000C8, 0x00050083, 0x0000000C, +0x00000424, 0x00000422, 0x00000423, 0x0003003E, 0x0000041F, 0x00000424, 0x00050041, 0x00000007, +0x00000426, 0x000003DA, 0x00000208, 0x0004003D, 0x00000006, 0x00000427, 0x00000426, 0x00050083, +0x00000006, 0x00000428, 0x000000D3, 0x00000427, 0x0003003E, 0x00000425, 0x00000428, 0x0004003D, +0x0000000C, 0x0000042A, 0x0000041F, 0x0006000C, 0x00000006, 0x0000042B, 0x00000001, 0x00000042, +0x0000042A, 0x0003003E, 0x00000429, 0x0000042B, 0x0004003D, 0x0000000C, 0x0000042C, 0x0000041F, +0x0006000C, 0x0000000C, 0x0000042D, 0x00000001, 0x00000045, 0x0000042C, 0x0003003E, 0x0000041F, +0x0000042D, 0x0004003D, 0x0000000C, 0x0000042F, 0x0000041F, 0x00050041, 0x00000013, 0x00000430, +0x000003DA, 0x0000020E, 0x0004003D, 0x00000012, 0x00000431, 0x00000430, 0x0008004F, 0x0000000C, +0x00000432, 0x00000431, 0x00000431, 0x00000000, 0x00000001, 0x00000002, 0x00050094, 0x00000006, +0x00000433, 0x0000042F, 0x00000432, 0x0003003E, 0x0000042E, 0x00000433, 0x0004003D, 0x00000006, +0x00000435, 0x00000425, 0x0004003D, 0x00000006, 0x00000436, 0x00000425, 0x00050085, 0x00000006, +0x00000438, 0x00000436, 0x00000437, 0x00050083, 0x00000006, 0x00000439, 0x00000435, 0x00000438, +0x0003003E, 0x00000434, 0x00000439, 0x0004003D, 0x00000006, 0x0000043B, 0x0000042E, 0x0004003D, +0x00000006, 0x0000043C, 0x00000425, 0x00050083, 0x00000006, 0x0000043D, 0x0000043B, 0x0000043C, +0x0004003D, 0x00000006, 0x0000043E, 0x00000434, 0x00050088, 0x00000006, 0x0000043F, 0x0000043D, +0x0000043E, 0x0003003E, 0x0000043A, 0x0000043F, 0x00050041, 0x00000007, 0x00000440, 0x000003DA, +0x0000025E, 0x0004003D, 0x00000006, 0x00000441, 0x00000440, 0x0004003D, 0x00000006, 0x00000442, +0x00000429, 0x0007000C, 0x00000006, 0x00000443, 0x00000001, 0x0000001A, 0x00000442, 0x0000012E, +0x00050081, 0x00000006, 0x00000444, 0x00000443, 0x000000D3, 0x00050088, 0x00000006, 0x00000445, +0x00000441, 0x00000444, 0x0004003D, 0x00000006, 0x00000446, 0x0000043A, 0x00050085, 0x00000006, +0x00000447, 0x00000446, 0x00000445, 0x0003003E, 0x0000043A, 0x00000447, 0x0004003D, 0x00000006, +0x00000448, 0x0000043A, 0x0008000C, 0x00000006, 0x00000449, 0x00000001, 0x0000002B, 0x00000448, +0x000000F6, 0x000000D3, 0x0003003E, 0x000003EE, 0x00000449, 0x000200F9, 0x0000041E, 0x000200F8, +0x0000044A, 0x0004003D, 0x0000000C, 0x0000044D, 0x000000C8, 0x0003003E, 0x0000044C, 0x0000044D, +0x00050039, 0x00000083, 0x0000044E, 0x000000A0, 0x0000044C, 0x0003003E, 0x0000044B, 0x0000044E, +0x00050041, 0x0000030D, 0x00000450, 0x000002AC, 0x0000044F, 0x0004003D, 0x00000083, 0x00000451, +0x00000450, 0x000500AD, 0x000001E3, 0x00000452, 0x00000451, 0x000001E7, 0x000300F7, 0x00000454, +0x00000000, 0x000400FA, 0x00000452, 0x00000453, 0x00000461, 0x000200F8, 0x00000453, 0x0004003D, +0x0000000C, 0x00000456, 0x000000C8, 0x0003003E, 0x00000455, 0x00000456, 0x0004003D, 0x00000083, +0x00000458, 0x0000044B, 0x0003003E, 0x00000457, 0x00000458, 0x00050041, 0x00000013, 0x0000045A, +0x000003DA, 0x0000020E, 0x0004003D, 0x00000012, 0x0000045B, 0x0000045A, 0x0008004F, 0x0000000C, +0x0000045C, 0x0000045B, 0x0000045B, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000459, +0x0000045C, 0x00050041, 0x0000000D, 0x0000045E, 0x000000C9, 0x00000208, 0x0004003D, 0x0000000C, +0x0000045F, 0x0000045E, 0x0003003E, 0x0000045D, 0x0000045F, 0x00080039, 0x00000006, 0x00000460, +0x000000A7, 0x00000455, 0x00000457, 0x00000459, 0x0000045D, 0x0003003E, 0x000003EE, 0x00000460, +0x000200F9, 0x00000454, 0x000200F8, 0x00000461, 0x0003003E, 0x000003EE, 0x000000D3, 0x000200F9, +0x00000454, 0x000200F8, 0x00000454, 0x000200F9, 0x0000041E, 0x000200F8, 0x0000041E, 0x000200F9, +0x000003F3, 0x000200F8, 0x000003F3, 0x00050041, 0x00000013, 0x00000463, 0x000003DA, 0x0000020E, +0x0004003D, 0x00000012, 0x00000464, 0x00000463, 0x0008004F, 0x0000000C, 0x00000465, 0x00000464, +0x00000464, 0x00000000, 0x00000001, 0x00000002, 0x0003003E, 0x00000462, 0x00000465, 0x00050041, +0x00000013, 0x00000467, 0x000003DA, 0x000001E7, 0x0004003D, 0x00000012, 0x00000468, 0x00000467, +0x0008004F, 0x0000000C, 0x00000469, 0x00000468, 0x00000468, 0x00000000, 0x00000001, 0x00000002, +0x00050041, 0x00000007, 0x0000046A, 0x000003DA, 0x000003E6, 0x0004003D, 0x00000006, 0x0000046B, +0x0000046A, 0x0005008E, 0x0000000C, 0x0000046C, 0x00000469, 0x0000046B, 0x0003003E, 0x00000466, +0x0000046C, 0x0004003D, 0x0000000C, 0x0000046E, 0x00000462, 0x00050041, 0x0000000D, 0x0000046F, +0x000000C9, 0x000002D1, 0x0004003D, 0x0000000C, 0x00000470, 0x0000046F, 0x00050081, 0x0000000C, +0x00000471, 0x0000046E, 0x00000470, 0x0006000C, 0x0000000C, 0x00000472, 0x00000001, 0x00000045, +0x00000471, 0x0003003E, 0x0000046D, 0x00000472, 0x00050041, 0x0000000D, 0x00000474, 0x000000C9, +0x00000208, 0x0004003D, 0x0000000C, 0x00000475, 0x00000474, 0x0004003D, 0x0000000C, 0x00000476, +0x00000462, 0x00050094, 0x00000006, 0x00000477, 0x00000475, 0x00000476, 0x0003003E, 0x00000478, +0x00000477, 0x00050039, 0x00000006, 0x00000479, 0x00000019, 0x00000478, 0x0003003E, 0x00000473, +0x00000479, 0x00050041, 0x0000000D, 0x0000047B, 0x000000C9, 0x000002D1, 0x0004003D, 0x0000000C, +0x0000047C, 0x0000047B, 0x0004003D, 0x0000000C, 0x0000047D, 0x00000462, 0x00050081, 0x0000000C, +0x0000047E, 0x0000047C, 0x0000047D, 0x0006000C, 0x0000000C, 0x0000047F, 0x00000001, 0x00000045, +0x0000047E, 0x0003003E, 0x0000047A, 0x0000047F, 0x00050041, 0x0000000D, 0x00000481, 0x000000C9, +0x00000208, 0x0004003D, 0x0000000C, 0x00000482, 0x00000481, 0x00050041, 0x0000000D, 0x00000483, +0x000000C9, 0x000002D1, 0x0004003D, 0x0000000C, 0x00000484, 0x00000483, 0x00050094, 0x00000006, +0x00000485, 0x00000482, 0x00000484, 0x0003003E, 0x00000486, 0x00000485, 0x00050039, 0x00000006, +0x00000487, 0x00000046, 0x00000486, 0x0003003E, 0x00000480, 0x00000487, 0x0004003D, 0x00000006, +0x00000489, 0x00000480, 0x0003003E, 0x00000488, 0x00000489, 0x0004003D, 0x00000006, 0x0000048C, +0x00000473, 0x0003003E, 0x0000048B, 0x0000048C, 0x00050039, 0x00000006, 0x0000048D, 0x00000019, +0x0000048B, 0x0003003E, 0x0000048A, 0x0000048D, 0x00050041, 0x0000000D, 0x0000048F, 0x000000C9, +0x00000208, 0x0004003D, 0x0000000C, 0x00000490, 0x0000048F, 0x0004003D, 0x0000000C, 0x00000491, +0x0000047A, 0x00050094, 0x00000006, 0x00000492, 0x00000490, 0x00000491, 0x0003003E, 0x00000493, +0x00000492, 0x00050039, 0x00000006, 0x00000494, 0x00000019, 0x00000493, 0x0003003E, 0x0000048E, +0x00000494, 0x0004003D, 0x0000000C, 0x00000496, 0x00000462, 0x0004003D, 0x0000000C, 0x00000497, +0x0000047A, 0x00050094, 0x00000006, 0x00000498, 0x00000496, 0x00000497, 0x0003003E, 0x00000499, +0x00000498, 0x00050039, 0x00000006, 0x0000049A, 0x00000019, 0x00000499, 0x0003003E, 0x00000495, +0x0000049A, 0x0004003D, 0x000000A9, 0x0000049C, 0x000000C9, 0x0004003D, 0x00000006, 0x0000049E, +0x00000488, 0x0003003E, 0x0000049D, 0x0000049E, 0x0004003D, 0x00000006, 0x000004A0, 0x0000048A, +0x0003003E, 0x0000049F, 0x000004A0, 0x0004003D, 0x00000006, 0x000004A2, 0x00000495, 0x0003003E, +0x000004A1, 0x000004A2, 0x00080039, 0x0000000C, 0x000004A3, 0x000000BA, 0x0000049C, 0x0000049D, +0x0000049F, 0x000004A1, 0x0003003E, 0x0000049B, 0x000004A3, 0x0004003D, 0x000000A9, 0x000004A5, +0x000000C9, 0x0004003D, 0x000000AA, 0x000004A6, 0x000003DA, 0x0004003D, 0x0000000C, 0x000004A7, +0x0000047A, 0x0004003D, 0x00000006, 0x000004A9, 0x00000488, 0x0003003E, 0x000004A8, 0x000004A9, +0x0004003D, 0x00000006, 0x000004AB, 0x0000048A, 0x0003003E, 0x000004AA, 0x000004AB, 0x0004003D, +0x00000006, 0x000004AD, 0x0000048E, 0x0003003E, 0x000004AC, 0x000004AD, 0x0004003D, 0x00000006, +0x000004AF, 0x00000495, 0x0003003E, 0x000004AE, 0x000004AF, 0x000B0039, 0x0000000C, 0x000004B0, +0x000000C3, 0x000004A5, 0x000004A6, 0x000004A7, 0x000004A8, 0x000004AA, 0x000004AC, 0x000004AE, +0x0003003E, 0x000004A4, 0x000004B0, 0x0004003D, 0x0000000C, 0x000004B2, 0x0000049B, 0x0004003D, +0x0000000C, 0x000004B3, 0x000004A4, 0x00050081, 0x0000000C, 0x000004B4, 0x000004B2, 0x000004B3, +0x0003003E, 0x000004B1, 0x000004B4, 0x0004003D, 0x0000000C, 0x000004B5, 0x000004B1, 0x0004003D, +0x0000000C, 0x000004B6, 0x00000466, 0x00050085, 0x0000000C, 0x000004B7, 0x000004B5, 0x000004B6, +0x0004003D, 0x00000006, 0x000004B8, 0x000003EE, 0x0004003D, 0x00000006, 0x000004B9, 0x0000048A, +0x00050085, 0x00000006, 0x000004BA, 0x000004B8, 0x000004B9, 0x0004003D, 0x00000006, 0x000004BC, +0x0000048A, 0x0003003E, 0x000004BB, 0x000004BC, 0x00050041, 0x00000007, 0x000004BE, 0x000000C9, +0x00000226, 0x0004003D, 0x00000006, 0x000004BF, 0x000004BE, 0x0003003E, 0x000004BD, 0x000004BF, +0x00060039, 0x00000006, 0x000004C0, 0x0000003D, 0x000004BB, 0x000004BD, 0x00050085, 0x00000006, +0x000004C1, 0x000004BA, 0x000004C0, 0x0005008E, 0x0000000C, 0x000004C2, 0x000004B7, 0x000004C1, +0x0004003D, 0x0000000C, 0x000004C3, 0x000003CC, 0x00050081, 0x0000000C, 0x000004C4, 0x000004C3, +0x000004C2, 0x0003003E, 0x000003CC, 0x000004C4, 0x000200F9, 0x000003D2, 0x000200F8, 0x000003D2, +0x0004003D, 0x00000083, 0x000004C5, 0x000003CE, 0x00050080, 0x00000083, 0x000004C6, 0x000004C5, +0x000001FD, 0x0003003E, 0x000003CE, 0x000004C6, 0x000200F9, 0x000003CF, 0x000200F8, 0x000003D1, +0x0004003D, 0x0000000C, 0x000004C7, 0x000003CC, 0x000200FE, 0x000004C7, 0x00010038, 0x00050036, +0x0000000C, 0x000000CF, 0x00000000, 0x000000C6, 0x00030037, 0x0000000D, 0x000000CC, 0x00030037, +0x0000000D, 0x000000CD, 0x00030037, 0x000000C5, 0x000000CE, 0x000200F8, 0x000000D0, 0x0004003B, +0x0000000D, 0x000004CA, 0x00000007, 0x0004003B, 0x0000000D, 0x000004D4, 0x00000007, 0x0004003B, +0x0000000D, 0x000004D5, 0x00000007, 0x0004003B, 0x00000007, 0x000004D7, 0x00000007, 0x0004003B, +0x00000007, 0x000004DA, 0x00000007, 0x0004003B, 0x0000000D, 0x000004DE, 0x00000007, 0x0004003B, +0x0000000D, 0x000004E6, 0x00000007, 0x0004003B, 0x00000084, 0x000004EC, 0x00000007, 0x0004003B, +0x0000000D, 0x000004F0, 0x00000007, 0x0004003B, 0x0000000D, 0x000004FB, 0x00000007, 0x0004003D, +0x000004CC, 0x000004CF, 0x000004CE, 0x00050041, 0x0000000D, 0x000004D0, 0x000000CE, 0x00000208, +0x0004003D, 0x0000000C, 0x000004D1, 0x000004D0, 0x00050057, 0x00000012, 0x000004D2, 0x000004CF, +0x000004D1, 0x0008004F, 0x0000000C, 0x000004D3, 0x000004D2, 0x000004D2, 0x00000000, 0x00000001, +0x00000002, 0x0003003E, 0x000004CA, 0x000004D3, 0x0004003D, 0x0000000C, 0x000004D6, 0x000000CC, +0x0003003E, 0x000004D5, 0x000004D6, 0x00050041, 0x00000007, 0x000004D8, 0x000000CE, 0x00000258, +0x0004003D, 0x00000006, 0x000004D9, 0x000004D8, 0x0003003E, 0x000004D7, 0x000004D9, 0x00050041, +0x00000007, 0x000004DB, 0x000000CE, 0x0000020E, 0x0004003D, 0x00000006, 0x000004DC, 0x000004DB, +0x0003003E, 0x000004DA, 0x000004DC, 0x00070039, 0x0000000C, 0x000004DD, 0x0000006D, 0x000004D5, +0x000004D7, 0x000004DA, 0x0003003E, 0x000004D4, 0x000004DD, 0x0004003D, 0x0000000C, 0x000004DF, +0x000004D4, 0x00060050, 0x0000000C, 0x000004E0, 0x000000D3, 0x000000D3, 0x000000D3, 0x00050083, +0x0000000C, 0x000004E1, 0x000004E0, 0x000004DF, 0x00050041, 0x00000007, 0x000004E2, 0x000000CE, +0x000001FD, 0x0004003D, 0x00000006, 0x000004E3, 0x000004E2, 0x00050083, 0x00000006, 0x000004E4, +0x000000D3, 0x000004E3, 0x0005008E, 0x0000000C, 0x000004E5, 0x000004E1, 0x000004E4, 0x0003003E, +0x000004DE, 0x000004E5, 0x00050041, 0x00000013, 0x000004E7, 0x000000CE, 0x000001E7, 0x0004003D, +0x00000012, 0x000004E8, 0x000004E7, 0x0008004F, 0x0000000C, 0x000004E9, 0x000004E8, 0x000004E8, +0x00000000, 0x00000001, 0x00000002, 0x0004003D, 0x0000000C, 0x000004EA, 0x000004CA, 0x00050085, +0x0000000C, 0x000004EB, 0x000004E9, 0x000004EA, 0x0003003E, 0x000004E6, 0x000004EB, 0x00050041, +0x0000030D, 0x000004EE, 0x000002AC, 0x000004ED, 0x0004003D, 0x00000083, 0x000004EF, 0x000004EE, +0x0003003E, 0x000004EC, 0x000004EF, 0x0004003D, 0x000004CC, 0x000004F2, 0x000004F1, 0x0004003D, +0x0000000C, 0x000004F3, 0x000000CD, 0x00050041, 0x00000007, 0x000004F4, 0x000000CE, 0x000003E6, +0x0004003D, 0x00000006, 0x000004F5, 0x000004F4, 0x0004003D, 0x00000083, 0x000004F6, 0x000004EC, +0x0004006F, 0x00000006, 0x000004F7, 0x000004F6, 0x00050085, 0x00000006, 0x000004F8, 0x000004F5, +0x000004F7, 0x00070058, 0x00000012, 0x000004F9, 0x000004F2, 0x000004F3, 0x00000002, 0x000004F8, +0x0008004F, 0x0000000C, 0x000004FA, 0x000004F9, 0x000004F9, 0x00000000, 0x00000001, 0x00000002, +0x0003003E, 0x000004F0, 0x000004FA, 0x0004003D, 0x0000000C, 0x000004FC, 0x000004F0, 0x0004003D, +0x0000000C, 0x000004FD, 0x000004D4, 0x00060041, 0x00000007, 0x000004FE, 0x000000CE, 0x0000030C, +0x0000023C, 0x0004003D, 0x00000006, 0x000004FF, 0x000004FE, 0x0005008E, 0x0000000C, 0x00000500, +0x000004FD, 0x000004FF, 0x00060041, 0x00000007, 0x00000502, 0x000000CE, 0x0000030C, 0x00000501, +0x0004003D, 0x00000006, 0x00000503, 0x00000502, 0x00060050, 0x0000000C, 0x00000504, 0x00000503, +0x00000503, 0x00000503, 0x00050081, 0x0000000C, 0x00000505, 0x00000500, 0x00000504, 0x00050085, +0x0000000C, 0x00000506, 0x000004FC, 0x00000505, 0x0003003E, 0x000004FB, 0x00000506, 0x0004003D, +0x0000000C, 0x00000507, 0x000004DE, 0x0004003D, 0x0000000C, 0x00000508, 0x000004E6, 0x00050085, +0x0000000C, 0x00000509, 0x00000507, 0x00000508, 0x0004003D, 0x0000000C, 0x0000050A, 0x000004FB, +0x00050081, 0x0000000C, 0x0000050B, 0x00000509, 0x0000050A, 0x000200FE, 0x0000050B, 0x00010038, + }; \ No newline at end of file diff --git a/Lumos/Assets/Shaders/ForwardPBR.frag b/Lumos/Assets/Shaders/ForwardPBR.frag index f88a7f98e..757a44886 100644 --- a/Lumos/Assets/Shaders/ForwardPBR.frag +++ b/Lumos/Assets/Shaders/ForwardPBR.frag @@ -556,6 +556,8 @@ void main() material.Roughness = sqrt(filteredRoughness2); } + material.Roughness = clamp(material.Roughness, MIN_ROUGHNESS, 1.0); + vec3 wsPos = VertexOutput.Position.xyz; material.View = normalize(ubo.cameraPosition.xyz - wsPos); material.NDotV = max(dot(material.Normal, material.View), 1e-4); diff --git a/Lumos/Assets/Shaders/PBR.glslh b/Lumos/Assets/Shaders/PBR.glslh index e40726e68..f6ab3d57e 100644 --- a/Lumos/Assets/Shaders/PBR.glslh +++ b/Lumos/Assets/Shaders/PBR.glslh @@ -163,7 +163,7 @@ float distribution(float roughness, float NoH, const vec3 h, const vec3 normal) float visibility(float roughness, float NoV, float NoL) { #if QUALITY_LOW - return V_SmithGGXCorrelated_Fast(roughness, NoV, NoL); + return V_SmithGGXCorrelatedFast(roughness, NoV, NoL); #else return V_SmithGGXCorrelated(roughness, NoV, NoL); #endif @@ -171,7 +171,7 @@ float visibility(float roughness, float NoV, float NoL) { vec3 fresnel(const vec3 f0, float LoH) { #if QUALITY_LOW - return F_Schlick(f0, LoH); // f90 = 1.0 + return F_Schlick(LoH, f0); // f90 = 1.0 #else float f90 = saturate(dot(f0, vec3(50.0 * 0.33))); return F_Schlick(f0, f90, LoH); diff --git a/Lumos/External/spdlog/.clang-format b/Lumos/External/spdlog/.clang-format new file mode 100644 index 000000000..222faea47 --- /dev/null +++ b/Lumos/External/spdlog/.clang-format @@ -0,0 +1,109 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 140 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +IndentPPDirectives: AfterHash +... + diff --git a/Lumos/External/spdlog/.clang-tidy b/Lumos/External/spdlog/.clang-tidy new file mode 100644 index 000000000..34239d6b1 --- /dev/null +++ b/Lumos/External/spdlog/.clang-tidy @@ -0,0 +1,54 @@ +Checks: 'cppcoreguidelines-*, +performance-*, +modernize-*, +google-*, +misc-* +cert-*, +readability-*, +clang-analyzer-*, +-performance-unnecessary-value-param, +-modernize-use-trailing-return-type, +-google-runtime-references, +-misc-non-private-member-variables-in-classes, +-readability-braces-around-statements, +-google-readability-braces-around-statements, +-cppcoreguidelines-avoid-magic-numbers, +-readability-magic-numbers, +-readability-magic-numbers, +-cppcoreguidelines-pro-type-vararg, +-cppcoreguidelines-pro-bounds-pointer-arithmetic, +-cppcoreguidelines-avoid-c-arrays, +-modernize-avoid-c-arrays, +-cppcoreguidelines-pro-bounds-array-to-pointer-decay, +-readability-named-parameter, +-cert-env33-c +' + + +WarningsAsErrors: '' +HeaderFilterRegex: '*spdlog/[^f].*' +AnalyzeTemporaryDtors: false +FormatStyle: none + +CheckOptions: + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + diff --git a/Lumos/External/spdlog/CMakeLists.txt b/Lumos/External/spdlog/CMakeLists.txt new file mode 100644 index 000000000..6556144b5 --- /dev/null +++ b/Lumos/External/spdlog/CMakeLists.txt @@ -0,0 +1,360 @@ +# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT) + +cmake_minimum_required(VERSION 3.10...3.21) + +# --------------------------------------------------------------------------------------- +# Start spdlog project +# --------------------------------------------------------------------------------------- +include(cmake/utils.cmake) +include(cmake/ide.cmake) + +spdlog_extract_version() + +project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX) +message(STATUS "Build spdlog: ${SPDLOG_VERSION}") + +include(GNUInstallDirs) + +# --------------------------------------------------------------------------------------- +# Set default build to release +# --------------------------------------------------------------------------------------- +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) +endif() + +# --------------------------------------------------------------------------------------- +# Compiler config +# --------------------------------------------------------------------------------------- +if(SPDLOG_USE_STD_FORMAT) + set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +elseif(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + +# make sure __cplusplus is defined when using msvc and enable parallel build +if(MSVC) + string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus /MP") +endif() + +set(CMAKE_CXX_EXTENSIONS OFF) + +if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS") + set(CMAKE_CXX_EXTENSIONS ON) +endif() + +# --------------------------------------------------------------------------------------- +# Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog +# --------------------------------------------------------------------------------------- +# Check if spdlog is being used directly or via add_subdirectory, but allow overriding +if(NOT DEFINED SPDLOG_MASTER_PROJECT) + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(SPDLOG_MASTER_PROJECT ON) + else() + set(SPDLOG_MASTER_PROJECT OFF) + endif() +endif() + +option(SPDLOG_BUILD_ALL "Build all artifacts" OFF) + +# build shared option +option(SPDLOG_BUILD_SHARED "Build shared library" OFF) + +# precompiled headers option +option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled header to speed up compilation time" OFF) + +# build position independent code +option(SPDLOG_BUILD_PIC "Build position independent code (-fPIC)" OFF) + +# example options +option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT}) +option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF) + +# testing options +option(SPDLOG_BUILD_TESTS "Build tests" OFF) +option(SPDLOG_BUILD_TESTS_HO "Build tests using the header only version" OFF) + +# bench options +option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" OFF) + +# sanitizer options +option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) + +# warning options +option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF) + +# install options +option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." OFF) +option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) +option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." OFF) +option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) +option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF) +option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF) + +if(SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO) + message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive") +endif() + +if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL_HO) + message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive") +endif() + +if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL) + message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL are mutually exclusive") +endif() + +# misc tweakme options +if(WIN32) + option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF) + option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF) +else() + set(SPDLOG_WCHAR_SUPPORT OFF CACHE BOOL "non supported option" FORCE) + set(SPDLOG_WCHAR_FILENAMES OFF CACHE BOOL "non supported option" FORCE) +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + option(SPDLOG_CLOCK_COARSE "Use CLOCK_REALTIME_COARSE instead of the regular clock," OFF) +else() + set(SPDLOG_CLOCK_COARSE OFF CACHE BOOL "non supported option" FORCE) +endif() + +option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF) +option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF) +option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF) +option( + SPDLOG_NO_ATOMIC_LEVELS + "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" + OFF) +option(SPDLOG_DISABLE_DEFAULT_LOGGER "Disable default logger creation" OFF) + +# clang-tidy +if(${CMAKE_VERSION} VERSION_GREATER "3.5") + option(SPDLOG_TIDY "run clang-tidy" OFF) +endif() + +if(SPDLOG_TIDY) + set(CMAKE_CXX_CLANG_TIDY "clang-tidy") + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + message(STATUS "Enabled clang-tidy") +endif() + +if(SPDLOG_BUILD_PIC) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif() + +find_package(Threads REQUIRED) +message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) +# --------------------------------------------------------------------------------------- +# Static/Shared library +# --------------------------------------------------------------------------------------- +set(SPDLOG_SRCS src/spdlog.cpp src/stdout_sinks.cpp src/color_sinks.cpp src/file_sinks.cpp src/async.cpp src/cfg.cpp) + +if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) + list(APPEND SPDLOG_SRCS src/bundled_fmtlib_format.cpp) +endif() + +if(SPDLOG_BUILD_SHARED OR BUILD_SHARED_LIBS) + if(WIN32) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) + list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc) + endif() + add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) + target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB) + if(MSVC) + target_compile_options(spdlog PUBLIC $<$,$>>:/wd4251 + /wd4275>) + endif() + if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) + target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED) + endif() +else() + add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) +endif() + +add_library(spdlog::spdlog ALIAS spdlog) + +set(SPDLOG_INCLUDES_LEVEL "") +if(SPDLOG_SYSTEM_INCLUDES) + set(SPDLOG_INCLUDES_LEVEL "SYSTEM") +endif() + +target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) +target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$" + "$") +target_link_libraries(spdlog PUBLIC Threads::Threads) +spdlog_enable_warnings(spdlog) + +set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION + ${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR}) +set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d) + +if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pch.h.in ${PROJECT_BINARY_DIR}/spdlog_pch.h @ONLY) + target_precompile_headers(spdlog PRIVATE ${PROJECT_BINARY_DIR}/spdlog_pch.h) +endif() + +# --------------------------------------------------------------------------------------- +# Header only version +# --------------------------------------------------------------------------------------- +add_library(spdlog_header_only INTERFACE) +add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only) + +target_include_directories( + spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$" + "$") +target_link_libraries(spdlog_header_only INTERFACE Threads::Threads) + +# --------------------------------------------------------------------------------------- +# Use fmt package if using external fmt +# --------------------------------------------------------------------------------------- +if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO) + if(NOT TARGET fmt::fmt) + find_package(fmt CONFIG REQUIRED) + endif() + target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL) + target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL) + + # use external fmt-header-nly + if(SPDLOG_FMT_EXTERNAL_HO) + target_link_libraries(spdlog PUBLIC fmt::fmt-header-only) + target_link_libraries(spdlog_header_only INTERFACE fmt::fmt-header-only) + else() # use external compile fmt + target_link_libraries(spdlog PUBLIC fmt::fmt) + target_link_libraries(spdlog_header_only INTERFACE fmt::fmt) + endif() + + set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config +endif() + +# --------------------------------------------------------------------------------------- +# Add required libraries for Android CMake build +# --------------------------------------------------------------------------------------- +if(ANDROID) + target_link_libraries(spdlog PUBLIC log) + target_link_libraries(spdlog_header_only INTERFACE log) +endif() + +# --------------------------------------------------------------------------------------- +# Misc definitions according to tweak options +# --------------------------------------------------------------------------------------- +set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT}) +foreach( + SPDLOG_OPTION + SPDLOG_WCHAR_TO_UTF8_SUPPORT + SPDLOG_WCHAR_FILENAMES + SPDLOG_NO_EXCEPTIONS + SPDLOG_CLOCK_COARSE + SPDLOG_PREVENT_CHILD_FD + SPDLOG_NO_THREAD_ID + SPDLOG_NO_TLS + SPDLOG_NO_ATOMIC_LEVELS + SPDLOG_DISABLE_DEFAULT_LOGGER + SPDLOG_USE_STD_FORMAT) + if(${SPDLOG_OPTION}) + target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION}) + target_compile_definitions(spdlog_header_only INTERFACE ${SPDLOG_OPTION}) + endif() +endforeach() + +# --------------------------------------------------------------------------------------- +# If exceptions are disabled, disable them in the bundled fmt as well +# --------------------------------------------------------------------------------------- +if(SPDLOG_NO_EXCEPTIONS) + if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) + target_compile_definitions(spdlog PUBLIC FMT_EXCEPTIONS=0) + endif() + if(NOT MSVC) + target_compile_options(spdlog PRIVATE -fno-exceptions) + else() + target_compile_options(spdlog PRIVATE /EHsc) + endif() +endif() +# --------------------------------------------------------------------------------------- +# Build binaries +# --------------------------------------------------------------------------------------- +if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO OR SPDLOG_BUILD_ALL) + message(STATUS "Generating example(s)") + add_subdirectory(example) + spdlog_enable_warnings(example) + if(SPDLOG_BUILD_EXAMPLE_HO) + spdlog_enable_warnings(example_header_only) + endif() +endif() + +if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO OR SPDLOG_BUILD_ALL) + message(STATUS "Generating tests") + enable_testing() + add_subdirectory(tests) +endif() + +if(SPDLOG_BUILD_BENCH OR SPDLOG_BUILD_ALL) + message(STATUS "Generating benchmarks") + add_subdirectory(bench) +endif() + +# --------------------------------------------------------------------------------------- +# Install +# --------------------------------------------------------------------------------------- +if(SPDLOG_INSTALL) + message(STATUS "Generating install") + set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in") + set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake") + set(config_targets_file "spdlogConfigTargets.cmake") + set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake") + set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/spdlog") + set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") + + # --------------------------------------------------------------------------------------- + # Include files + # --------------------------------------------------------------------------------------- + install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) + install( + TARGETS spdlog spdlog_header_only + EXPORT spdlog + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + + if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) + install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/ + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/") + endif() + + # --------------------------------------------------------------------------------------- + # Install pkg-config file + # --------------------------------------------------------------------------------------- + if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(PKG_CONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") + else() + set(PKG_CONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") + endif() + if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + set(PKG_CONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}") + else() + set(PKG_CONFIG_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") + endif() + get_target_property(PKG_CONFIG_DEFINES spdlog INTERFACE_COMPILE_DEFINITIONS) + string(REPLACE ";" " -D" PKG_CONFIG_DEFINES "${PKG_CONFIG_DEFINES}") + string(CONCAT PKG_CONFIG_DEFINES "-D" "${PKG_CONFIG_DEFINES}") + configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY) + install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}") + + # --------------------------------------------------------------------------------------- + # Install CMake config files + # --------------------------------------------------------------------------------------- + export(TARGETS spdlog NAMESPACE spdlog:: FILE "${CMAKE_CURRENT_BINARY_DIR}/${config_targets_file}") + install(EXPORT spdlog DESTINATION ${export_dest_dir} NAMESPACE spdlog:: FILE ${config_targets_file}) + + include(CMakePackageConfigHelpers) + configure_package_config_file("${project_config_in}" "${project_config_out}" INSTALL_DESTINATION ${export_dest_dir}) + + write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) + install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}") + + # --------------------------------------------------------------------------------------- + # Support creation of installable packages + # --------------------------------------------------------------------------------------- + include(cmake/spdlogCPack.cmake) +endif() diff --git a/Lumos/External/spdlog/INSTALL b/Lumos/External/spdlog/INSTALL new file mode 100644 index 000000000..20a9b4c40 --- /dev/null +++ b/Lumos/External/spdlog/INSTALL @@ -0,0 +1,24 @@ +Header only version: +================================================================== +Just copy the files to your build tree and use a C++11 compiler. +Or use CMake: + add_executable(example_header_only example.cpp) + target_link_libraries(example_header_only spdlog::spdlog_header_only) + + +Compiled library version: +================================================================== +CMake: + add_executable(example example.cpp) + target_link_libraries(example spdlog::spdlog) + +Or copy files src/*.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler. + +Tested on: +gcc 4.8.1 and above +clang 3.5 +Visual Studio 2013 + + + + diff --git a/Lumos/External/spdlog/README.md b/Lumos/External/spdlog/README.md index a37938c59..6ce32fb60 100644 --- a/Lumos/External/spdlog/README.md +++ b/Lumos/External/spdlog/README.md @@ -1,59 +1,61 @@ # spdlog -Very fast, header-only/compiled, C++ logging library. [![Build Status](https://travis-ci.com/gabime/spdlog.svg?branch=v1.x)](https://travis-ci.com/gabime/spdlog)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true)](https://ci.appveyor.com/project/gabime/spdlog) [![Release](https://img.shields.io/github/release/gabime/spdlog.svg)](https://github.com/gabime/spdlog/releases/latest) +Very fast, header-only/compiled, C++ logging library. [![ci](https://github.com/gabime/spdlog/actions/workflows/ci.yml/badge.svg)](https://github.com/gabime/spdlog/actions/workflows/ci.yml)  [![Build status](https://ci.appveyor.com/api/projects/status/d2jnxclg20vd0o50?svg=true&branch=v1.x)](https://ci.appveyor.com/project/gabime/spdlog) [![Release](https://img.shields.io/github/release/gabime/spdlog.svg)](https://github.com/gabime/spdlog/releases/latest) -## Install -#### Header only version -Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. +## Install +#### Header-only version +Copy the include [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. -#### Static lib version (recommended - much faster compile times) +#### Compiled version (recommended - much faster compile times) ```console $ git clone https://github.com/gabime/spdlog.git $ cd spdlog && mkdir build && cd build $ cmake .. && make -j ``` - - see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use. + +see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use. ## Platforms - * Linux, FreeBSD, OpenBSD, Solaris, AIX - * Windows (msvc 2013+, cygwin) - * macOS (clang 3.5+) - * Android +* Linux, FreeBSD, OpenBSD, Solaris, AIX +* Windows (msvc 2013+, cygwin) +* macOS (clang 3.5+) +* Android ## Package managers: +* Debian: `sudo apt install libspdlog-dev` * Homebrew: `brew install spdlog` * MacPorts: `sudo port install spdlog` -* FreeBSD: `cd /usr/ports/devel/spdlog/ && make install clean` +* FreeBSD: `pkg install spdlog` * Fedora: `dnf install spdlog` * Gentoo: `emerge dev-libs/spdlog` * Arch Linux: `pacman -S spdlog` +* openSUSE: `sudo zypper in spdlog-devel` * vcpkg: `vcpkg install spdlog` * conan: `spdlog/[>=1.4.1]` * conda: `conda install -c conda-forge spdlog` * build2: ```depends: spdlog ^1.8.2``` - ## Features * Very fast (see [benchmarks](#benchmarks) below). * Headers only or compiled -* Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. +* Feature-rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. * Asynchronous mode (optional) * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: - * Rotating log files. - * Daily log files. - * Console logging (colors supported). - * syslog. - * Windows event log. - * Windows debugger (```OutputDebugString(..)```). - * Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. -* Log filtering - log levels can be modified in runtime as well as in compile time. -* Support for loading log levels from argv or from environment var. -* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand. - + * Rotating log files. + * Daily log files. + * Console logging (colors supported). + * syslog. + * Windows event log. + * Windows debugger (```OutputDebugString(..)```). + * Log to Qt widgets ([example](#log-to-qt-with-nice-colors)). + * Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. +* Log filtering - log levels can be modified at runtime as well as compile time. +* Support for loading log levels from argv or environment var. +* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand. + ## Usage samples #### Basic usage @@ -91,7 +93,7 @@ int main() #include "spdlog/sinks/stdout_color_sinks.h" void stdout_example() { - // create color multi threaded logger + // create a color multi-threaded logger auto console = spdlog::stdout_color_mt("console"); auto err_logger = spdlog::stderr_color_mt("stderr"); spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)"); @@ -120,7 +122,7 @@ void basic_logfile_example() #include "spdlog/sinks/rotating_file_sink.h" void rotating_example() { - // Create a file rotating logger with 5mb size max and 3 rotated files + // Create a file rotating logger with 5 MB size max and 3 rotated files auto max_size = 1048576 * 5; auto max_files = 3; auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files); @@ -134,7 +136,7 @@ void rotating_example() #include "spdlog/sinks/daily_file_sink.h" void daily_example() { - // Create a daily logger - a new file is created every day on 2:30am + // Create a daily logger - a new file is created every day at 2:30 am auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); } @@ -144,10 +146,10 @@ void daily_example() #### Backtrace support ```c++ // Debug messages can be stored in a ring buffer instead of being logged immediately. -// This is useful in order to display debug logs only when really nededed (e.g. when error happens). -// When needed, call dump_backtrace() to see them. +// This is useful to display debug logs only when needed (e.g. when an error happens). +// When needed, call dump_backtrace() to dump them to your log. -spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. Older messages will be dropped. +spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. // or my_logger->enable_backtrace(32).. for(int i = 0; i < 100; i++) { @@ -155,7 +157,6 @@ for(int i = 0; i < 100; i++) } // e.g. if some error happened: spdlog::dump_backtrace(); // log them now! show the last 32 messages - // or my_logger->dump_backtrace(32).. ``` @@ -163,7 +164,7 @@ spdlog::dump_backtrace(); // log them now! show the last 32 messages #### Periodic flush ```c++ // periodically flush all *registered* loggers every 3 seconds: -// warning: only use if all your loggers are thread safe ("_mt" loggers) +// warning: only use if all your loggers are thread-safe ("_mt" loggers) spdlog::flush_every(std::chrono::seconds(3)); ``` @@ -191,7 +192,7 @@ void stopwatch_example() // {: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. +// {:n} - don't split the output into lines. // {:a} - show ASCII if :n is not set. #include "spdlog/fmt/bin_to_hex.h" @@ -211,11 +212,11 @@ void binary_example() ``` --- -#### Logger with multi sinks - each with different format and log level +#### Logger with multi sinks - each with a different format and log level ```c++ -// create logger with 2 targets with different log levels and formats. -// the console will show only warnings or errors, while the file will log all. +// create a logger with 2 targets, with different log levels and formats. +// The console will show only warnings or errors, while the file will log all. void multi_sink_example() { auto console_sink = std::make_shared(); @@ -232,6 +233,27 @@ void multi_sink_example() } ``` +--- +#### User-defined callbacks about log events +```c++ + +// create a logger with a lambda function callback, the callback will be called +// each time something is logged to the logger +void callback_example() +{ + auto callback_sink = std::make_shared([](const spdlog::details::log_msg &msg) { + // for example you can be notified by sending an email to yourself + }); + callback_sink->set_level(spdlog::level::err); + + auto console_sink = std::make_shared(); + spdlog::logger logger("custom_callback_logger", {console_sink, callback_sink}); + + logger.info("some info log"); + logger.error("critical issue"); // will notify you +} +``` + --- #### Asynchronous logging ```c++ @@ -249,7 +271,7 @@ void async_example() ``` --- -#### Asynchronous logger with multi sinks +#### Asynchronous logger with multi sinks ```c++ #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/rotating_file_sink.h" @@ -266,29 +288,26 @@ void multi_sink_example2() ``` --- -#### User defined types +#### User-defined types ```c++ -// user defined types logging by implementing operator<< -#include "spdlog/fmt/ostr.h" // must be included -struct my_type +template<> +struct fmt::formatter : fmt::formatter { - int i; - template - friend OStream &operator<<(OStream &os, const my_type &c) + auto format(my_type my, format_context &ctx) const -> decltype(ctx.out()) { - return os << "[my_type i=" << c.i << "]"; + return format_to(ctx.out(), "[my_type i={}]", my.i); } }; void user_defined_example() { - spdlog::get("console")->info("user defined type: {}", my_type{14}); + spdlog::info("user defined type: {}", my_type(14)); } ``` --- -#### User defined flags in the log pattern +#### User-defined flags in the log pattern ```c++ // Log patterns can contain custom flags. // the following example will add new flag '%*' - which will be bound to a instance. @@ -330,7 +349,7 @@ void err_handler_example() ``` --- -#### syslog +#### syslog ```c++ #include "spdlog/sinks/syslog_sink.h" void syslog_example() @@ -341,7 +360,7 @@ void syslog_example() } ``` --- -#### Android example +#### Android example ```c++ #include "spdlog/sinks/android_sink.h" void android_example() @@ -353,14 +372,14 @@ void android_example() ``` --- -#### Load log levels from env variable or from argv +#### Load log levels from the env variable or argv ```c++ #include "spdlog/cfg/env.h" int main (int argc, char *argv[]) { spdlog::cfg::load_env_levels(); - // or from command line: + // or from the command line: // ./example SPDLOG_LEVEL=info,mylogger=trace // #include "spdlog/cfg/argv.h" // for loading levels from argv // spdlog::cfg::load_argv_levels(argc, argv); @@ -373,6 +392,51 @@ $ export SPDLOG_LEVEL=info,mylogger=trace $ ./example ``` + +--- +#### Log file open/close event handlers +```c++ +// You can get callbacks from spdlog before/after a log file has been opened or closed. +// This is useful for cleanup procedures or for adding something to the start/end of the log file. +void file_events_example() +{ + // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications + spdlog::file_event_handlers handlers; + handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); }; + handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("After opening\n", fstream); }; + handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("Before closing\n", fstream); }; + handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); }; + auto my_logger = spdlog::basic_logger_st("some_logger", "logs/events-sample.txt", true, handlers); +} +``` + +--- +#### Replace the Default Logger +```c++ +void replace_default_logger_example() +{ + auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true); + spdlog::set_default_logger(new_logger); + spdlog::info("new logger log message"); +} +``` + +--- +#### Log to Qt with nice colors +```c++ +#include "spdlog/spdlog.h" +#include "spdlog/sinks/qt_sinks.h" +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) +{ + setMinimumSize(640, 480); + auto log_widget = new QTextEdit(this); + setCentralWidget(log_widget); + int max_lines = 500; // keep the text widget to max 500 lines. remove old lines if needed. + auto logger = spdlog::qt_color_logger_mt("qt_logger", log_widget, max_lines); + logger->info("Some info message"); +} +``` + --- ## Benchmarks diff --git a/Lumos/External/spdlog/appveyor.yml b/Lumos/External/spdlog/appveyor.yml new file mode 100644 index 000000000..f2757f30c --- /dev/null +++ b/Lumos/External/spdlog/appveyor.yml @@ -0,0 +1,89 @@ +version: 1.0.{build} +image: Visual Studio 2017 +environment: + matrix: + - GENERATOR: '"Visual Studio 15 2017 Win64"' + BUILD_TYPE: Debug + BUILD_SHARED: 'OFF' + FATAL_ERRORS: 'OFF' + WCHAR: 'ON' + WCHAR_FILES: 'OFF' + BUILD_EXAMPLE: 'ON' + USE_STD_FORMAT: 'OFF' + CXX_STANDARD: 11 + - GENERATOR: '"Visual Studio 15 2017 Win64"' + BUILD_TYPE: Release + BUILD_SHARED: 'OFF' + FATAL_ERRORS: 'OFF' + WCHAR: 'OFF' + WCHAR_FILES: 'OFF' + BUILD_EXAMPLE: 'ON' + USE_STD_FORMAT: 'OFF' + CXX_STANDARD: 11 + - GENERATOR: '"Visual Studio 15 2017 Win64"' + BUILD_TYPE: Release + BUILD_SHARED: 'ON' + FATAL_ERRORS: 'OFF' + WCHAR: 'OFF' + WCHAR_FILES: 'OFF' + BUILD_EXAMPLE: 'ON' + USE_STD_FORMAT: 'OFF' + CXX_STANDARD: 11 + - GENERATOR: '"Visual Studio 15 2017 Win64"' + BUILD_TYPE: Release + BUILD_SHARED: 'ON' + FATAL_ERRORS: 'OFF' + WCHAR: 'ON' + WCHAR_FILES: 'ON' + BUILD_EXAMPLE: 'OFF' + USE_STD_FORMAT: 'OFF' + CXX_STANDARD: 11 + - GENERATOR: '"Visual Studio 16 2019" -A x64' + BUILD_TYPE: Release + BUILD_SHARED: 'ON' + FATAL_ERRORS: 'ON' + WCHAR: 'OFF' + WCHAR_FILES: 'OFF' + BUILD_EXAMPLE: 'OFF' + USE_STD_FORMAT: 'OFF' + CXX_STANDARD: 17 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - GENERATOR: '"Visual Studio 17 2022" -A x64' + BUILD_TYPE: Release + BUILD_SHARED: 'ON' + FATAL_ERRORS: 'ON' + WCHAR: 'OFF' + WCHAR_FILES: 'OFF' + BUILD_EXAMPLE: 'OFF' + USE_STD_FORMAT: 'ON' + CXX_STANDARD: 20 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + - GENERATOR: '"Visual Studio 17 2022" -A x64' + BUILD_TYPE: Release + BUILD_SHARED: 'ON' + FATAL_ERRORS: 'ON' + WCHAR: 'ON' + WCHAR_FILES: 'ON' + BUILD_EXAMPLE: 'OFF' + USE_STD_FORMAT: 'ON' + CXX_STANDARD: 20 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 +build_script: + - cmd: >- + set + + mkdir build + + cd build + + set PATH=%PATH%;C:\Program Files\Git\usr\bin + + cmake -G %GENERATOR% -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -D BUILD_SHARED_LIBS=%BUILD_SHARED% -D SPDLOG_WCHAR_SUPPORT=%WCHAR% -D SPDLOG_WCHAR_FILENAMES=%WCHAR_FILES% -D SPDLOG_BUILD_EXAMPLE=%BUILD_EXAMPLE% -D SPDLOG_BUILD_EXAMPLE_HO=%BUILD_EXAMPLE% -D SPDLOG_BUILD_TESTS=ON -D SPDLOG_BUILD_TESTS_HO=OFF -D SPDLOG_BUILD_WARNINGS=%FATAL_ERRORS% -D SPDLOG_USE_STD_FORMAT=%USE_STD_FORMAT% -D CMAKE_CXX_STANDARD=%CXX_STANDARD% .. + + cmake --build . --config %BUILD_TYPE% + +before_test: + - set PATH=%PATH%;C:\projects\spdlog\build\_deps\catch2-build\src\%BUILD_TYPE%;C:\projects\spdlog\build\%BUILD_TYPE% + +test_script: + - C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe diff --git a/Lumos/External/spdlog/bench/CMakeLists.txt b/Lumos/External/spdlog/bench/CMakeLists.txt new file mode 100644 index 000000000..8003886a6 --- /dev/null +++ b/Lumos/External/spdlog/bench/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT) + +cmake_minimum_required(VERSION 3.10) +project(spdlog_bench CXX) + +if(NOT TARGET spdlog) + # Stand-alone build + find_package(spdlog CONFIG REQUIRED) +endif() + +find_package(Threads REQUIRED) +find_package(benchmark CONFIG) +if(NOT benchmark_FOUND) + message(STATUS "Using CMake Version ${CMAKE_VERSION}") + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0") + # User can fetch googlebenchmark + message(STATUS "Downloading GoogleBenchmark") + include(FetchContent) + + # disable tests + set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "") + # Do not build and run googlebenchmark tests + FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0) + FetchContent_MakeAvailable(googlebenchmark) + else() + message(FATAL_ERROR "GoogleBenchmark is missing. Use CMake >= 3.11 or download it") + endif() +endif() + +add_executable(bench bench.cpp) +spdlog_enable_warnings(bench) +target_link_libraries(bench PRIVATE spdlog::spdlog) + +add_executable(async_bench async_bench.cpp) +target_link_libraries(async_bench PRIVATE spdlog::spdlog) + +add_executable(latency latency.cpp) +target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog) + +add_executable(formatter-bench formatter-bench.cpp) +target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog) diff --git a/Lumos/External/spdlog/bench/async_bench.cpp b/Lumos/External/spdlog/bench/async_bench.cpp new file mode 100644 index 000000000..cf4d9754d --- /dev/null +++ b/Lumos/External/spdlog/bench/async_bench.cpp @@ -0,0 +1,186 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +// +// bench.cpp : spdlog benchmarks +// +#include "spdlog/spdlog.h" +#include "spdlog/async.h" +#include "spdlog/sinks/basic_file_sink.h" + +#if defined(SPDLOG_USE_STD_FORMAT) +# include +#elif defined(SPDLOG_FMT_EXTERNAL) +# include +#else +# include "spdlog/fmt/bundled/format.h" +#endif + +#include "utils.h" +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; +using namespace spdlog; +using namespace spdlog::sinks; +using namespace utils; + +void bench_mt(int howmany, std::shared_ptr log, int thread_count); + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4996) // disable fopen warning under msvc +#endif // _MSC_VER + +int count_lines(const char *filename) +{ + int counter = 0; + auto *infile = fopen(filename, "r"); + int ch; + while (EOF != (ch = getc(infile))) + { + if ('\n' == ch) + counter++; + } + fclose(infile); + + return counter; +} + +void verify_file(const char *filename, int expected_count) +{ + spdlog::info("Verifying {} to contain {} line..", filename, expected_count); + auto count = count_lines(filename); + if (count != expected_count) + { + spdlog::error("Test failed. {} has {} lines instead of {}", filename, count, expected_count); + exit(1); + } + spdlog::info("Line count OK ({})\n", count); +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +int main(int argc, char *argv[]) +{ + + int howmany = 1000000; + int queue_size = std::min(howmany + 2, 8192); + int threads = 10; + int iters = 3; + + try + { + spdlog::set_pattern("[%^%l%$] %v"); + if (argc == 1) + { + spdlog::info("Usage: {} ", argv[0]); + return 0; + } + + if (argc > 1) + howmany = atoi(argv[1]); + if (argc > 2) + threads = atoi(argv[2]); + if (argc > 3) + { + queue_size = atoi(argv[3]); + if (queue_size > 500000) + { + spdlog::error("Max queue size allowed: 500,000"); + exit(1); + } + } + + if (argc > 4) + iters = atoi(argv[4]); + + auto slot_size = sizeof(spdlog::details::async_msg); + spdlog::info("-------------------------------------------------"); + spdlog::info("Messages : {:L}", howmany); + spdlog::info("Threads : {:L}", threads); + spdlog::info("Queue : {:L} slots", queue_size); + spdlog::info("Queue memory : {:L} x {:L} = {:L} KB ", queue_size, slot_size, (queue_size * slot_size) / 1024); + spdlog::info("Total iters : {:L}", iters); + spdlog::info("-------------------------------------------------"); + + const char *filename = "logs/basic_async.log"; + spdlog::info(""); + spdlog::info("*********************************"); + spdlog::info("Queue Overflow Policy: block"); + spdlog::info("*********************************"); + for (int i = 0; i < iters; i++) + { + auto tp = std::make_shared(queue_size, 1); + auto file_sink = std::make_shared(filename, true); + auto logger = std::make_shared("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block); + bench_mt(howmany, std::move(logger), threads); + // verify_file(filename, howmany); + } + + spdlog::info(""); + spdlog::info("*********************************"); + spdlog::info("Queue Overflow Policy: overrun"); + spdlog::info("*********************************"); + // do same test but discard oldest if queue is full instead of blocking + filename = "logs/basic_async-overrun.log"; + for (int i = 0; i < iters; i++) + { + auto tp = std::make_shared(queue_size, 1); + auto file_sink = std::make_shared(filename, true); + auto logger = + std::make_shared("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::overrun_oldest); + bench_mt(howmany, std::move(logger), threads); + } + spdlog::shutdown(); + } + catch (std::exception &ex) + { + std::cerr << "Error: " << ex.what() << std::endl; + perror("Last error"); + return 1; + } + return 0; +} + +void thread_fun(std::shared_ptr logger, int howmany) +{ + for (int i = 0; i < howmany; i++) + { + logger->info("Hello logger: msg number {}", i); + } +} + +void bench_mt(int howmany, std::shared_ptr logger, int thread_count) +{ + using std::chrono::high_resolution_clock; + vector threads; + auto start = high_resolution_clock::now(); + + int msgs_per_thread = howmany / thread_count; + int msgs_per_thread_mod = howmany % thread_count; + for (int t = 0; t < thread_count; ++t) + { + if (t == 0 && msgs_per_thread_mod) + threads.push_back(std::thread(thread_fun, logger, msgs_per_thread + msgs_per_thread_mod)); + else + threads.push_back(std::thread(thread_fun, logger, msgs_per_thread)); + } + + for (auto &t : threads) + { + t.join(); + }; + + auto delta = high_resolution_clock::now() - start; + auto delta_d = duration_cast>(delta).count(); + spdlog::info("Elapsed: {} secs\t {:L}/sec", delta_d, int(howmany / delta_d)); +} diff --git a/Lumos/External/spdlog/bench/bench.cpp b/Lumos/External/spdlog/bench/bench.cpp new file mode 100644 index 000000000..ae47f047c --- /dev/null +++ b/Lumos/External/spdlog/bench/bench.cpp @@ -0,0 +1,248 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +// +// bench.cpp : spdlog benchmarks +// +#include "spdlog/spdlog.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/daily_file_sink.h" +#include "spdlog/sinks/null_sink.h" +#include "spdlog/sinks/rotating_file_sink.h" + +#if defined(SPDLOG_USE_STD_FORMAT) +# include +#elif defined(SPDLOG_FMT_EXTERNAL) +# include +#else +# include "spdlog/fmt/bundled/format.h" +#endif + +#include "utils.h" +#include +#include // EXIT_FAILURE +#include +#include +#include + +void bench(int howmany, std::shared_ptr log); +void bench_mt(int howmany, std::shared_ptr log, size_t thread_count); + +// void bench_default_api(int howmany, std::shared_ptr log); +// void bench_c_string(int howmany, std::shared_ptr log); + +static const size_t file_size = 30 * 1024 * 1024; +static const size_t rotating_files = 5; +static const int max_threads = 1000; + +void bench_threaded_logging(size_t threads, int iters) +{ + spdlog::info("**************************************************************"); + spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} messages", threads, iters)); + spdlog::info("**************************************************************"); + + auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true); + bench_mt(iters, std::move(basic_mt), threads); + auto basic_mt_tracing = spdlog::basic_logger_mt("basic_mt/backtrace-on", "logs/basic_mt.log", true); + basic_mt_tracing->enable_backtrace(32); + bench_mt(iters, std::move(basic_mt_tracing), threads); + + spdlog::info(""); + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files); + bench_mt(iters, std::move(rotating_mt), threads); + auto rotating_mt_tracing = spdlog::rotating_logger_mt("rotating_mt/backtrace-on", "logs/rotating_mt.log", file_size, rotating_files); + rotating_mt_tracing->enable_backtrace(32); + bench_mt(iters, std::move(rotating_mt_tracing), threads); + + spdlog::info(""); + auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log"); + bench_mt(iters, std::move(daily_mt), threads); + auto daily_mt_tracing = spdlog::daily_logger_mt("daily_mt/backtrace-on", "logs/daily_mt.log"); + daily_mt_tracing->enable_backtrace(32); + bench_mt(iters, std::move(daily_mt_tracing), threads); + + spdlog::info(""); + auto empty_logger = std::make_shared("level-off"); + empty_logger->set_level(spdlog::level::off); + bench(iters, empty_logger); + auto empty_logger_tracing = std::make_shared("level-off/backtrace-on"); + empty_logger_tracing->set_level(spdlog::level::off); + empty_logger_tracing->enable_backtrace(32); + bench(iters, empty_logger_tracing); +} + +void bench_single_threaded(int iters) +{ + spdlog::info("**************************************************************"); + spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Single threaded: {} messages", iters)); + spdlog::info("**************************************************************"); + + auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); + bench(iters, std::move(basic_st)); + + auto basic_st_tracing = spdlog::basic_logger_st("basic_st/backtrace-on", "logs/basic_st.log", true); + bench(iters, std::move(basic_st_tracing)); + + spdlog::info(""); + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files); + bench(iters, std::move(rotating_st)); + auto rotating_st_tracing = spdlog::rotating_logger_st("rotating_st/backtrace-on", "logs/rotating_st.log", file_size, rotating_files); + rotating_st_tracing->enable_backtrace(32); + bench(iters, std::move(rotating_st_tracing)); + + spdlog::info(""); + auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log"); + bench(iters, std::move(daily_st)); + auto daily_st_tracing = spdlog::daily_logger_st("daily_st/backtrace-on", "logs/daily_st.log"); + daily_st_tracing->enable_backtrace(32); + bench(iters, std::move(daily_st_tracing)); + + spdlog::info(""); + auto empty_logger = std::make_shared("level-off"); + empty_logger->set_level(spdlog::level::off); + bench(iters, empty_logger); + + auto empty_logger_tracing = std::make_shared("level-off/backtrace-on"); + empty_logger_tracing->set_level(spdlog::level::off); + empty_logger_tracing->enable_backtrace(32); + bench(iters, empty_logger_tracing); +} + +int main(int argc, char *argv[]) +{ + spdlog::set_automatic_registration(false); + spdlog::default_logger()->set_pattern("[%^%l%$] %v"); + int iters = 250000; + size_t threads = 4; + try + { + + if (argc > 1) + { + iters = std::stoi(argv[1]); + } + if (argc > 2) + { + threads = std::stoul(argv[2]); + } + + if (threads > max_threads) + { + throw std::runtime_error(spdlog::fmt_lib::format("Number of threads exceeds maximum({})", max_threads)); + } + + bench_single_threaded(iters); + bench_threaded_logging(1, iters); + bench_threaded_logging(threads, iters); + } + catch (std::exception &ex) + { + spdlog::error(ex.what()); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +void bench(int howmany, std::shared_ptr log) +{ + using std::chrono::duration; + using std::chrono::duration_cast; + using std::chrono::high_resolution_clock; + + auto start = high_resolution_clock::now(); + for (auto i = 0; i < howmany; ++i) + { + log->info("Hello logger: msg number {}", i); + } + + auto delta = high_resolution_clock::now() - start; + auto delta_d = duration_cast>(delta).count(); + + spdlog::info(spdlog::fmt_lib::format( + std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d))); + spdlog::drop(log->name()); +} + +void bench_mt(int howmany, std::shared_ptr log, size_t thread_count) +{ + using std::chrono::duration; + using std::chrono::duration_cast; + using std::chrono::high_resolution_clock; + + std::vector threads; + threads.reserve(thread_count); + auto start = high_resolution_clock::now(); + for (size_t t = 0; t < thread_count; ++t) + { + threads.emplace_back([&]() { + for (int j = 0; j < howmany / static_cast(thread_count); j++) + { + log->info("Hello logger: msg number {}", j); + } + }); + } + + for (auto &t : threads) + { + t.join(); + }; + + auto delta = high_resolution_clock::now() - start; + auto delta_d = duration_cast>(delta).count(); + spdlog::info(spdlog::fmt_lib::format( + std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d))); + spdlog::drop(log->name()); +} + +/* +void bench_default_api(int howmany, std::shared_ptr log) +{ + using std::chrono::high_resolution_clock; + using std::chrono::duration; + using std::chrono::duration_cast; + + auto orig_default = spdlog::default_logger(); + spdlog::set_default_logger(log); + auto start = high_resolution_clock::now(); + for (auto i = 0; i < howmany; ++i) + { + spdlog::info("Hello logger: msg number {}", i); + } + + auto delta = high_resolution_clock::now() - start; + auto delta_d = duration_cast>(delta).count(); + spdlog::drop(log->name()); + spdlog::set_default_logger(std::move(orig_default)); + spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany / delta_d)); +} + +void bench_c_string(int howmany, std::shared_ptr log) +{ + using std::chrono::high_resolution_clock; + using std::chrono::duration; + using std::chrono::duration_cast; + + const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " + "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem " + "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed " + "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare " + "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis."; + + auto orig_default = spdlog::default_logger(); + spdlog::set_default_logger(log); + auto start = high_resolution_clock::now(); + for (auto i = 0; i < howmany; ++i) + { + spdlog::log(spdlog::level::info, msg); + } + + auto delta = high_resolution_clock::now() - start; + auto delta_d = duration_cast>(delta).count(); + spdlog::drop(log->name()); + spdlog::set_default_logger(std::move(orig_default)); + spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany / delta_d)); +} + +*/ \ No newline at end of file diff --git a/Lumos/External/spdlog/bench/formatter-bench.cpp b/Lumos/External/spdlog/bench/formatter-bench.cpp new file mode 100644 index 000000000..1454c6bb8 --- /dev/null +++ b/Lumos/External/spdlog/bench/formatter-bench.cpp @@ -0,0 +1,80 @@ +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#include "benchmark/benchmark.h" + +#include "spdlog/spdlog.h" +#include "spdlog/pattern_formatter.h" + +void bench_formatter(benchmark::State &state, std::string pattern) +{ + auto formatter = spdlog::details::make_unique(pattern); + spdlog::memory_buf_t dest; + std::string logger_name = "logger-name"; + const char *text = "Hello. This is some message with length of 80 "; + + spdlog::source_loc source_loc{"a/b/c/d/myfile.cpp", 123, "some_func()"}; + spdlog::details::log_msg msg(source_loc, logger_name, spdlog::level::info, text); + + for (auto _ : state) + { + dest.clear(); + formatter->format(msg, dest); + benchmark::DoNotOptimize(dest); + } +} + +void bench_formatters() +{ + // basic patterns(single flag) + std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEisg@luioO%"; + std::vector basic_patterns; + for (auto &flag : all_flags) + { + auto pattern = std::string("%") + flag; + benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern); + + // pattern = std::string("%16") + flag; + // benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern); + // + // // bench center padding + // pattern = std::string("%=16") + flag; + // benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern); + } + + // complex patterns + std::vector patterns = { + "[%D %X] [%l] [%n] %v", + "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v", + "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v", + }; + for (auto &pattern : patterns) + { + benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern)->Iterations(2500000); + } +} + +int main(int argc, char *argv[]) +{ + + spdlog::set_pattern("[%^%l%$] %v"); + if (argc != 2) + { + spdlog::error("Usage: {} (or \"all\" to bench all)", argv[0]); + exit(1); + } + + std::string pattern = argv[1]; + if (pattern == "all") + { + bench_formatters(); + } + else + { + benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern); + } + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/Lumos/External/spdlog/bench/latency.cpp b/Lumos/External/spdlog/bench/latency.cpp new file mode 100644 index 000000000..8f002ee12 --- /dev/null +++ b/Lumos/External/spdlog/bench/latency.cpp @@ -0,0 +1,189 @@ +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +// +// latency.cpp : spdlog latency benchmarks +// + +#include "benchmark/benchmark.h" + +#include "spdlog/spdlog.h" +#include "spdlog/async.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/daily_file_sink.h" +#include "spdlog/sinks/null_sink.h" +#include "spdlog/sinks/rotating_file_sink.h" + +void bench_c_string(benchmark::State &state, std::shared_ptr logger) +{ + const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " + "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem " + "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed " + "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare " + "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis."; + + for (auto _ : state) + { + logger->info(msg); + } +} + +void bench_logger(benchmark::State &state, std::shared_ptr logger) +{ + int i = 0; + for (auto _ : state) + { + logger->info("Hello logger: msg number {}...............", ++i); + } +} +void bench_global_logger(benchmark::State &state, std::shared_ptr logger) +{ + spdlog::set_default_logger(std::move(logger)); + int i = 0; + for (auto _ : state) + { + spdlog::info("Hello logger: msg number {}...............", ++i); + } +} + +void bench_disabled_macro(benchmark::State &state, std::shared_ptr logger) +{ + int i = 0; + benchmark::DoNotOptimize(i); // prevent unused warnings + benchmark::DoNotOptimize(logger); // prevent unused warnings + for (auto _ : state) + { + SPDLOG_LOGGER_DEBUG(logger, "Hello logger: msg number {}...............", i++); + } +} + +void bench_disabled_macro_global_logger(benchmark::State &state, std::shared_ptr logger) +{ + spdlog::set_default_logger(std::move(logger)); + int i = 0; + benchmark::DoNotOptimize(i); // prevent unused warnings + benchmark::DoNotOptimize(logger); // prevent unused warnings + for (auto _ : state) + { + SPDLOG_DEBUG("Hello logger: msg number {}...............", i++); + } +} + +#ifdef __linux__ +void bench_dev_null() +{ + auto dev_null_st = spdlog::basic_logger_st("/dev/null_st", "/dev/null"); + benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))->UseRealTime(); + spdlog::drop("/dev/null_st"); + + auto dev_null_mt = spdlog::basic_logger_mt("/dev/null_mt", "/dev/null"); + benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))->UseRealTime(); + spdlog::drop("/dev/null_mt"); +} +#endif // __linux__ + +int main(int argc, char *argv[]) +{ + using spdlog::sinks::null_sink_mt; + using spdlog::sinks::null_sink_st; + + size_t file_size = 30 * 1024 * 1024; + size_t rotating_files = 5; + int n_threads = benchmark::CPUInfo::Get().num_cpus; + + auto full_bench = argc > 1 && std::string(argv[1]) == "full"; + + // disabled loggers + auto disabled_logger = std::make_shared("bench", std::make_shared()); + disabled_logger->set_level(spdlog::level::off); + benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger); + benchmark::RegisterBenchmark("disabled-at-compile-time (global logger)", bench_disabled_macro_global_logger, disabled_logger); + benchmark::RegisterBenchmark("disabled-at-runtime", bench_logger, disabled_logger); + benchmark::RegisterBenchmark("disabled-at-runtime (global logger)", bench_global_logger, disabled_logger); + // with backtrace of 64 + auto tracing_disabled_logger = std::make_shared("bench", std::make_shared()); + tracing_disabled_logger->enable_backtrace(64); + benchmark::RegisterBenchmark("disabled-at-runtime/backtrace", bench_logger, tracing_disabled_logger); + + auto null_logger_st = std::make_shared("bench", std::make_shared()); + benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string, std::move(null_logger_st)); + benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger_st); + benchmark::RegisterBenchmark("null_sink_st (global logger)", bench_global_logger, null_logger_st); + // with backtrace of 64 + auto tracing_null_logger_st = std::make_shared("bench", std::make_shared()); + tracing_null_logger_st->enable_backtrace(64); + benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); + +#ifdef __linux + bench_dev_null(); +#endif // __linux__ + + if (full_bench) + { + // basic_st + auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); + benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime(); + spdlog::drop("basic_st"); + // with backtrace of 64 + auto tracing_basic_st = spdlog::basic_logger_st("tracing_basic_st", "latency_logs/tracing_basic_st.log", true); + tracing_basic_st->enable_backtrace(64); + benchmark::RegisterBenchmark("basic_st/backtrace", bench_logger, std::move(tracing_basic_st))->UseRealTime(); + spdlog::drop("tracing_basic_st"); + + // rotating st + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files); + benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime(); + spdlog::drop("rotating_st"); + // with backtrace of 64 + auto tracing_rotating_st = + spdlog::rotating_logger_st("tracing_rotating_st", "latency_logs/tracing_rotating_st.log", file_size, rotating_files); + benchmark::RegisterBenchmark("rotating_st/backtrace", bench_logger, std::move(tracing_rotating_st))->UseRealTime(); + spdlog::drop("tracing_rotating_st"); + + // daily st + auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log"); + benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime(); + spdlog::drop("daily_st"); + auto tracing_daily_st = spdlog::daily_logger_mt("tracing_daily_st", "latency_logs/daily_st.log"); + benchmark::RegisterBenchmark("daily_st/backtrace", bench_logger, std::move(tracing_daily_st))->UseRealTime(); + spdlog::drop("tracing_daily_st"); + + // + // Multi threaded bench, 10 loggers using same logger concurrently + // + auto null_logger_mt = std::make_shared("bench", std::make_shared()); + benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime(); + + // basic_mt + auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true); + benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime(); + spdlog::drop("basic_mt"); + + // rotating mt + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files); + benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime(); + spdlog::drop("rotating_mt"); + + // daily mt + auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log"); + benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime(); + spdlog::drop("daily_mt"); + } + + // async + auto queue_size = 1024 * 1024 * 3; + auto tp = std::make_shared(queue_size, 1); + auto async_logger = std::make_shared( + "async_logger", std::make_shared(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest); + benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)->Threads(n_threads)->UseRealTime(); + + auto async_logger_tracing = std::make_shared( + "async_logger_tracing", std::make_shared(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest); + async_logger_tracing->enable_backtrace(32); + benchmark::RegisterBenchmark("async_logger/tracing", bench_logger, async_logger_tracing)->Threads(n_threads)->UseRealTime(); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/Lumos/External/spdlog/bench/utils.h b/Lumos/External/spdlog/bench/utils.h new file mode 100644 index 000000000..916101283 --- /dev/null +++ b/Lumos/External/spdlog/bench/utils.h @@ -0,0 +1,34 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include +#include +#include + +namespace utils { + +template +inline std::string format(const T &value) +{ + static std::locale loc(""); + std::stringstream ss; + ss.imbue(loc); + ss << value; + return ss.str(); +} + +template<> +inline std::string format(const double &value) +{ + static std::locale loc(""); + std::stringstream ss; + ss.imbue(loc); + ss << std::fixed << std::setprecision(1) << value; + return ss.str(); +} + +} // namespace utils diff --git a/Lumos/External/spdlog/cmake/ide.cmake b/Lumos/External/spdlog/cmake/ide.cmake new file mode 100644 index 000000000..a0656a5e8 --- /dev/null +++ b/Lumos/External/spdlog/cmake/ide.cmake @@ -0,0 +1,18 @@ +# --------------------------------------------------------------------------------------- +# IDE support for headers +# --------------------------------------------------------------------------------------- +set(SPDLOG_HEADERS_DIR "${CMAKE_CURRENT_LIST_DIR}/../include") + +file(GLOB SPDLOG_TOP_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/*.h") +file(GLOB SPDLOG_DETAILS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/details/*.h") +file(GLOB SPDLOG_SINKS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/sinks/*.h") +file(GLOB SPDLOG_FMT_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/*.h") +file(GLOB SPDLOG_FMT_BUNDELED_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/bundled/*.h") +set(SPDLOG_ALL_HEADERS ${SPDLOG_TOP_HEADERS} ${SPDLOG_DETAILS_HEADERS} ${SPDLOG_SINKS_HEADERS} ${SPDLOG_FMT_HEADERS} + ${SPDLOG_FMT_BUNDELED_HEADERS}) + +source_group("Header Files\\spdlog" FILES ${SPDLOG_TOP_HEADERS}) +source_group("Header Files\\spdlog\\details" FILES ${SPDLOG_DETAILS_HEADERS}) +source_group("Header Files\\spdlog\\sinks" FILES ${SPDLOG_SINKS_HEADERS}) +source_group("Header Files\\spdlog\\fmt" FILES ${SPDLOG_FMT_HEADERS}) +source_group("Header Files\\spdlog\\fmt\\bundled\\" FILES ${SPDLOG_FMT_BUNDELED_HEADERS}) diff --git a/Lumos/External/spdlog/cmake/pch.h.in b/Lumos/External/spdlog/cmake/pch.h.in new file mode 100644 index 000000000..a5f941507 --- /dev/null +++ b/Lumos/External/spdlog/cmake/pch.h.in @@ -0,0 +1,258 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// details/pattern_formatter-inl.h +// fmt/bin_to_hex.h +// fmt/bundled/format-inl.h +#include + +// details/file_helper-inl.h +// details/os-inl.h +// fmt/bundled/core.h +// fmt/bundled/posix.h +// logger-inl.h +// sinks/daily_file_sink.h +// sinks/stdout_sinks.h +#include + +// details/os-inl.h +// fmt/bundled/posix.h +#include + +// details/os-inl.h +// details/pattern_formatter-inl.h +// fmt/bundled/core.h +// fmt/bundled/format-inl.h +#include + +// details/os-inl.h +// details/os.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// fmt/bundled/chrono.h +// sinks/daily_file_sink.h +// sinks/rotating_file_sink-inl.h +#include + +// fmt/bundled/format-inl.h +#include + +// fmt/bundled/format-inl.h +#include + +// fmt/bundled/format-inl.h +// fmt/bundled/format.h +#include + +// fmt/bundled/format-inl.h +#include + +// details/file_helper-inl.h +// fmt/bundled/format.h +// fmt/bundled/posix.h +// sinks/rotating_file_sink-inl.h +#include + +// details/circular_q.h +// details/thread_pool-inl.h +// fmt/bundled/format-inl.h +#include + +// async_logger-inl.h +// cfg/helpers-inl.h +// log_levels.h +// common.h +// details/file_helper-inl.h +// details/log_msg.h +// details/os-inl.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/registry-inl.h +// details/registry.h +// details/tcp_client-windows.h +// details/tcp_client.h +// fmt/bundled/core.h +// sinks/android_sink.h +// sinks/ansicolor_sink.h +// sinks/basic_file_sink.h +// sinks/daily_file_sink.h +// sinks/dup_filter_sink.h +// sinks/msvc_sink.h +// sinks/ringbuffer_sink.h +// sinks/rotating_file_sink-inl.h +// sinks/rotating_file_sink.h +// sinks/syslog_sink.h +// sinks/tcp_sink.h +// sinks/win_eventlog_sink.h +// sinks/wincolor_sink.h +// spdlog.h: +#include + +// cfg/helpers-inl.h +// fmt/bundled/chrono.h +#include + +// fmt/bundled/ostream.h +// sinks/ostream_sink.h +#include + +// cfg/log_levels.h +// details/registry-inl.h +// details/registry.h +#include + +// details/circular_q.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/thread_pool.h +// fmt/bundled/compile.h +// logger.h +// sinks/dist_sink.h +// sinks/ringbuffer_sink.h +// sinks/win_eventlog_sink.h +#include + +// details/os-inl.h +// details/pattern_formatter-inl.h +// sinks/ansicolor_sink.h +// sinks/syslog_sink.h +// sinks/systemd_sink.h +// sinks/wincolor_sink.h +#include + +// details/file_helper-inl.h +// details/file_helper.h +// sinks/rotating_file_sink-inl.h +#include + +// details/os-inl.h +// fmt/bundled/format.h +// fmt/bundled/printf.h +#include + +// common.h +// details/backtracer.h +// details/null_mutex.h +#include + +// common.h +// details/backtracer.h +// details/null_mutex.h +#include + +// common.h +#include + +// common.h +#include + +// common.h +// details/fmt_helper.h +// fmt/bundled/core.h +// fmt/bundled/ranges.h +#include + +// cfg/helpers-inl.h +// details/null_mutex.h +// details/pattern_formatter-inl.h +#include + +// async.h +// async_logger-inl.h +// common.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/registry-inl.h +// details/registry.h +// details/thread_pool.h +// fmt/bundled/format.h +// sinks/ansicolor_sink.h +// sinks/base_sink-inl.h +// sinks/dist_sink.h +// sinks/stdout_sinks-inl.h +// sinks/wincolor_sink.h +// spdlog.h +#include + +// async.h +// common.h +// details/backtracer.h +// details/periodic_worker.h +// details/registry-inl.h +// details/registry.h +// details/thread_pool.h +// sinks/tcp_sink.h +// spdlog.h +#include + +// details/mpmc_blocking_q.h +// details/periodic_worker.h +#include + +// details/os-inl.h +// fmt/bundled/format.h +// fmt/bundled/printf.h +// sinks/dist_sink.h +#include + +// common.h +// details/file_helper-inl.h +// details/fmt_helper.h +// details/os-inl.h +// details/pattern_formatter-inl.h +// details/pattern_formatter.h +// details/periodic_worker.h +// details/registry-inl.h +// details/registry.h +// details/thread_pool.h +// fmt/bundled/chrono.h +// sinks/android_sink.h +// sinks/daily_file_sink.h +// sinks/dup_filter_sink.h +// sinks/rotating_file_sink-inl.h +// sinks/rotating_file_sink.h +// sinks/tcp_sink.h +// spdlog.h +#include + +// details/file_helper-inl.h +// details/os-inl.h +// details/pattern_formatter-inl.h +// details/periodic_worker.h +// details/thread_pool.h +// sinks/android_sink.h +#include + +// async.h +// details/backtracer.h +// details/console_globals.h +// details/mpmc_blocking_q.h +// details/pattern_formatter-inl.h +// details/periodic_worker.h +// details/registry.h +// sinks/android_sink.h +// sinks/ansicolor_sink.h +// sinks/basic_file_sink.h +// sinks/daily_file_sink.h +// sinks/dist_sink.h +// sinks/dup_filter_sink.h +// sinks/msvc_sink.h +// sinks/null_sink.h +// sinks/ostream_sink.h +// sinks/ringbuffer_sink.h +// sinks/rotating_file_sink-inl.h +// sinks/rotating_file_sink.h +// sinks/tcp_sink.h +// sinks/win_eventlog_sink.h +// sinks/wincolor_sink.h +// +// color_sinks.cpp +// file_sinks.cpp +// spdlog.cpp +// stdout_sinks.cpp +#include + +// spdlog +#include \ No newline at end of file diff --git a/Lumos/External/spdlog/cmake/spdlog.pc.in b/Lumos/External/spdlog/cmake/spdlog.pc.in new file mode 100644 index 000000000..ffab5d6f8 --- /dev/null +++ b/Lumos/External/spdlog/cmake/spdlog.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +includedir=@PKG_CONFIG_INCLUDEDIR@ +libdir=@PKG_CONFIG_LIBDIR@ + +Name: lib@PROJECT_NAME@ +Description: Fast C++ logging library. +URL: https://github.com/gabime/@PROJECT_NAME@ +Version: @SPDLOG_VERSION@ +CFlags: -I${includedir} @PKG_CONFIG_DEFINES@ +Libs: -L${libdir} -lspdlog -pthread +Requires: @PKG_CONFIG_REQUIRES@ + diff --git a/Lumos/External/spdlog/cmake/spdlogConfig.cmake.in b/Lumos/External/spdlog/cmake/spdlogConfig.cmake.in new file mode 100644 index 000000000..d8a3ac164 --- /dev/null +++ b/Lumos/External/spdlog/cmake/spdlogConfig.cmake.in @@ -0,0 +1,20 @@ +# Copyright(c) 2019 spdlog authors +# Distributed under the MIT License (http://opensource.org/licenses/MIT) + +@PACKAGE_INIT@ + +find_package(Threads REQUIRED) + +set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@) +set(SPDLOG_FMT_EXTERNAL_HO @SPDLOG_FMT_EXTERNAL_HO@) +set(config_targets_file @config_targets_file@) + +if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO) + include(CMakeFindDependencyMacro) + find_dependency(fmt CONFIG) +endif() + + +include("${CMAKE_CURRENT_LIST_DIR}/${config_targets_file}") + +check_required_components(spdlog) diff --git a/Lumos/External/spdlog/cmake/utils.cmake b/Lumos/External/spdlog/cmake/utils.cmake new file mode 100644 index 000000000..85fcd80f7 --- /dev/null +++ b/Lumos/External/spdlog/cmake/utils.cmake @@ -0,0 +1,62 @@ +# Get spdlog version from include/spdlog/version.h and put it in SPDLOG_VERSION +function(spdlog_extract_version) + file(READ "${CMAKE_CURRENT_LIST_DIR}/include/spdlog/version.h" file_contents) + string(REGEX MATCH "SPDLOG_VER_MAJOR ([0-9]+)" _ "${file_contents}") + if(NOT CMAKE_MATCH_COUNT EQUAL 1) + message(FATAL_ERROR "Could not extract major version number from spdlog/version.h") + endif() + set(ver_major ${CMAKE_MATCH_1}) + + string(REGEX MATCH "SPDLOG_VER_MINOR ([0-9]+)" _ "${file_contents}") + if(NOT CMAKE_MATCH_COUNT EQUAL 1) + message(FATAL_ERROR "Could not extract minor version number from spdlog/version.h") + endif() + + set(ver_minor ${CMAKE_MATCH_1}) + string(REGEX MATCH "SPDLOG_VER_PATCH ([0-9]+)" _ "${file_contents}") + if(NOT CMAKE_MATCH_COUNT EQUAL 1) + message(FATAL_ERROR "Could not extract patch version number from spdlog/version.h") + endif() + set(ver_patch ${CMAKE_MATCH_1}) + + set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE) + set(SPDLOG_VERSION_MINOR ${ver_minor} PARENT_SCOPE) + set(SPDLOG_VERSION_PATCH ${ver_patch} PARENT_SCOPE) + set(SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE) +endfunction() + +# Turn on warnings on the given target +function(spdlog_enable_warnings target_name) + if(SPDLOG_BUILD_WARNINGS) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + list(APPEND MSVC_OPTIONS "/W3") + if(MSVC_VERSION GREATER 1900) # Allow non fatal security warnings for msvc 2015 + list(APPEND MSVC_OPTIONS "/WX") + endif() + endif() + + target_compile_options( + ${target_name} + PRIVATE $<$,$,$>: + -Wall + -Wextra + -Wconversion + -pedantic + -Werror + -Wfatal-errors> + $<$:${MSVC_OPTIONS}>) + endif() +endfunction() + +# Enable address sanitizer (gcc/clang only) +function(spdlog_enable_sanitizer target_name) + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + message(FATAL_ERROR "Sanitizer supported only for gcc/clang") + endif() + message(STATUS "Address sanitizer enabled") + target_compile_options(${target_name} PRIVATE -fsanitize=address,undefined) + target_compile_options(${target_name} PRIVATE -fno-sanitize=signed-integer-overflow) + target_compile_options(${target_name} PRIVATE -fno-sanitize-recover=all) + target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer) + target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined -fuse-ld=gold) +endfunction() diff --git a/Lumos/External/spdlog/cmake/version.rc.in b/Lumos/External/spdlog/cmake/version.rc.in new file mode 100644 index 000000000..a86c13853 --- /dev/null +++ b/Lumos/External/spdlog/cmake/version.rc.in @@ -0,0 +1,42 @@ +#define APSTUDIO_READONLY_SYMBOLS +#include +#undef APSTUDIO_READONLY_SYMBOLS + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0 + PRODUCTVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "spdlog dll\0" + VALUE "FileVersion", "@SPDLOG_VERSION@.0\0" + VALUE "InternalName", "spdlog.dll\0" + VALUE "LegalCopyright", "Copyright (C) spdlog\0" + VALUE "ProductName", "spdlog\0" + VALUE "ProductVersion", "@SPDLOG_VERSION@.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + + + + diff --git a/Lumos/External/spdlog/example/CMakeLists.txt b/Lumos/External/spdlog/example/CMakeLists.txt new file mode 100644 index 000000000..a7863493c --- /dev/null +++ b/Lumos/External/spdlog/example/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT) + +cmake_minimum_required(VERSION 3.10) +project(spdlog_examples CXX) + +if(NOT TARGET spdlog) + # Stand-alone build + find_package(spdlog REQUIRED) +endif() + +# --------------------------------------------------------------------------------------- +# Example of using pre-compiled library +# --------------------------------------------------------------------------------------- +add_executable(example example.cpp) +target_link_libraries(example PRIVATE spdlog::spdlog $<$:ws2_32>) + +# --------------------------------------------------------------------------------------- +# Example of using header-only library +# --------------------------------------------------------------------------------------- +if(SPDLOG_BUILD_EXAMPLE_HO) + add_executable(example_header_only example.cpp) + target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) +endif() diff --git a/Lumos/External/spdlog/example/example.cpp b/Lumos/External/spdlog/example/example.cpp new file mode 100644 index 000000000..d6609ed51 --- /dev/null +++ b/Lumos/External/spdlog/example/example.cpp @@ -0,0 +1,398 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// spdlog usage example + +#include +#include + +void load_levels_example(); +void stdout_logger_example(); +void basic_example(); +void rotating_example(); +void daily_example(); +void callback_example(); +void async_example(); +void binary_example(); +void vector_example(); +void stopwatch_example(); +void trace_example(); +void multi_sink_example(); +void user_defined_example(); +void err_handler_example(); +void syslog_example(); +void udp_example(); +void custom_flags_example(); +void file_events_example(); +void replace_default_logger_example(); + +#include "spdlog/spdlog.h" +#include "spdlog/cfg/env.h" // support for loading levels from the environment variable +#include "spdlog/fmt/ostr.h" // support for user defined types + + +int main(int, char *[]) +{ + // Log levels can be loaded from argv/env using "SPDLOG_LEVEL" + load_levels_example(); + + spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); + + spdlog::warn("Easy padding in numbers like {:08d}", 12); + spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + spdlog::info("Support for floats {:03.2f}", 1.23456); + spdlog::info("Positional args are {1} {0}..", "too", "supported"); + spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left"); + + // Runtime log levels + spdlog::set_level(spdlog::level::info); // Set global log level to info + spdlog::debug("This message should not be displayed!"); + spdlog::set_level(spdlog::level::trace); // Set specific logger's log level + spdlog::debug("This message should be displayed.."); + + // Customize msg format for all loggers + spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); + spdlog::info("This an info message with custom format"); + spdlog::set_pattern("%+"); // back to default format + spdlog::set_level(spdlog::level::info); + + // Backtrace support + // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection. + // When needed, call dump_backtrace() to see what happened: + spdlog::enable_backtrace(10); // create ring buffer with capacity of 10 messages + for (int i = 0; i < 100; i++) + { + spdlog::debug("Backtrace message {}", i); // not logged.. + } + // e.g. if some error happened: + spdlog::dump_backtrace(); // log them now! + + try + { + stdout_logger_example(); + basic_example(); + rotating_example(); + daily_example(); + callback_example(); + async_example(); + binary_example(); + vector_example(); + multi_sink_example(); + user_defined_example(); + err_handler_example(); + trace_example(); + stopwatch_example(); + udp_example(); + custom_flags_example(); + file_events_example(); + replace_default_logger_example(); + + // Flush all *registered* loggers using a worker thread every 3 seconds. + // note: registered loggers *must* be thread safe for this to work correctly! + spdlog::flush_every(std::chrono::seconds(3)); + + // Apply some function on all registered loggers + spdlog::apply_all([&](std::shared_ptr l) { l->info("End of example."); }); + + // Release all spdlog resources, and drop all loggers in the registry. + // This is optional (only mandatory if using windows + async log). + spdlog::shutdown(); + } + + // Exceptions will only be thrown upon failed logger or sink construction (not during logging). + catch (const spdlog::spdlog_ex &ex) + { + std::printf("Log initialization failed: %s\n", ex.what()); + return 1; + } +} + +#include "spdlog/sinks/stdout_color_sinks.h" +// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed. +void stdout_logger_example() +{ + // Create color multi threaded logger. + auto console = spdlog::stdout_color_mt("console"); + // or for stderr: + // auto console = spdlog::stderr_color_mt("error-logger"); +} + +#include "spdlog/sinks/basic_file_sink.h" +void basic_example() +{ + // Create basic file logger (not rotated). + auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt", true); +} + +#include "spdlog/sinks/rotating_file_sink.h" +void rotating_example() +{ + // Create a file rotating logger with 5mb size max and 3 rotated files. + auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); +} + +#include "spdlog/sinks/daily_file_sink.h" +void daily_example() +{ + // Create a daily logger - a new file is created every day on 2:30am. + auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); +} + +#include "spdlog/sinks/callback_sink.h" +void callback_example() +{ + // Create the logger + auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg & /*msg*/) { + // do what you need to do with msg + }); +} + +#include "spdlog/cfg/env.h" +void load_levels_example() +{ + // Set the log level to "info" and mylogger to "trace": + // SPDLOG_LEVEL=info,mylogger=trace && ./example + spdlog::cfg::load_env_levels(); + // or from command line: + // ./example SPDLOG_LEVEL=info,mylogger=trace + // #include "spdlog/cfg/argv.h" // for loading levels from argv + // spdlog::cfg::load_argv_levels(args, argv); +} + +#include "spdlog/async.h" +void async_example() +{ + // Default thread pool settings can be modified *before* creating the async logger: + // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread. + auto async_file = spdlog::basic_logger_mt("async_file_logger", "logs/async_log.txt"); + // alternatively: + // auto async_file = spdlog::create_async("async_file_logger", "logs/async_log.txt"); + + for (int i = 1; i < 101; ++i) + { + async_file->info("Async message #{}", i); + } +} + +// Log binary data as hex. +// Many types of std::container types can be used. +// Iterator ranges are supported too. +// Format flags: +// {: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. + +#if !defined SPDLOG_USE_STD_FORMAT || defined(_MSC_VER) +#include "spdlog/fmt/bin_to_hex.h" +void binary_example() +{ + std::vector buf(80); + for (int i = 0; i < 80; i++) + { + buf.push_back(static_cast(i & 0xff)); + } + spdlog::info("Binary example: {}", spdlog::to_hex(buf)); + spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10)); + // more examples: + // logger->info("uppercase: {:X}", spdlog::to_hex(buf)); + // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); + // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf)); + // logger->info("hexdump style: {:a}", spdlog::to_hex(buf)); + // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20)); +} +#else +void binary_example() { + // not supported with std::format yet +} +#endif + +// Log a vector of numbers +#ifndef SPDLOG_USE_STD_FORMAT +# include "spdlog/fmt/ranges.h" +void vector_example() +{ + std::vector vec = {1, 2, 3}; + spdlog::info("Vector example: {}", vec); +} + +#else +void vector_example() {} +#endif + +// ! DSPDLOG_USE_STD_FORMAT + +// Compile time log levels. +// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE) +void trace_example() +{ + // trace from default logger + SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23); + // debug from default logger + SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23); + + // trace from logger object + auto logger = spdlog::get("file_logger"); + SPDLOG_LOGGER_TRACE(logger, "another trace message"); +} + +// stopwatch example +#include "spdlog/stopwatch.h" +#include +void stopwatch_example() +{ + spdlog::stopwatch sw; + std::this_thread::sleep_for(std::chrono::milliseconds(123)); + spdlog::info("Stopwatch: {} seconds", sw); +} + +#include "spdlog/sinks/udp_sink.h" +void udp_example() +{ + spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091); + auto my_logger = spdlog::udp_logger_mt("udplog", cfg); + my_logger->set_level(spdlog::level::debug); + my_logger->info("hello world"); +} + +// A logger with multiple sinks (stdout and file) - each with a different format and log level. +void multi_sink_example() +{ + auto console_sink = std::make_shared(); + console_sink->set_level(spdlog::level::warn); + console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); + + auto file_sink = std::make_shared("logs/multisink.txt", true); + file_sink->set_level(spdlog::level::trace); + + spdlog::logger logger("multi_sink", {console_sink, file_sink}); + logger.set_level(spdlog::level::debug); + logger.warn("this should appear in both console and file"); + logger.info("this message should not appear in the console, only in the file"); +} + +// User defined types logging +struct my_type +{ + int i = 0; + explicit my_type(int i) + : i(i){}; +}; + +#ifndef SPDLOG_USE_STD_FORMAT // when using fmtlib +template<> +struct fmt::formatter : fmt::formatter +{ + auto format(my_type my, format_context &ctx) -> decltype(ctx.out()) + { + return fmt::format_to(ctx.out(), "[my_type i={}]", my.i); + } +}; + +#else // when using std::format +template<> +struct std::formatter : std::formatter +{ + auto format(my_type my, format_context &ctx) const -> decltype(ctx.out()) + { + return format_to(ctx.out(), "[my_type i={}]", my.i); + } +}; +#endif + +void user_defined_example() +{ + spdlog::info("user defined type: {}", my_type(14)); +} + +// Custom error handler. Will be triggered on log failure. +void err_handler_example() +{ + // can be set globally or per logger(logger->set_error_handler(..)) + spdlog::set_error_handler([](const std::string &msg) { printf("*** Custom log error handler: %s ***\n", msg.c_str()); }); +} + +// syslog example (linux/osx/freebsd) +#ifndef _WIN32 +# include "spdlog/sinks/syslog_sink.h" +void syslog_example() +{ + std::string ident = "spdlog-example"; + auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); + syslog_logger->warn("This is warning that will end up in syslog."); +} +#endif + +// Android example. +#if defined(__ANDROID__) +# include "spdlog/sinks/android_sink.h" +void android_example() +{ + std::string tag = "spdlog-android"; + auto android_logger = spdlog::android_logger_mt("android", tag); + android_logger->critical("Use \"adb shell logcat\" to view this message."); +} +#endif + +// Log patterns can contain custom flags. +// this will add custom flag '%*' which will be bound to a instance +#include "spdlog/pattern_formatter.h" +class my_formatter_flag : public spdlog::custom_flag_formatter +{ +public: + void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override + { + std::string some_txt = "custom-flag"; + dest.append(some_txt.data(), some_txt.data() + some_txt.size()); + } + + std::unique_ptr clone() const override + { + return spdlog::details::make_unique(); + } +}; + +void custom_flags_example() +{ + + using spdlog::details::make_unique; // for pre c++14 + auto formatter = make_unique(); + formatter->add_flag('*').set_pattern("[%n] [%*] [%^%l%$] %v"); + // set the new formatter using spdlog::set_formatter(formatter) or logger->set_formatter(formatter) + // spdlog::set_formatter(std::move(formatter)); +} + +void file_events_example() +{ + // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications + spdlog::file_event_handlers handlers; + handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); }; + handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { + spdlog::info("After opening {}", filename); + fputs("After opening\n", fstream); + }; + handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { + spdlog::info("Before closing {}", filename); + fputs("Before closing\n", fstream); + }; + handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); }; + auto file_sink = std::make_shared("logs/events-sample.txt", true, handlers); + spdlog::logger my_logger("some_logger", file_sink); + my_logger.info("Some log line"); +} + +void replace_default_logger_example() +{ + // store the old logger so we don't break other examples. + auto old_logger = spdlog::default_logger(); + + auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true); + spdlog::set_default_logger(new_logger); + spdlog::set_level(spdlog::level::info); + spdlog::debug("This message should not be displayed!"); + spdlog::set_level(spdlog::level::trace); + spdlog::debug("This message should be displayed.."); + + spdlog::set_default_logger(old_logger); +} diff --git a/Lumos/External/spdlog/include/spdlog/async.h b/Lumos/External/spdlog/include/spdlog/async.h index 6406822c5..94f9f6d94 100644 --- a/Lumos/External/spdlog/include/spdlog/async.h +++ b/Lumos/External/spdlog/include/spdlog/async.h @@ -73,16 +73,22 @@ inline std::shared_ptr create_async_nb(std::string logger_name, } // set global thread pool. -inline void init_thread_pool(size_t q_size, size_t thread_count, std::function on_thread_start) +inline void init_thread_pool( + size_t q_size, size_t thread_count, std::function on_thread_start, std::function on_thread_stop) { - auto tp = std::make_shared(q_size, thread_count, on_thread_start); + auto tp = std::make_shared(q_size, thread_count, on_thread_start, on_thread_stop); 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, std::function on_thread_start) +{ + init_thread_pool(q_size, thread_count, on_thread_start, [] {}); +} + inline void init_thread_pool(size_t q_size, size_t thread_count) { - init_thread_pool(q_size, thread_count, [] {}); + init_thread_pool( + q_size, thread_count, [] {}, [] {}); } // get the global thread pool. diff --git a/Lumos/External/spdlog/include/spdlog/async_logger-inl.h b/Lumos/External/spdlog/include/spdlog/async_logger-inl.h index 6fac8fc9f..4de8382a6 100644 --- a/Lumos/External/spdlog/include/spdlog/async_logger-inl.h +++ b/Lumos/External/spdlog/include/spdlog/async_logger-inl.h @@ -24,29 +24,27 @@ SPDLOG_INLINE spdlog::async_logger::async_logger( {} // send the log message to the thread pool -SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg) +SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); +} +else { - 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"); - } + throw_spdlog_ex("async log: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(msg.source) } // send flush request to the thread pool -SPDLOG_INLINE void spdlog::async_logger::flush_() +SPDLOG_INLINE void spdlog::async_logger::flush_(){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){pool_ptr->post_flush(shared_from_this(), overflow_policy_); +} +else { - 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"); - } + throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(source_loc()) } // @@ -62,7 +60,7 @@ SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg { sink->log(msg); } - SPDLOG_LOGGER_CATCH() + SPDLOG_LOGGER_CATCH(msg.source) } } @@ -80,7 +78,7 @@ SPDLOG_INLINE void spdlog::async_logger::backend_flush_() { sink->flush(); } - SPDLOG_LOGGER_CATCH() + SPDLOG_LOGGER_CATCH(source_loc()) } } diff --git a/Lumos/External/spdlog/include/spdlog/common-inl.h b/Lumos/External/spdlog/include/spdlog/common-inl.h index f83476563..728f98317 100644 --- a/Lumos/External/spdlog/include/spdlog/common-inl.h +++ b/Lumos/External/spdlog/include/spdlog/common-inl.h @@ -55,9 +55,13 @@ SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) { +#ifdef SPDLOG_USE_STD_FORMAT + msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); +#else memory_buf_t outbuf; fmt::format_system_error(outbuf, last_errno, msg.c_str()); msg_ = fmt::to_string(outbuf); +#endif } SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT diff --git a/Lumos/External/spdlog/include/spdlog/common.h b/Lumos/External/spdlog/include/spdlog/common.h index d64348931..0a262eb2c 100644 --- a/Lumos/External/spdlog/include/spdlog/common.h +++ b/Lumos/External/spdlog/include/spdlog/common.h @@ -14,16 +14,30 @@ #include #include #include +#include + +#ifdef SPDLOG_USE_STD_FORMAT +# include +# if __cpp_lib_format >= 202207L +# include +# else +# include +# endif +#endif #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) +# if defined(SPDLOG_SHARED_LIB) +# if defined(_WIN32) +# ifdef spdlog_EXPORTS +# define SPDLOG_API __declspec(dllexport) +# else // !spdlog_EXPORTS +# define SPDLOG_API __declspec(dllimport) +# endif +# else // !defined(_WIN32) +# define SPDLOG_API __attribute__((visibility("default"))) # endif -# else // !defined(_WIN32) || !defined(SPDLOG_SHARED_LIB) +# else // !defined(SPDLOG_SHARED_LIB) # define SPDLOG_API # endif # define SPDLOG_INLINE @@ -35,23 +49,30 @@ #include -// backward compatibility with fmt versions older than 8 -#if FMT_VERSION >= 80000 +#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8 # define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) +# define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string) # if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) # include # endif #else # define SPDLOG_FMT_RUNTIME(format_string) format_string +# define SPDLOG_FMT_STRING(format_string) format_string #endif -// visual studio upto 2013 does not support noexcept nor constexpr +// visual studio up to 2013 does not support noexcept nor constexpr #if defined(_MSC_VER) && (_MSC_VER < 1900) # define SPDLOG_NOEXCEPT _NOEXCEPT # define SPDLOG_CONSTEXPR +# define SPDLOG_CONSTEXPR_FUNC inline #else # define SPDLOG_NOEXCEPT noexcept # define SPDLOG_CONSTEXPR constexpr +# if __cplusplus >= 201402L +# define SPDLOG_CONSTEXPR_FUNC constexpr +# else +# define SPDLOG_CONSTEXPR_FUNC inline +# endif #endif #if defined(__GNUC__) || defined(__clang__) @@ -86,7 +107,8 @@ # define SPDLOG_TRY try # define SPDLOG_THROW(ex) throw(ex) # define SPDLOG_CATCH_STD \ - catch (const std::exception &) {} + catch (const std::exception &) \ + {} #endif namespace spdlog { @@ -111,24 +133,82 @@ using log_clock = std::chrono::system_clock; using sink_ptr = std::shared_ptr; using sinks_init_list = std::initializer_list; using err_handler = std::function; +#ifdef SPDLOG_USE_STD_FORMAT +namespace fmt_lib = std; + +using string_view_t = std::string_view; +using memory_buf_t = std::string; + +template +# if __cpp_lib_format >= 202207L +using format_string_t = std::format_string; +# else +using format_string_t = std::string_view; +# endif + +template +struct is_convertible_to_basic_format_string : std::integral_constant>::value> +{}; + +# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +using wstring_view_t = std::wstring_view; +using wmemory_buf_t = std::wstring; + +template +# if __cpp_lib_format >= 202207L +using wformat_string_t = std::wformat_string; +# else +using wformat_string_t = std::wstring_view; +# endif +# endif +# define SPDLOG_BUF_TO_STRING(x) x +#else // use fmt lib instead of std::format +namespace fmt_lib = fmt; + using string_view_t = fmt::basic_string_view; -using wstring_view_t = fmt::basic_string_view; using memory_buf_t = fmt::basic_memory_buffer; + +template +using format_string_t = fmt::format_string; + +template +using remove_cvref_t = typename std::remove_cv::type>::type; + +template +# if FMT_VERSION >= 90101 +using fmt_runtime_string = fmt::runtime_format_string; +# else +using fmt_runtime_string = fmt::basic_runtime; +# endif + +// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here, +// in addition, fmt::basic_runtime is only convertible to basic_format_string but not basic_string_view +template +struct is_convertible_to_basic_format_string + : std::integral_constant>::value || std::is_same, fmt_runtime_string>::value> +{}; + +# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +using wstring_view_t = fmt::basic_string_view; using wmemory_buf_t = fmt::basic_memory_buffer; +template +using wformat_string_t = fmt::wformat_string; +# endif +# define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x) +#endif + #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT # ifndef _WIN32 # error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows -# else -template -struct is_convertible_to_wstring_view : std::is_convertible -{}; # endif // _WIN32 -#else -template -struct is_convertible_to_wstring_view : std::false_type +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + +template +struct is_convertible_to_any_format_string : std::integral_constant::value || + is_convertible_to_basic_format_string::value> {}; -#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT #if defined(SPDLOG_NO_ATOMIC_LEVELS) using level_t = details::null_atomic_int; @@ -150,7 +230,7 @@ using level_t = std::atomic; // Log level enum namespace level { -enum level_enum +enum level_enum : int { trace = SPDLOG_LEVEL_TRACE, debug = SPDLOG_LEVEL_DEBUG, @@ -162,13 +242,13 @@ enum level_enum n_levels }; -#define SPDLOG_LEVEL_NAME_TRACE string_view_t("trace", 5) -#define SPDLOG_LEVEL_NAME_DEBUG string_view_t("debug", 5) -#define SPDLOG_LEVEL_NAME_INFO string_view_t("info", 4) -#define SPDLOG_LEVEL_NAME_WARNING string_view_t("warning", 7) -#define SPDLOG_LEVEL_NAME_ERROR string_view_t("error", 5) -#define SPDLOG_LEVEL_NAME_CRITICAL string_view_t("critical", 8) -#define SPDLOG_LEVEL_NAME_OFF string_view_t("off", 3) +#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 \ @@ -247,12 +327,70 @@ struct source_loc const char *funcname{nullptr}; }; +struct file_event_handlers +{ + file_event_handlers() + : before_open(nullptr) + , after_open(nullptr) + , before_close(nullptr) + , after_close(nullptr) + {} + + std::function before_open; + std::function after_open; + std::function before_close; + std::function after_close; +}; + namespace details { + +// to_string_view + +SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT +{ + return spdlog::string_view_t{buf.data(), buf.size()}; +} + +SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(spdlog::string_view_t str) SPDLOG_NOEXCEPT +{ + return str; +} + +#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(const wmemory_buf_t &buf) SPDLOG_NOEXCEPT +{ + return spdlog::wstring_view_t{buf.data(), buf.size()}; +} + +SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view_t str) SPDLOG_NOEXCEPT +{ + return str; +} +#endif + +#ifndef SPDLOG_USE_STD_FORMAT +template +inline fmt::basic_string_view to_string_view(fmt::basic_format_string fmt) +{ + return fmt; +} +#elif __cpp_lib_format >= 202207L +template +SPDLOG_CONSTEXPR_FUNC std::basic_string_view to_string_view(std::basic_format_string fmt) SPDLOG_NOEXCEPT +{ + return fmt.get(); +} +#endif + // make_unique support for pre c++14 #if __cplusplus >= 201402L // C++14 and beyond +using std::enable_if_t; using std::make_unique; #else +template +using enable_if_t = typename std::enable_if::type; + template std::unique_ptr make_unique(Args &&...args) { @@ -260,6 +398,20 @@ std::unique_ptr make_unique(Args &&...args) return std::unique_ptr(new T(std::forward(args)...)); } #endif + +// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) +template::value, int> = 0> +constexpr T conditional_static_cast(U value) +{ + return static_cast(value); +} + +template::value, int> = 0> +constexpr T conditional_static_cast(U value) +{ + return value; +} + } // namespace details } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/details/backtracer-inl.h b/Lumos/External/spdlog/include/spdlog/details/backtracer-inl.h index 2621c8f7d..40eba4086 100644 --- a/Lumos/External/spdlog/include/spdlog/details/backtracer-inl.h +++ b/Lumos/External/spdlog/include/spdlog/details/backtracer-inl.h @@ -54,6 +54,12 @@ SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) messages_.push_back(log_msg_buffer{msg}); } +SPDLOG_INLINE bool backtracer::empty() const +{ + std::lock_guard lock{mutex_}; + return messages_.empty(); +} + // pop all items in the q and apply the given fun on each of them. SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) { diff --git a/Lumos/External/spdlog/include/spdlog/details/backtracer.h b/Lumos/External/spdlog/include/spdlog/details/backtracer.h index b336ee776..13785d856 100644 --- a/Lumos/External/spdlog/include/spdlog/details/backtracer.h +++ b/Lumos/External/spdlog/include/spdlog/details/backtracer.h @@ -32,6 +32,7 @@ class SPDLOG_API backtracer void disable(); bool enabled() const; void push_back(const log_msg &msg); + bool empty() const; // pop all items in the q and apply the given fun on each of them. void foreach_pop(std::function fun); diff --git a/Lumos/External/spdlog/include/spdlog/details/circular_q.h b/Lumos/External/spdlog/include/spdlog/details/circular_q.h index 1f2712e7e..e4fd5fd4a 100644 --- a/Lumos/External/spdlog/include/spdlog/details/circular_q.h +++ b/Lumos/External/spdlog/include/spdlog/details/circular_q.h @@ -121,6 +121,11 @@ class circular_q return overrun_counter_; } + void reset_overrun_counter() + { + overrun_counter_ = 0; + } + private: // copy from other&& and reset it to disabled state void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT diff --git a/Lumos/External/spdlog/include/spdlog/details/file_helper-inl.h b/Lumos/External/spdlog/include/spdlog/details/file_helper-inl.h index ac7021a9f..74c89a873 100644 --- a/Lumos/External/spdlog/include/spdlog/details/file_helper-inl.h +++ b/Lumos/External/spdlog/include/spdlog/details/file_helper-inl.h @@ -20,6 +20,10 @@ namespace spdlog { namespace details { +SPDLOG_INLINE file_helper::file_helper(const file_event_handlers &event_handlers) + : event_handlers_(event_handlers) +{} + SPDLOG_INLINE file_helper::~file_helper() { close(); @@ -33,6 +37,10 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) auto *mode = SPDLOG_FILENAME_T("ab"); auto *trunc_mode = SPDLOG_FILENAME_T("wb"); + if (event_handlers_.before_open) + { + event_handlers_.before_open(filename_); + } for (int tries = 0; tries < open_tries_; ++tries) { // create containing folder if not exists already. @@ -52,6 +60,10 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) } if (!os::fopen_s(&fd_, fname, mode)) { + if (event_handlers_.after_open) + { + event_handlers_.after_open(filename_, fd_); + } return; } @@ -72,15 +84,36 @@ SPDLOG_INLINE void file_helper::reopen(bool truncate) SPDLOG_INLINE void file_helper::flush() { - std::fflush(fd_); + if (std::fflush(fd_) != 0) + { + throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE void file_helper::sync() +{ + if (!os::fsync(fd_)) + { + throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno); + } } SPDLOG_INLINE void file_helper::close() { if (fd_ != nullptr) { + if (event_handlers_.before_close) + { + event_handlers_.before_close(filename_, fd_); + } + std::fclose(fd_); fd_ = nullptr; + + if (event_handlers_.after_close) + { + event_handlers_.after_close(filename_); + } } } diff --git a/Lumos/External/spdlog/include/spdlog/details/file_helper.h b/Lumos/External/spdlog/include/spdlog/details/file_helper.h index cfccaed2a..f42a5eb1c 100644 --- a/Lumos/External/spdlog/include/spdlog/details/file_helper.h +++ b/Lumos/External/spdlog/include/spdlog/details/file_helper.h @@ -16,7 +16,8 @@ namespace details { class SPDLOG_API file_helper { public: - explicit file_helper() = default; + file_helper() = default; + explicit file_helper(const file_event_handlers &event_handlers); file_helper(const file_helper &) = delete; file_helper &operator=(const file_helper &) = delete; @@ -25,6 +26,7 @@ class SPDLOG_API file_helper void open(const filename_t &fname, bool truncate = false); void reopen(bool truncate); void flush(); + void sync(); void close(); void write(const memory_buf_t &buf); size_t size() const; @@ -50,6 +52,7 @@ class SPDLOG_API file_helper const unsigned int open_interval_ = 10; std::FILE *fd_{nullptr}; filename_t filename_; + file_event_handlers event_handlers_; }; } // namespace details } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/details/fmt_helper.h b/Lumos/External/spdlog/include/spdlog/details/fmt_helper.h index dcbee10ae..d98671808 100644 --- a/Lumos/External/spdlog/include/spdlog/details/fmt_helper.h +++ b/Lumos/External/spdlog/include/spdlog/details/fmt_helper.h @@ -8,42 +8,89 @@ #include #include +#ifdef SPDLOG_USE_STD_FORMAT +# include +# include +#endif + // 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()); } +#ifdef SPDLOG_USE_STD_FORMAT +template +inline void append_int(T n, memory_buf_t &dest) +{ + // Buffer should be large enough to hold all digits (digits10 + 1) and a sign + SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits::digits10 + 2; + char buf[BUF_SIZE]; + + auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10); + if (ec == std::errc()) + { + dest.append(buf, ptr); + } + else + { + throw_spdlog_ex("Failed to format int", static_cast(ec)); + } +} +#else template inline void append_int(T n, memory_buf_t &dest) { fmt::format_int i(n); dest.append(i.data(), i.data() + i.size()); } +#endif + +template +SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) +{ + // taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912 + unsigned int count = 1; + for (;;) + { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) + return count; + if (n < 100) + return count + 1; + if (n < 1000) + return count + 2; + if (n < 10000) + return count + 3; + n /= 10000u; + count += 4; + } +} template inline unsigned int count_digits(T n) { using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; +#ifdef SPDLOG_USE_STD_FORMAT + return count_digits_fallback(static_cast(n)); +#else return static_cast(fmt:: // fmt 7.0.0 renamed the internal namespace to detail. // See: https://github.com/fmtlib/fmt/issues/1538 -#if FMT_VERSION < 70000 +# if FMT_VERSION < 70000 internal -#else +# else detail -#endif +# endif ::count_digits(static_cast(n))); +#endif } inline void pad2(int n, memory_buf_t &dest) @@ -55,7 +102,7 @@ inline void pad2(int n, memory_buf_t &dest) } else // unlikely, but just in case, let fmt deal with it { - fmt::format_to(std::back_inserter(dest), "{:02}", n); + fmt_lib::format_to(std::back_inserter(dest), SPDLOG_FMT_STRING("{:02}"), n); } } diff --git a/Lumos/External/spdlog/include/spdlog/details/mpmc_blocking_q.h b/Lumos/External/spdlog/include/spdlog/details/mpmc_blocking_q.h index 5c3cca76b..101ea8c05 100644 --- a/Lumos/External/spdlog/include/spdlog/details/mpmc_blocking_q.h +++ b/Lumos/External/spdlog/include/spdlog/details/mpmc_blocking_q.h @@ -49,7 +49,7 @@ class mpmc_blocking_queue push_cv_.notify_one(); } - // try to dequeue item. if no item found. wait upto timeout and try again + // dequeue with a timeout. // Return true, if succeeded dequeue item, false otherwise bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { @@ -66,6 +66,18 @@ class mpmc_blocking_queue return true; } + // blocking dequeue without a timeout. + void dequeue(T &popped_item) + { + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + } + pop_cv_.notify_one(); + } + #else // apparently mingw deadlocks if the mutex is released before cv.notify_one(), // so release the mutex at the very end each function. @@ -87,7 +99,7 @@ class mpmc_blocking_queue push_cv_.notify_one(); } - // try to dequeue item. if no item found. wait upto timeout and try again + // dequeue with a timeout. // Return true, if succeeded dequeue item, false otherwise bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { @@ -102,6 +114,16 @@ class mpmc_blocking_queue return true; } + // blocking dequeue without a timeout. + void dequeue(T &popped_item) + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + pop_cv_.notify_one(); + } + #endif size_t overrun_counter() @@ -116,6 +138,12 @@ class mpmc_blocking_queue return q_.size(); } + void reset_overrun_counter() + { + std::unique_lock lock(queue_mutex_); + q_.reset_overrun_counter(); + } + private: std::mutex queue_mutex_; std::condition_variable push_cv_; diff --git a/Lumos/External/spdlog/include/spdlog/details/null_mutex.h b/Lumos/External/spdlog/include/spdlog/details/null_mutex.h index 83533d4fe..6550a7bf6 100644 --- a/Lumos/External/spdlog/include/spdlog/details/null_mutex.h +++ b/Lumos/External/spdlog/include/spdlog/details/null_mutex.h @@ -13,10 +13,6 @@ struct null_mutex { void lock() const {} void unlock() const {} - bool try_lock() const - { - return true; - } }; struct null_atomic_int diff --git a/Lumos/External/spdlog/include/spdlog/details/os-inl.h b/Lumos/External/spdlog/include/spdlog/details/os-inl.h index 4602782c8..ea8864eae 100644 --- a/Lumos/External/spdlog/include/spdlog/details/os-inl.h +++ b/Lumos/External/spdlog/include/spdlog/details/os-inl.h @@ -23,9 +23,10 @@ #ifdef _WIN32 -# include // _get_osfhandle and _isatty support -# include // _get_pid support +# include // for _get_osfhandle, _isatty, _fileno +# include // for _get_pid # include +# include // for FlushFileBuffers # ifdef __MINGW32__ # include @@ -33,6 +34,7 @@ # if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) # include +# include # endif # include // for _mkdir/_wmkdir @@ -46,7 +48,7 @@ # include //Use gettid() syscall under linux to get thread id # elif defined(_AIX) -# include // for pthread_getthreadid_np +# include // for pthread_getthrds_np # elif defined(__DragonFly__) || defined(__FreeBSD__) # include // for pthread_getthreadid_np @@ -60,6 +62,10 @@ #endif // unix +#if defined __APPLE__ +# include +#endif + #ifndef __has_feature // Clang - feature checking macros. # define __has_feature(x) 0 // Compatibility with non-clang compilers. #endif @@ -145,7 +151,7 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); if (fd == -1) { - return false; + return true; } *fp = ::fdopen(fd, mode.c_str()); if (*fp == nullptr) @@ -230,14 +236,14 @@ SPDLOG_INLINE size_t filesize(FILE *f) # endif #else // unix -// OpenBSD doesn't compile with :: before the fileno(..) -# if defined(__OpenBSD__) +// OpenBSD and AIX doesn't compile with :: before the fileno(..) +# if defined(__OpenBSD__) || defined(_AIX) 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)) +// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated) +# if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) struct stat64 st; if (::fstat64(fd, &st) == 0) { @@ -286,7 +292,8 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) return offset; #else -# if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) +# if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \ + (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris struct helper { @@ -305,7 +312,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) // + difference in years * 365 */ - + (long int)(local_year - gmt_year) * 365); + + static_cast(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); @@ -336,7 +343,14 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT # define SYS_gettid __NR_gettid # endif return static_cast(::syscall(SYS_gettid)); -#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__) +#elif defined(_AIX) + struct __pthrdsinfo buf; + int reg_size = 0; + pthread_t pt = pthread_self(); + int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, ®_size); + int tid = (!retval) ? buf.__pi_tid : 0; + return static_cast(tid); +#elif defined(__DragonFly__) || defined(__FreeBSD__) return static_cast(::pthread_getthreadid_np()); #elif defined(__NetBSD__) return static_cast(::_lwp_self()); @@ -346,7 +360,22 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT return static_cast(::thr_self()); #elif __APPLE__ uint64_t tid; + // There is no pthread_threadid_np prior to 10.6, and it is not supported on any PPC, + // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64. +# if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__) + tid = pthread_mach_thread_np(pthread_self()); +# elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + if (&pthread_threadid_np) + { + pthread_threadid_np(nullptr, &tid); + } + else + { + tid = pthread_mach_thread_np(pthread_self()); + } +# else pthread_threadid_np(nullptr, &tid); +# endif return static_cast(tid); #else // Default to standard C++11 (other Unix) return static_cast(std::hash()(std::this_thread::get_id())); @@ -381,7 +410,7 @@ 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); + return SPDLOG_BUF_TO_STRING(buf); } #else SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) @@ -394,9 +423,9 @@ SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT { #ifdef _WIN32 - return static_cast(::GetCurrentProcessId()); + return conditional_static_cast(::GetCurrentProcessId()); #else - return static_cast(::getpid()); + return conditional_static_cast(::getpid()); #endif } @@ -476,7 +505,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) } } - throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); + throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); } SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) @@ -493,25 +522,21 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) return; } - int result_size = static_cast(target.capacity()); - if (str_size + 1 > result_size) - { - result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); - } + // find the size to allocate for the result buffer + int 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); + assert(result_size == target.size()); return; } } - throw_spdlog_ex(fmt::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); + throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); } #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) @@ -531,7 +556,7 @@ static SPDLOG_INLINE bool mkdir_(const filename_t &path) // 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) +SPDLOG_INLINE bool create_dir(const filename_t &path) { if (path_exists(path)) { @@ -570,7 +595,7 @@ SPDLOG_INLINE bool create_dir(filename_t path) // "abc/" => "abc" // "abc" => "" // "abc///" => "abc//" -SPDLOG_INLINE filename_t dir_name(filename_t path) +SPDLOG_INLINE filename_t dir_name(const filename_t &path) { auto pos = path.find_last_of(folder_seps_filename); return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; @@ -594,6 +619,17 @@ std::string SPDLOG_INLINE getenv(const char *field) #endif } +// Do fsync by FILE handlerpointer +// Return true on success +SPDLOG_INLINE bool fsync(FILE *fp) +{ +#ifdef _WIN32 + return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fp)))) != 0; +#else + return ::fsync(fileno(fp)) == 0; +#endif +} + } // namespace os } // namespace details } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/details/os.h b/Lumos/External/spdlog/include/spdlog/details/os.h index 2b2ffa1d2..37b008745 100644 --- a/Lumos/External/spdlog/include/spdlog/details/os.h +++ b/Lumos/External/spdlog/include/spdlog/details/os.h @@ -99,16 +99,20 @@ SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); // "abc/" => "abc" // "abc" => "" // "abc///" => "abc//" -SPDLOG_API filename_t dir_name(filename_t path); +SPDLOG_API filename_t dir_name(const 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); +SPDLOG_API bool create_dir(const 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); +// Do fsync by FILE objectpointer. +// Return true on success. +SPDLOG_API bool fsync(FILE *fp); + } // namespace os } // namespace details } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/details/periodic_worker-inl.h b/Lumos/External/spdlog/include/spdlog/details/periodic_worker-inl.h index d4abbda31..520a2b339 100644 --- a/Lumos/External/spdlog/include/spdlog/details/periodic_worker-inl.h +++ b/Lumos/External/spdlog/include/spdlog/details/periodic_worker-inl.h @@ -10,27 +10,6 @@ namespace spdlog { namespace details { -SPDLOG_INLINE periodic_worker::periodic_worker(const std::function &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 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() { diff --git a/Lumos/External/spdlog/include/spdlog/details/periodic_worker.h b/Lumos/External/spdlog/include/spdlog/details/periodic_worker.h index a300218d6..d7d69b28c 100644 --- a/Lumos/External/spdlog/include/spdlog/details/periodic_worker.h +++ b/Lumos/External/spdlog/include/spdlog/details/periodic_worker.h @@ -20,7 +20,27 @@ namespace details { class SPDLOG_API periodic_worker { public: - periodic_worker(const std::function &callback_fun, std::chrono::seconds interval); + template + periodic_worker(const std::function &callback_fun, std::chrono::duration interval) + { + active_ = (interval > std::chrono::duration::zero()); + if (!active_) + { + return; + } + + worker_thread_ = std::thread([this, callback_fun, interval]() { + for (;;) + { + std::unique_lock lock(this->mutex_); + if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) + { + return; // active_ == false, so exit this thread + } + callback_fun(); + } + }); + } periodic_worker(const periodic_worker &) = delete; periodic_worker &operator=(const periodic_worker &) = delete; // stop the worker thread and join it diff --git a/Lumos/External/spdlog/include/spdlog/details/registry-inl.h b/Lumos/External/spdlog/include/spdlog/details/registry-inl.h index c55b5eea8..cb1fe84ff 100644 --- a/Lumos/External/spdlog/include/spdlog/details/registry-inl.h +++ b/Lumos/External/spdlog/include/spdlog/details/registry-inl.h @@ -188,13 +188,6 @@ SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) flush_level_ = log_level; } -SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval) -{ - std::lock_guard lock(flusher_mutex_); - auto clbk = [this]() { this->flush_all(); }; - periodic_flusher_ = details::make_unique(clbk, interval); -} - SPDLOG_INLINE void registry::set_error_handler(err_handler handler) { std::lock_guard lock(logger_map_mutex_); @@ -226,8 +219,9 @@ SPDLOG_INLINE void registry::flush_all() SPDLOG_INLINE void registry::drop(const std::string &logger_name) { std::lock_guard lock(logger_map_mutex_); + auto is_default_logger = default_logger_ && default_logger_->name() == logger_name; loggers_.erase(logger_name); - if (default_logger_ && default_logger_->name() == logger_name) + if (is_default_logger) { default_logger_.reset(); } @@ -294,6 +288,14 @@ SPDLOG_INLINE registry ®istry::instance() return s_instance; } +SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr new_logger) +{ + std::lock_guard lock(logger_map_mutex_); + 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); +} + SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) { if (loggers_.find(logger_name) != loggers_.end()) diff --git a/Lumos/External/spdlog/include/spdlog/details/registry.h b/Lumos/External/spdlog/include/spdlog/details/registry.h index 97473ea33..4666fa296 100644 --- a/Lumos/External/spdlog/include/spdlog/details/registry.h +++ b/Lumos/External/spdlog/include/spdlog/details/registry.h @@ -9,6 +9,7 @@ // This class is thread safe #include +#include #include #include @@ -22,7 +23,6 @@ class logger; namespace details { class thread_pool; -class periodic_worker; class SPDLOG_API registry { @@ -61,7 +61,13 @@ class SPDLOG_API registry void flush_on(level::level_enum log_level); - void flush_every(std::chrono::seconds interval); + template + void flush_every(std::chrono::duration interval) + { + std::lock_guard lock(flusher_mutex_); + auto clbk = [this]() { this->flush_all(); }; + periodic_flusher_ = details::make_unique(clbk, interval); + } void set_error_handler(err_handler handler); @@ -85,6 +91,8 @@ class SPDLOG_API registry static registry &instance(); + void apply_logger_env_levels(std::shared_ptr new_logger); + private: registry(); ~registry(); diff --git a/Lumos/External/spdlog/include/spdlog/details/tcp_client-windows.h b/Lumos/External/spdlog/include/spdlog/details/tcp_client-windows.h index 95c0d22e8..968b25702 100644 --- a/Lumos/External/spdlog/include/spdlog/details/tcp_client-windows.h +++ b/Lumos/External/spdlog/include/spdlog/details/tcp_client-windows.h @@ -25,20 +25,6 @@ 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; @@ -52,13 +38,24 @@ class tcp_client 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, + ::FormatMessageA(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)); + throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); } public: + tcp_client() + { + init_winsock_(); + } + + ~tcp_client() + { + close(); + ::WSACleanup(); + } + bool is_connected() const { return socket_ != INVALID_SOCKET; @@ -68,7 +65,6 @@ class tcp_client { ::closesocket(socket_); socket_ = INVALID_SOCKET; - WSACleanup(); } SOCKET fd() const @@ -76,20 +72,9 @@ class tcp_client 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(); @@ -98,7 +83,7 @@ class tcp_client {}; ZeroMemory(&hints, sizeof(hints)); - hints.ai_family = AF_INET; // IPv4 + hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on hints.ai_socktype = SOCK_STREAM; // TCP hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value hints.ai_protocol = 0; diff --git a/Lumos/External/spdlog/include/spdlog/details/tcp_client.h b/Lumos/External/spdlog/include/spdlog/details/tcp_client.h index 706d75994..8b11dfd24 100644 --- a/Lumos/External/spdlog/include/spdlog/details/tcp_client.h +++ b/Lumos/External/spdlog/include/spdlog/details/tcp_client.h @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -57,7 +58,7 @@ class tcp_client struct addrinfo hints {}; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; // IPv4 + hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on hints.ai_socktype = SOCK_STREAM; // TCP hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value hints.ai_protocol = 0; @@ -67,8 +68,7 @@ class tcp_client 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); + throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); } // Try each address until we successfully connect(2). @@ -111,7 +111,7 @@ class tcp_client #endif #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) -# error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available" +# error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available" #endif } diff --git a/Lumos/External/spdlog/include/spdlog/details/thread_pool-inl.h b/Lumos/External/spdlog/include/spdlog/details/thread_pool-inl.h index deee37661..dbd424ff0 100644 --- a/Lumos/External/spdlog/include/spdlog/details/thread_pool-inl.h +++ b/Lumos/External/spdlog/include/spdlog/details/thread_pool-inl.h @@ -13,7 +13,8 @@ namespace spdlog { namespace details { -SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) +SPDLOG_INLINE thread_pool::thread_pool( + size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop) : q_(q_max_items) { if (threads_n == 0 || threads_n > 1000) @@ -23,15 +24,21 @@ SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std } for (size_t i = 0; i < threads_n; i++) { - threads_.emplace_back([this, on_thread_start] { + threads_.emplace_back([this, on_thread_start, on_thread_stop] { on_thread_start(); this->thread_pool::worker_loop_(); + on_thread_stop(); }); } } +SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) + : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) +{} + SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) - : thread_pool(q_max_items, threads_n, [] {}) + : thread_pool( + q_max_items, threads_n, [] {}, [] {}) {} // message all threads to terminate gracefully join them @@ -68,6 +75,11 @@ size_t SPDLOG_INLINE thread_pool::overrun_counter() return q_.overrun_counter(); } +void SPDLOG_INLINE thread_pool::reset_overrun_counter() +{ + q_.reset_overrun_counter(); +} + size_t SPDLOG_INLINE thread_pool::queue_size() { return q_.size(); @@ -96,11 +108,7 @@ void SPDLOG_INLINE thread_pool::worker_loop_() 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; - } + q_.dequeue(incoming_async_msg); switch (incoming_async_msg.msg_type) { diff --git a/Lumos/External/spdlog/include/spdlog/details/thread_pool.h b/Lumos/External/spdlog/include/spdlog/details/thread_pool.h index aa3cef2bc..52c569b80 100644 --- a/Lumos/External/spdlog/include/spdlog/details/thread_pool.h +++ b/Lumos/External/spdlog/include/spdlog/details/thread_pool.h @@ -27,7 +27,6 @@ enum class async_msg_type terminate }; -#include // Async msg to move to/from the queue // Movable only. should never be copied struct async_msg : log_msg_buffer @@ -85,10 +84,11 @@ class SPDLOG_API thread_pool using item_type = async_msg; using q_type = details::mpmc_blocking_queue; + thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start, std::function on_thread_stop); thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); thread_pool(size_t q_max_items, size_t threads_n); - // message all threads to terminate gracefully join them + // message all threads to terminate gracefully and join them ~thread_pool(); thread_pool(const thread_pool &) = delete; @@ -97,6 +97,7 @@ class SPDLOG_API thread_pool 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(); + void reset_overrun_counter(); size_t queue_size(); private: diff --git a/Lumos/External/spdlog/include/spdlog/details/udp_client-windows.h b/Lumos/External/spdlog/include/spdlog/details/udp_client-windows.h new file mode 100644 index 000000000..10894ee6a --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/details/udp_client-windows.h @@ -0,0 +1,113 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Helper RAII over winsock udp client socket. +// Will throw on construction if socket creation failed. + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# pragma comment(lib, "Ws2_32.lib") +# pragma comment(lib, "Mswsock.lib") +# pragma comment(lib, "AdvApi32.lib") +#endif + +namespace spdlog { +namespace details { +class udp_client +{ + static constexpr int TX_BUFFER_SIZE = 1024 * 10; + SOCKET socket_ = INVALID_SOCKET; + sockaddr_in addr_ = {}; + + 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]; + ::FormatMessageA(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_lib::format("udp_sink - {}: {}", msg, buf)); + } + + void cleanup_() + { + if (socket_ != INVALID_SOCKET) + { + ::closesocket(socket_); + } + socket_ = INVALID_SOCKET; + ::WSACleanup(); + } + +public: + udp_client(const std::string &host, uint16_t port) + { + init_winsock_(); + + addr_.sin_family = PF_INET; + addr_.sin_port = htons(port); + addr_.sin_addr.s_addr = INADDR_ANY; + if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) + { + int last_error = ::WSAGetLastError(); + ::WSACleanup(); + throw_winsock_error_("error: Invalid address!", last_error); + } + + socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ == INVALID_SOCKET) + { + int last_error = ::WSAGetLastError(); + ::WSACleanup(); + throw_winsock_error_("error: Create Socket failed", last_error); + } + + int option_value = TX_BUFFER_SIZE; + if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) + { + int last_error = ::WSAGetLastError(); + cleanup_(); + throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); + } + } + + ~udp_client() + { + cleanup_(); + } + + SOCKET fd() const + { + return socket_; + } + + void send(const char *data, size_t n_bytes) + { + socklen_t tolen = sizeof(struct sockaddr); + if (::sendto(socket_, data, static_cast(n_bytes), 0, (struct sockaddr *)&addr_, tolen) == -1) + { + throw_spdlog_ex("sendto(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/details/udp_client.h b/Lumos/External/spdlog/include/spdlog/details/udp_client.h new file mode 100644 index 000000000..e8c2cccf3 --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/details/udp_client.h @@ -0,0 +1,94 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Helper RAII over unix udp client socket. +// Will throw on construction if the socket creation failed. + +#ifdef _WIN32 +# error "include udp_client-windows.h instead" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { + +class udp_client +{ + static constexpr int TX_BUFFER_SIZE = 1024 * 10; + int socket_ = -1; + struct sockaddr_in sockAddr_; + + void cleanup_() + { + if (socket_ != -1) + { + ::close(socket_); + socket_ = -1; + } + } + +public: + udp_client(const std::string &host, uint16_t port) + { + socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ < 0) + { + throw_spdlog_ex("error: Create Socket Failed!"); + } + + int option_value = TX_BUFFER_SIZE; + if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast(&option_value), sizeof(option_value)) < 0) + { + cleanup_(); + throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); + } + + sockAddr_.sin_family = AF_INET; + sockAddr_.sin_port = htons(port); + + if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) + { + cleanup_(); + throw_spdlog_ex("error: Invalid address!"); + } + + ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); + } + + ~udp_client() + { + cleanup_(); + } + + int fd() const + { + return socket_; + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) + { + ssize_t toslen = 0; + socklen_t tolen = sizeof(struct sockaddr); + if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) + { + throw_spdlog_ex("sendto(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bin_to_hex.h b/Lumos/External/spdlog/include/spdlog/fmt/bin_to_hex.h index 45bc8f7d8..3bf003d47 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bin_to_hex.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bin_to_hex.h @@ -6,10 +6,21 @@ #pragma once #include +#include + +#if defined(__has_include) +# if __has_include() +# include +# endif +#endif + +#if __cpp_lib_span >= 202002L +# include +#endif // // Support for logging binary data as hex -// format flags, any combination of the followng: +// format flags, any combination of the following: // {:X} - print in uppercase. // {:s} - don't separate each byte with space. // {:p} - don't print the position on each line start. @@ -38,11 +49,12 @@ class dump_info , size_per_line_(size_per_line) {} - It begin() const + // do not use begin() and end() to avoid collision with fmt/ranges + It get_begin() const { return begin_; } - It end() const + It get_end() const { return end_; } @@ -66,6 +78,20 @@ inline details::dump_info to_hex(const Conta return details::dump_info(std::begin(container), std::end(container), size_per_line); } +#if __cpp_lib_span >= 202002L + +template +inline details::dump_info::iterator> to_hex( + const std::span &container, size_t size_per_line = 32) +{ + using Container = std::span; + static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); + using Iter = typename Container::iterator; + return details::dump_info(std::begin(container), std::end(container), size_per_line); +} + +#endif + // create dump_info from ranges template inline details::dump_info to_hex(const It range_begin, const It range_end, size_t size_per_line = 32) @@ -75,10 +101,16 @@ inline details::dump_info to_hex(const It range_begin, const It range_end, s } // namespace spdlog -namespace fmt { +namespace +#ifdef SPDLOG_USE_STD_FORMAT + std +#else + fmt +#endif +{ template -struct formatter> +struct formatter, char> { const char delimiter = ' '; bool put_newlines = true; @@ -89,7 +121,7 @@ struct formatter> // parse the format string flags template - auto parse(ParseContext &ctx) -> decltype(ctx.begin()) + SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); while (it != ctx.end() && *it != '}') @@ -124,27 +156,27 @@ struct formatter> // format the given bytes range as hex template - auto format(const spdlog::details::dump_info &the_range, FormatContext &ctx) -> decltype(ctx.out()) + auto format(const spdlog::details::dump_info &the_range, FormatContext &ctx) const -> 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 +#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000 auto inserter = ctx.begin(); #else auto inserter = ctx.out(); #endif int size_per_line = static_cast(the_range.size_per_line()); - auto start_of_line = the_range.begin(); - for (auto i = the_range.begin(); i != the_range.end(); i++) + auto start_of_line = the_range.get_begin(); + for (auto i = the_range.get_begin(); i != the_range.get_end(); i++) { auto ch = static_cast(*i); - if (put_newlines && (i == the_range.begin() || i - start_of_line >= size_per_line)) + if (put_newlines && (i == the_range.get_begin() || i - start_of_line >= size_per_line)) { - if (show_ascii && i != the_range.begin()) + if (show_ascii && i != the_range.get_begin()) { *inserter++ = delimiter; *inserter++ = delimiter; @@ -155,7 +187,7 @@ struct formatter> } } - put_newline(inserter, static_cast(i - the_range.begin())); + put_newline(inserter, static_cast(i - the_range.get_begin())); // put first byte without delimiter in front of it *inserter++ = hex_chars[(ch >> 4) & 0x0f]; @@ -164,7 +196,7 @@ struct formatter> continue; } - if (put_delimiters) + if (put_delimiters && i != the_range.get_begin()) { *inserter++ = delimiter; } @@ -174,9 +206,9 @@ struct formatter> } if (show_ascii) // add ascii to last line { - if (the_range.end() - the_range.begin() > size_per_line) + if (the_range.get_end() - the_range.get_begin() > size_per_line) { - auto blank_num = size_per_line - (the_range.end() - start_of_line); + auto blank_num = size_per_line - (the_range.get_end() - start_of_line); while (blank_num-- > 0) { *inserter++ = delimiter; @@ -189,7 +221,7 @@ struct formatter> } *inserter++ = delimiter; *inserter++ = delimiter; - for (auto j = start_of_line; j != the_range.end(); j++) + for (auto j = start_of_line; j != the_range.get_end(); j++) { auto pc = static_cast(*j); *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; @@ -200,7 +232,7 @@ struct formatter> // put newline(and position header) template - void put_newline(It inserter, std::size_t pos) + void put_newline(It inserter, std::size_t pos) const { #ifdef _WIN32 *inserter++ = '\r'; @@ -209,8 +241,8 @@ struct formatter> if (put_positions) { - fmt::format_to(inserter, "{:04X}: ", pos); + spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos); } } }; -} // namespace fmt +} // namespace std diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/args.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/args.h index 562e8ab11..a3966d140 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/args.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/args.h @@ -95,10 +95,10 @@ class dynamic_format_arg_store }; template - using stored_type = conditional_t::value && - !has_formatter::value && - !detail::is_reference_wrapper::value, - std::basic_string, T>; + using stored_type = conditional_t< + std::is_convertible>::value && + !detail::is_reference_wrapper::value, + std::basic_string, T>; // Storage of basic_format_arg must be contiguous. std::vector> data_; @@ -143,6 +143,8 @@ class dynamic_format_arg_store } public: + constexpr dynamic_format_arg_store() = default; + /** \rst Adds an argument into the dynamic store for later passing to a formatting diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/chrono.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/chrono.h index c024fd710..b112f76e9 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/chrono.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/chrono.h @@ -10,14 +10,32 @@ #include #include +#include // std::isfinite +#include // std::memcpy #include +#include #include -#include +#include +#include #include "format.h" FMT_BEGIN_NAMESPACE +// Enable tzset. +#ifndef FMT_USE_TZSET +// UWP doesn't provide _tzset. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# define FMT_USE_TZSET 1 +# else +# define FMT_USE_TZSET 0 +# endif +#endif + // Enable safe chrono durations, unless explicitly disabled. #ifndef FMT_SAFE_DURATION_CAST # define FMT_SAFE_DURATION_CAST 1 @@ -44,7 +62,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { static_assert(T::is_integer, "To must be integral"); // A and B are both signed, or both unsigned. - if (F::digits <= T::digits) { + if (detail::const_check(F::digits <= T::digits)) { // From fits in To without any problem. } else { // From does not always fit in To, resort to a dynamic check. @@ -79,14 +97,15 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { return {}; } // From is positive. Can it always fit in To? - if (F::digits > T::digits && + if (detail::const_check(F::digits > T::digits) && from > static_cast(detail::max_value())) { ec = 1; return {}; } } - if (!F::is_signed && T::is_signed && F::digits >= T::digits && + if (detail::const_check(!F::is_signed && T::is_signed && + F::digits >= T::digits) && from > static_cast(detail::max_value())) { ec = 1; return {}; @@ -184,7 +203,7 @@ To safe_duration_cast(std::chrono::duration from, } const auto min1 = (std::numeric_limits::min)() / Factor::num; - if (count < min1) { + if (!std::is_unsigned::value && count < min1) { ec = 1; return {}; } @@ -243,7 +262,7 @@ To safe_duration_cast(std::chrono::duration from, } // multiply with Factor::num without overflow or underflow - if (Factor::num != 1) { + if (detail::const_check(Factor::num != 1)) { constexpr auto max1 = detail::max_value() / static_cast(Factor::num); if (count > max1) { @@ -260,7 +279,7 @@ To safe_duration_cast(std::chrono::duration from, } // this can't go wrong, right? den>0 is checked earlier. - if (Factor::den != 1) { + if (detail::const_check(Factor::den != 1)) { using common_t = typename std::common_type::type; count /= static_cast(Factor::den); } @@ -288,74 +307,138 @@ inline null<> localtime_s(...) { return null<>(); } inline null<> gmtime_r(...) { return null<>(); } inline null<> gmtime_s(...) { return null<>(); } -inline auto do_write(const std::tm& time, const std::locale& loc, char format, - char modifier) -> std::string { - auto&& os = std::ostringstream(); - os.imbue(loc); - using iterator = std::ostreambuf_iterator; - const auto& facet = std::use_facet>(loc); - auto end = facet.put(os, os, ' ', &time, format, modifier); - if (end.failed()) FMT_THROW(format_error("failed to format time")); - auto str = os.str(); - if (!detail::is_utf8() || loc == std::locale::classic()) return str; - // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and - // gcc-4. -#if FMT_MSC_VER != 0 || \ - (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) - // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 - // and newer. - using code_unit = wchar_t; +inline const std::locale& get_classic_locale() { + static const auto& locale = std::locale::classic(); + return locale; +} + +template struct codecvt_result { + static constexpr const size_t max_size = 32; + CodeUnit buf[max_size]; + CodeUnit* end; +}; +template +constexpr const size_t codecvt_result::max_size; + +template +void write_codecvt(codecvt_result& out, string_view in_buf, + const std::locale& loc) { +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet>(loc); +# pragma clang diagnostic pop #else - using code_unit = char32_t; + auto& f = std::use_facet>(loc); #endif - auto& f = std::use_facet>(loc); auto mb = std::mbstate_t(); const char* from_next = nullptr; - code_unit* to_next = nullptr; - constexpr size_t buf_size = 32; - code_unit buf[buf_size] = {}; - auto result = f.in(mb, str.data(), str.data() + str.size(), from_next, buf, - buf + buf_size, to_next); + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, + std::begin(out.buf), std::end(out.buf), out.end); if (result != std::codecvt_base::ok) FMT_THROW(format_error("failed to format time")); - str.clear(); - for (code_unit* p = buf; p != to_next; ++p) { - uint32_t c = static_cast(*p); - if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { - // surrogate pair - ++p; - if (p == to_next || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { +} + +template +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { + if (detail::is_utf8() && loc != get_classic_locale()) { + // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and + // gcc-4. +#if FMT_MSC_VERSION != 0 || \ + (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) + // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 + // and newer. + using code_unit = wchar_t; +#else + using code_unit = char32_t; +#endif + + using unit_t = codecvt_result; + unit_t unit; + write_codecvt(unit, in, loc); + // In UTF-8 is used one to four one-byte code units. + auto&& buf = basic_memory_buffer(); + for (code_unit* p = unit.buf; p != unit.end; ++p) { + uint32_t c = static_cast(*p); + if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { + // surrogate pair + ++p; + if (p == unit.end || (c & 0xfc00) != 0xd800 || + (*p & 0xfc00) != 0xdc00) { + FMT_THROW(format_error("failed to format time")); + } + c = (c << 10) + static_cast(*p) - 0x35fdc00; + } + if (c < 0x80) { + buf.push_back(static_cast(c)); + } else if (c < 0x800) { + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if (c >= 0x10000 && c <= 0x10ffff) { + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else { FMT_THROW(format_error("failed to format time")); } - c = (c << 10) + static_cast(*p) - 0x35fdc00; - } - if (c < 0x80) { - str.push_back(static_cast(c)); - } else if (c < 0x800) { - str.push_back(static_cast(0xc0 | (c >> 6))); - str.push_back(static_cast(0x80 | (c & 0x3f))); - } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { - str.push_back(static_cast(0xe0 | (c >> 12))); - str.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - str.push_back(static_cast(0x80 | (c & 0x3f))); - } else if (c >= 0x10000 && c <= 0x10ffff) { - str.push_back(static_cast(0xf0 | (c >> 18))); - str.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); - str.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - str.push_back(static_cast(0x80 | (c & 0x3f))); - } else { - FMT_THROW(format_error("failed to format time")); } + return copy_str(buf.data(), buf.data() + buf.size(), out); } - return str; + return copy_str(in.data(), in.data() + in.size(), out); } -template +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + codecvt_result unit; + write_codecvt(unit, sv, loc); + return copy_str(unit.buf, unit.end, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + return write_encoded_tm_str(out, sv, loc); +} + +template +inline void do_write(buffer& buf, const std::tm& time, + const std::locale& loc, char format, char modifier) { + auto&& format_buf = formatbuf>(buf); + auto&& os = std::basic_ostream(&format_buf); + os.imbue(loc); + using iterator = std::ostreambuf_iterator; + const auto& facet = std::use_facet>(loc); + auto end = facet.put(os, os, Char(' '), &time, format, modifier); + if (end.failed()) FMT_THROW(format_error("failed to format time")); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = get_buffer(out); + do_write(buf, time, loc, format, modifier); + return buf.out(); +} + +template ::value)> auto write(OutputIt out, const std::tm& time, const std::locale& loc, char format, char modifier = 0) -> OutputIt { - auto str = do_write(time, loc, format, modifier); - return std::copy(str.begin(), str.end(), out); + auto&& buf = basic_memory_buffer(); + do_write(buf, time, loc, format, modifier); + return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); } + } // namespace detail FMT_MODULE_EXPORT_BEGIN @@ -386,7 +469,7 @@ inline std::tm localtime(std::time_t time) { bool fallback(int res) { return res == 0; } -#if !FMT_MSC_VER +#if !FMT_MSC_VERSION bool fallback(detail::null<>) { using namespace fmt::detail; std::tm* tm = std::localtime(&time_); @@ -432,7 +515,7 @@ inline std::tm gmtime(std::time_t time) { bool fallback(int res) { return res == 0; } -#if !FMT_MSC_VER +#if !FMT_MSC_VERSION bool fallback(detail::null<>) { std::tm* tm = std::gmtime(&time_); if (tm) tm_ = *tm; @@ -453,102 +536,39 @@ inline std::tm gmtime( FMT_BEGIN_DETAIL_NAMESPACE -inline size_t strftime(char* str, size_t count, const char* format, - const std::tm* time) { - // Assign to a pointer to suppress GCCs -Wformat-nonliteral - // First assign the nullptr to suppress -Wsuggest-attribute=format - std::size_t (*strftime)(char*, std::size_t, const char*, const std::tm*) = - nullptr; - strftime = std::strftime; - return strftime(str, count, format, time); -} - -inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format, - const std::tm* time) { - // See above - std::size_t (*wcsftime)(wchar_t*, std::size_t, const wchar_t*, - const std::tm*) = nullptr; - wcsftime = std::wcsftime; - return wcsftime(str, count, format, time); -} - -FMT_END_DETAIL_NAMESPACE - -template -struct formatter, - Char> : formatter { - FMT_CONSTEXPR formatter() { - this->specs = {default_specs, sizeof(default_specs) / sizeof(Char)}; - } - - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto it = ctx.begin(); - if (it != ctx.end() && *it == ':') ++it; - auto end = it; - while (end != ctx.end() && *end != '}') ++end; - if (end != it) this->specs = {it, detail::to_unsigned(end - it)}; - return end; - } - - template - auto format(std::chrono::time_point val, - FormatContext& ctx) -> decltype(ctx.out()) { - std::tm time = localtime(val); - return formatter::format(time, ctx); - } - - static constexpr Char default_specs[] = {'%', 'Y', '-', '%', 'm', '-', - '%', 'd', ' ', '%', 'H', ':', - '%', 'M', ':', '%', 'S'}; -}; - -template -constexpr Char - formatter, - Char>::default_specs[]; - -template struct formatter { - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - auto it = ctx.begin(); - if (it != ctx.end() && *it == ':') ++it; - auto end = it; - while (end != ctx.end() && *end != '}') ++end; - specs = {it, detail::to_unsigned(end - it)}; - return end; - } - - template - auto format(const std::tm& tm, FormatContext& ctx) const - -> decltype(ctx.out()) { - basic_memory_buffer tm_format; - tm_format.append(specs.begin(), specs.end()); - // By appending an extra space we can distinguish an empty result that - // indicates insufficient buffer size from a guaranteed non-empty result - // https://github.com/fmtlib/fmt/issues/2238 - tm_format.push_back(' '); - tm_format.push_back('\0'); - basic_memory_buffer buf; - size_t start = buf.size(); - for (;;) { - size_t size = buf.capacity() - start; - size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm); - if (count != 0) { - buf.resize(start + count); - break; - } - const size_t MIN_GROWTH = 10; - buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - // Remove the extra space. - return std::copy(buf.begin(), buf.end() - 1, ctx.out()); +// Writes two-digit numbers a, b and c separated by sep to buf. +// The method by Pavel Novikov based on +// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +inline void write_digit2_separated(char* buf, unsigned a, unsigned b, + unsigned c, char sep) { + unsigned long long digits = + a | (b << 24) | (static_cast(c) << 48); + // Convert each value to BCD. + // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. + // The difference is + // y - x = a * 6 + // a can be found from x: + // a = floor(x / 10) + // then + // y = x + a * 6 = x + floor(x / 10) * 6 + // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). + digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; + // Put low nibbles to high bytes and high nibbles to low bytes. + digits = ((digits & 0x00f00000f00000f0) >> 4) | + ((digits & 0x000f00000f00000f) << 8); + auto usep = static_cast(sep); + // Add ASCII '0' to each digit byte and insert separators. + digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); + + constexpr const size_t len = 8; + if (const_check(is_big_endian())) { + char tmp[len]; + std::memcpy(tmp, &digits, len); + std::reverse_copy(tmp, tmp + len, buf); + } else { + std::memcpy(buf, &digits, len); } - - basic_string_view specs; -}; - -FMT_BEGIN_DETAIL_NAMESPACE +} template FMT_CONSTEXPR inline const char* get_units() { if (std::is_same::value) return "as"; @@ -610,6 +630,22 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, handler.on_text(tab, tab + 1); break; } + // Year: + case 'Y': + handler.on_year(numeric_system::standard); + break; + case 'y': + handler.on_short_year(numeric_system::standard); + break; + case 'C': + handler.on_century(numeric_system::standard); + break; + case 'G': + handler.on_iso_week_based_year(); + break; + case 'g': + handler.on_iso_week_based_short_year(); + break; // Day of the week: case 'a': handler.on_abbr_weekday(); @@ -625,11 +661,34 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, break; // Month: case 'b': + case 'h': handler.on_abbr_month(); break; case 'B': handler.on_full_month(); break; + case 'm': + handler.on_dec_month(numeric_system::standard); + break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::standard); + break; + case 'j': + handler.on_day_of_year(); + break; + case 'd': + handler.on_day_of_month(numeric_system::standard); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::standard); + break; // Hour, minute, second: case 'H': handler.on_24_hour(numeric_system::standard); @@ -688,6 +747,15 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { + case 'Y': + handler.on_year(numeric_system::alternative); + break; + case 'y': + handler.on_offset_year(); + break; + case 'C': + handler.on_century(numeric_system::alternative); + break; case 'c': handler.on_datetime(numeric_system::alternative); break; @@ -706,6 +774,27 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { + case 'y': + handler.on_short_year(numeric_system::alternative); + break; + case 'm': + handler.on_dec_month(numeric_system::alternative); + break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative); + break; + case 'e': + handler.on_day_of_month_space(numeric_system::alternative); + break; case 'w': handler.on_dec0_weekday(numeric_system::alternative); break; @@ -741,12 +830,25 @@ template struct null_chrono_spec_handler { FMT_CONSTEXPR void unsupported() { static_cast(this)->unsupported(); } + FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_offset_year() { unsupported(); } + FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } FMT_CONSTEXPR void on_full_weekday() { unsupported(); } FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_abbr_month() { unsupported(); } FMT_CONSTEXPR void on_full_month() { unsupported(); } + FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_year() { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } @@ -766,6 +868,509 @@ template struct null_chrono_spec_handler { FMT_CONSTEXPR void on_tz_name() { unsupported(); } }; +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_year(numeric_system) {} + FMT_CONSTEXPR void on_short_year(numeric_system) {} + FMT_CONSTEXPR void on_offset_year() {} + FMT_CONSTEXPR void on_century(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_based_year() {} + FMT_CONSTEXPR void on_iso_week_based_short_year() {} + FMT_CONSTEXPR void on_abbr_weekday() {} + FMT_CONSTEXPR void on_full_weekday() {} + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} + FMT_CONSTEXPR void on_abbr_month() {} + FMT_CONSTEXPR void on_full_month() {} + FMT_CONSTEXPR void on_dec_month(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_day_of_month(numeric_system) {} + FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} + FMT_CONSTEXPR void on_24_hour(numeric_system) {} + FMT_CONSTEXPR void on_12_hour(numeric_system) {} + FMT_CONSTEXPR void on_minute(numeric_system) {} + FMT_CONSTEXPR void on_second(numeric_system) {} + FMT_CONSTEXPR void on_datetime(numeric_system) {} + FMT_CONSTEXPR void on_loc_date(numeric_system) {} + FMT_CONSTEXPR void on_loc_time(numeric_system) {} + FMT_CONSTEXPR void on_us_date() {} + FMT_CONSTEXPR void on_iso_date() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_utc_offset() {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline const char* tm_wday_full_name(int wday) { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +} +inline const char* tm_wday_short_name(int wday) { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +} + +inline const char* tm_mon_full_name(int mon) { + static constexpr const char* full_name_list[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; +} +inline const char* tm_mon_short_name(int mon) { + static constexpr const char* short_name_list[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; +} + +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + +#if FMT_USE_TZSET +inline void tzset_once() { + static bool init = []() -> bool { + _tzset(); + return true; + }(); + ignore_unused(init); +} +#endif + +template class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const std::tm& tm_; + + auto tm_sec() const noexcept -> int { + FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); + return tm_.tm_sec; + } + auto tm_min() const noexcept -> int { + FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); + return tm_.tm_min; + } + auto tm_hour() const noexcept -> int { + FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); + return tm_.tm_hour; + } + auto tm_mday() const noexcept -> int { + FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); + return tm_.tm_mday; + } + auto tm_mon() const noexcept -> int { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); + return tm_.tm_mon; + } + auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } + auto tm_wday() const noexcept -> int { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); + return tm_.tm_wday; + } + auto tm_yday() const noexcept -> int { + FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); + return tm_.tm_yday; + } + + auto tm_hour12() const noexcept -> int { + const auto h = tm_hour(); + const auto z = h < 12 ? h : h - 12; + return z == 0 ? 12 : z; + } + + // POSIX and the C Standard are unclear or inconsistent about what %C and %y + // do if the year is negative or exceeds 9999. Use the convention that %C + // concatenated with %y yields the same output as %Y, and that %Y contains at + // least 4 characters, with more only if necessary. + auto split_year_lower(long long year) const noexcept -> int { + auto l = year % 100; + if (l < 0) l = -l; // l in [0, 99] + return static_cast(l); + } + + // Algorithm: + // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date + auto iso_year_weeks(long long curr_year) const noexcept -> int { + const auto prev_year = curr_year - 1; + const auto curr_p = + (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % + days_per_week; + const auto prev_p = + (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % + days_per_week; + return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); + } + auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { + return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / + days_per_week; + } + auto tm_iso_week_year() const noexcept -> long long { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return year - 1; + if (w > iso_year_weeks(year)) return year + 1; + return year; + } + auto tm_iso_week_of_year() const noexcept -> int { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return iso_year_weeks(year - 1); + if (w > iso_year_weeks(year)) return 1; + return w; + } + + void write1(int value) { + *out_++ = static_cast('0' + to_unsigned(value) % 10); + } + void write2(int value) { + const char* d = digits2(to_unsigned(value) % 100); + *out_++ = *d++; + *out_++ = *d; + } + + void write_year_extended(long long year) { + // At least 4 characters. + int width = 4; + if (year < 0) { + *out_++ = '-'; + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (width > num_digits) out_ = std::fill_n(out_, width - num_digits, '0'); + out_ = format_decimal(out_, n, num_digits).end; + } + void write_year(long long year) { + if (year >= 0 && year < 10000) { + write2(static_cast(year / 100)); + write2(static_cast(year % 100)); + } else { + write_year_extended(year); + } + } + + void write_utc_offset(long offset) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + write2(static_cast(offset % 60)); + } + template ::value)> + void format_utc_offset_impl(const T& tm) { + write_utc_offset(tm.tm_gmtoff); + } + template ::value)> + void format_utc_offset_impl(const T& tm) { +#if defined(_WIN32) && defined(_UCRT) +# if FMT_USE_TZSET + tzset_once(); +# endif + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset); +#else + ignore_unused(tm); + format_localized('z'); +#endif + } + + template ::value)> + void format_tz_name_impl(const T& tm) { + if (is_classic_) + out_ = write_tm_str(out_, tm.tm_zone, loc_); + else + format_localized('Z'); + } + template ::value)> + void format_tz_name_impl(const T&) { + format_localized('Z'); + } + + void format_localized(char format, char modifier = 0) { + out_ = write(out_, tm_, loc_, format, modifier); + } + + public: + tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + tm_(tm) {} + + OutputIt out() const { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy_str(begin, end, out_); + } + + void on_abbr_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_short_name(tm_wday())); + else + format_localized('a'); + } + void on_full_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_full_name(tm_wday())); + else + format_localized('A'); + } + void on_dec0_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); + format_localized('w', 'O'); + } + void on_dec1_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write1(wday == 0 ? days_per_week : wday); + } else { + format_localized('u', 'O'); + } + } + + void on_abbr_month() { + if (is_classic_) + out_ = write(out_, tm_mon_short_name(tm_mon())); + else + format_localized('b'); + } + void on_full_month() { + if (is_classic_) + out_ = write(out_, tm_mon_full_name(tm_mon())); + else + format_localized('B'); + } + + void on_datetime(numeric_system ns) { + if (is_classic_) { + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month_space(numeric_system::standard); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); + } else { + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + } + } + void on_loc_date(numeric_system ns) { + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_loc_time(numeric_system ns) { + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_us_date() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_mon() + 1), + to_unsigned(tm_mday()), + to_unsigned(split_year_lower(tm_year())), '/'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + void on_iso_date() { + auto year = tm_year(); + char buf[10]; + size_t offset = 0; + if (year >= 0 && year < 10000) { + copy2(buf, digits2(static_cast(year / 100))); + } else { + offset = 4; + write_year_extended(year); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset() { format_utc_offset_impl(tm_); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year()); + format_localized('Y', 'E'); + } + void on_short_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(split_year_lower(tm_year())); + format_localized('y', 'O'); + } + void on_offset_year() { + if (is_classic_) return write2(split_year_lower(tm_year())); + format_localized('y', 'E'); + } + + void on_century(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto year = tm_year(); + auto upper = year / 100; + if (year >= -99 && year < 0) { + // Zero upper on negative year. + *out_++ = '-'; + *out_++ = '0'; + } else if (upper >= 0 && upper < 100) { + write2(static_cast(upper)); + } else { + out_ = write(out_, upper); + } + } else { + format_localized('C', 'E'); + } + } + + void on_dec_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write2((tm_yday() + days_per_week - + (wday == 0 ? (days_per_week - 1) : (wday - 1))) / + days_per_week); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year()); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { write_year(tm_iso_week_year()); } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year() { + auto yday = tm_yday() + 1; + write1(yday / 100); + write2(yday % 100); + } + void on_day_of_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); + format_localized('d', 'O'); + } + void on_day_of_month_space(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto mday = to_unsigned(tm_mday()) % 100; + const char* d2 = digits2(mday); + *out_++ = mday < 10 ? ' ' : d2[0]; + *out_++ = d2[1]; + } else { + format_localized('e', 'O'); + } + } + + void on_24_hour(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_hour()); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12()); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_min()); + format_localized('M', 'O'); + } + void on_second(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write2(tm_sec()); + format_localized('S', 'O'); + } + + void on_12_hour_time() { + if (is_classic_) { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); + } else { + format_localized('r'); + } + } + void on_24_hour_time() { + write2(tm_hour()); + *out_++ = ':'; + write2(tm_min()); + } + void on_iso_time() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour()), to_unsigned(tm_min()), + to_unsigned(tm_sec()), ':'); + out_ = copy_str(std::begin(buf), std::end(buf), out_); + } + + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_hour() < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else { + format_localized('p'); + } + } + + // These apply to chrono durations but not tm. + void on_duration_value() {} + void on_duration_unit() {} +}; + struct chrono_format_checker : null_chrono_spec_handler { FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } @@ -783,39 +1388,25 @@ struct chrono_format_checker : null_chrono_spec_handler { FMT_CONSTEXPR void on_duration_unit() {} }; -template ::value)> -inline bool isnan(T) { - return false; -} -template ::value)> -inline bool isnan(T value) { - return std::isnan(value); -} - template ::value)> inline bool isfinite(T) { return true; } -template ::value)> -inline bool isfinite(T value) { - return std::isfinite(value); -} -// Converts value to int and checks that it's in the range [0, upper). -template ::value)> -inline int to_nonnegative_int(T value, int upper) { - FMT_ASSERT(value >= 0 && to_unsigned(value) <= to_unsigned(upper), +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline Int to_nonnegative_int(T value, Int upper) { + FMT_ASSERT(std::is_unsigned::value || + (value >= 0 && to_unsigned(value) <= to_unsigned(upper)), "invalid value"); (void)upper; - return static_cast(value); + return static_cast(value); } -template ::value)> -inline int to_nonnegative_int(T value, int upper) { - FMT_ASSERT( - std::isnan(value) || (value >= 0 && value <= static_cast(upper)), - "invalid value"); - (void)upper; - return static_cast(value); +template ::value)> +inline Int to_nonnegative_int(T value, Int upper) { + if (value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return static_cast(value); } template ::value)> @@ -872,15 +1463,45 @@ inline std::chrono::duration get_milliseconds( #endif } -template ::value)> -inline std::chrono::duration get_milliseconds( +// Counts the number of fractional digits in the range [0, 18] according to the +// C++20 spec. If more than 18 fractional digits are required then returns 6 for +// microseconds precision. +template () / 10)> +struct count_fractional_digits { + static constexpr int value = + Num % Den == 0 ? N : count_fractional_digits::value; +}; + +// Base case that doesn't instantiate any more templates +// in order to avoid overflow. +template +struct count_fractional_digits { + static constexpr int value = (Num % Den == 0) ? N : 6; +}; + +constexpr long long pow10(std::uint32_t n) { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +template ::is_signed)> +constexpr std::chrono::duration abs( std::chrono::duration d) { - using common_type = typename std::common_type::type; - auto ms = mod(d.count() * static_cast(Period::num) / - static_cast(Period::den) * 1000, - 1000); - return std::chrono::duration(static_cast(ms)); + // We need to compare the duration using the count() method directly + // due to a compiler bug in clang-11 regarding the spaceship operator, + // when -Wzero-as-null-pointer-constant is enabled. + // In clang-12 the bug has been fixed. See + // https://bugs.llvm.org/show_bug.cgi?id=46235 and the reproducible example: + // https://www.godbolt.org/z/Knbb5joYx. + return d.count() >= d.zero().count() ? d : -d; +} + +template ::is_signed)> +constexpr std::chrono::duration abs( + std::chrono::duration d) { + return d; } template (); specs.precision = precision; - specs.type = precision > 0 ? 'f' : 'g'; + specs.type = precision >= 0 ? presentation_type::fixed_lower + : presentation_type::general_lower; return write(out, val, specs); } @@ -926,6 +1548,26 @@ OutputIt format_duration_unit(OutputIt out) { return out; } +class get_locale { + private: + union { + std::locale locale_; + }; + bool has_locale_ = false; + + public: + get_locale(bool localized, locale_ref loc) : has_locale_(localized) { + if (localized) + ::new (&locale_) std::locale(loc.template get()); + } + ~get_locale() { + if (has_locale_) locale_.~locale(); + } + operator const std::locale&() const { + return has_locale_ ? locale_ : get_classic_locale(); + } +}; + template struct chrono_formatter { @@ -944,9 +1586,10 @@ struct chrono_formatter { bool negative; using char_type = typename FormatContext::char_type; + using tm_writer_type = tm_writer; - explicit chrono_formatter(FormatContext& ctx, OutputIt o, - std::chrono::duration d) + chrono_formatter(FormatContext& ctx, OutputIt o, + std::chrono::duration d) : context(ctx), out(o), val(static_cast(d.count())), @@ -1021,15 +1664,47 @@ struct chrono_formatter { out = format_decimal(out, n, num_digits).end; } + template void write_fractional_seconds(Duration d) { + FMT_ASSERT(!std::is_floating_point::value, ""); + constexpr auto num_fractional_digits = + count_fractional_digits::value; + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, detail::pow10(num_fractional_digits)>>; + if (std::ratio_less::value) { + *out++ = '.'; + auto fractional = + detail::abs(d) - std::chrono::duration_cast(d); + auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : std::chrono::duration_cast(fractional) + .count(); + uint32_or_64_or_128_t n = + to_unsigned(to_nonnegative_int(subseconds, max_value())); + int num_digits = detail::count_digits(n); + if (num_fractional_digits > num_digits) + out = std::fill_n(out, num_fractional_digits - num_digits, '0'); + out = format_decimal(out, n, num_digits).end; + } + } + void write_nan() { std::copy_n("nan", 3, out); } void write_pinf() { std::copy_n("inf", 3, out); } void write_ninf() { std::copy_n("-inf", 4, out); } - void format_localized(const tm& time, char format, char modifier = 0) { + template + void format_tm(const tm& time, Callback cb, Args... args) { if (isnan(val)) return write_nan(); - const auto& loc = localized ? context.locale().template get() - : std::locale::classic(); - out = detail::write(out, time, loc, format, modifier); + get_locale loc(localized, context.locale()); + auto w = tm_writer_type(loc, out, time); + (w.*cb)(args...); + out = w.out(); } void on_text(const char_type* begin, const char_type* end) { @@ -1050,6 +1725,19 @@ struct chrono_formatter { void on_iso_date() {} void on_utc_offset() {} void on_tz_name() {} + void on_year(numeric_system) {} + void on_short_year(numeric_system) {} + void on_offset_year() {} + void on_century(numeric_system) {} + void on_iso_week_based_year() {} + void on_iso_week_based_short_year() {} + void on_dec_month(numeric_system) {} + void on_dec0_week_of_year(numeric_system) {} + void on_dec1_week_of_year(numeric_system) {} + void on_iso_week_of_year(numeric_system) {} + void on_day_of_year() {} + void on_day_of_month(numeric_system) {} + void on_day_of_month_space(numeric_system) {} void on_24_hour(numeric_system ns) { if (handle_nan_inf()) return; @@ -1057,7 +1745,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour(), 24); - format_localized(time, 'H', 'O'); + format_tm(time, &tm_writer_type::on_24_hour, ns); } void on_12_hour(numeric_system ns) { @@ -1066,7 +1754,7 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(hour12(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour12(), 12); - format_localized(time, 'I', 'O'); + format_tm(time, &tm_writer_type::on_12_hour, ns); } void on_minute(numeric_system ns) { @@ -1075,37 +1763,39 @@ struct chrono_formatter { if (ns == numeric_system::standard) return write(minute(), 2); auto time = tm(); time.tm_min = to_nonnegative_int(minute(), 60); - format_localized(time, 'M', 'O'); + format_tm(time, &tm_writer_type::on_minute, ns); } void on_second(numeric_system ns) { if (handle_nan_inf()) return; if (ns == numeric_system::standard) { - write(second(), 2); -#if FMT_SAFE_DURATION_CAST - // convert rep->Rep - using duration_rep = std::chrono::duration; - using duration_Rep = std::chrono::duration; - auto tmpval = fmt_safe_duration_cast(duration_rep{val}); -#else - auto tmpval = std::chrono::duration(val); -#endif - auto ms = get_milliseconds(tmpval); - if (ms != std::chrono::milliseconds(0)) { - *out++ = '.'; - write(ms.count(), 3); + if (std::is_floating_point::value) { + constexpr auto num_fractional_digits = + count_fractional_digits::value; + auto buf = memory_buffer(); + format_to(std::back_inserter(buf), runtime("{:.{}f}"), + std::fmod(val * static_cast(Period::num) / + static_cast(Period::den), + static_cast(60)), + num_fractional_digits); + if (negative) *out++ = '-'; + if (buf.size() < 2 || buf[1] == '.') *out++ = '0'; + out = std::copy(buf.begin(), buf.end(), out); + } else { + write(second(), 2); + write_fractional_seconds(std::chrono::duration(val)); } return; } auto time = tm(); time.tm_sec = to_nonnegative_int(second(), 60); - format_localized(time, 'S', 'O'); + format_tm(time, &tm_writer_type::on_second, ns); } void on_12_hour_time() { if (handle_nan_inf()) return; - format_localized(time(), 'r'); + format_tm(time(), &tm_writer_type::on_12_hour_time); } void on_24_hour_time() { @@ -1124,12 +1814,12 @@ struct chrono_formatter { on_24_hour_time(); *out++ = ':'; if (handle_nan_inf()) return; - write(second(), 2); + on_second(numeric_system::standard); } void on_am_pm() { if (handle_nan_inf()) return; - format_localized(time(), 'p'); + format_tm(time(), &tm_writer_type::on_am_pm); } void on_duration_value() { @@ -1159,15 +1849,18 @@ class weekday { : value(static_cast(wd != 7 ? wd : 0)) {} constexpr unsigned c_encoding() const noexcept { return value; } }; + +class year_month_day {}; #endif // A rudimentary weekday formatter. -template <> struct formatter { +template struct formatter { private: bool localized = false; public: - FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { auto begin = ctx.begin(), end = ctx.end(); if (begin != end && *begin == 'L') { ++begin; @@ -1176,12 +1869,14 @@ template <> struct formatter { return begin; } - auto format(weekday wd, format_context& ctx) -> decltype(ctx.out()) { + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { auto time = std::tm(); time.tm_wday = static_cast(wd.c_encoding()); - const auto& loc = localized ? ctx.locale().template get() - : std::locale::classic(); - return detail::write(ctx.out(), time, loc, 'a'); + detail::get_locale loc(localized, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_weekday(); + return w.out(); } }; @@ -1260,7 +1955,8 @@ struct formatter, Char> { ++begin; localized = true; } - end = parse_chrono_format(begin, end, detail::chrono_format_checker()); + end = detail::parse_chrono_format(begin, end, + detail::chrono_format_checker()); return {begin, end}; } @@ -1302,6 +1998,71 @@ struct formatter, Char> { } }; +template +struct formatter, + Char> : formatter { + FMT_CONSTEXPR formatter() { + basic_string_view default_specs = + detail::string_literal{}; + this->do_parse(default_specs.begin(), default_specs.end()); + } + + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + return formatter::format(localtime(val), ctx); + } +}; + +template struct formatter { + private: + enum class spec { + unknown, + year_month_day, + hh_mm_ss, + }; + spec spec_ = spec::unknown; + basic_string_view specs; + + protected: + template FMT_CONSTEXPR auto do_parse(It begin, It end) -> It { + if (begin != end && *begin == ':') ++begin; + end = detail::parse_chrono_format(begin, end, detail::tm_format_checker()); + // Replace default spec only if the new spec is not empty. + if (end != begin) specs = {begin, detail::to_unsigned(end - begin)}; + return end; + } + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto end = this->do_parse(ctx.begin(), ctx.end()); + // basic_string_view<>::compare isn't constexpr before C++17. + if (specs.size() == 2 && specs[0] == Char('%')) { + if (specs[1] == Char('F')) + spec_ = spec::year_month_day; + else if (specs[1] == Char('T')) + spec_ = spec::hh_mm_ss; + } + return end; + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = detail::tm_writer(loc, ctx.out(), tm); + if (spec_ == spec::year_month_day) + w.on_iso_date(); + else if (spec_ == spec::hh_mm_ss) + w.on_iso_time(); + else + detail::parse_chrono_format(specs.begin(), specs.end(), w); + return w.out(); + } +}; + FMT_MODULE_EXPORT_END FMT_END_NAMESPACE diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/color.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/color.h index 3d5490e87..4c163277e 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/color.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/color.h @@ -10,13 +10,6 @@ #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 @@ -185,9 +178,13 @@ enum class terminal_color : uint8_t { enum class emphasis : uint8_t { bold = 1, - italic = 1 << 1, - underline = 1 << 2, - strikethrough = 1 << 3 + faint = 1 << 1, + italic = 1 << 2, + underline = 1 << 3, + blink = 1 << 4, + reverse = 1 << 5, + conceal = 1 << 6, + strikethrough = 1 << 7, }; // rgb is a struct for red, green and blue colors. @@ -210,17 +207,16 @@ 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{} { + FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { value.rgb_color = static_cast(rgb_color); } - FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { + FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { value.rgb_color = (static_cast(rgb_color.r) << 16) | (static_cast(rgb_color.g) << 8) | rgb_color.b; } - FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), - value{} { + FMT_CONSTEXPR color_type(terminal_color term_color) noexcept + : is_rgb(), value{} { value.term_color = static_cast(term_color); } bool is_rgb; @@ -235,10 +231,8 @@ 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(emphasis em = emphasis()) noexcept + : set_foreground_color(), set_background_color(), ems(em) {} FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { if (!set_foreground_color) { @@ -269,44 +263,32 @@ class text_style { 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 { + FMT_CONSTEXPR bool has_foreground() const noexcept { return set_foreground_color; } - FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { + FMT_CONSTEXPR bool has_background() const noexcept { return set_background_color; } - FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { + FMT_CONSTEXPR bool has_emphasis() const noexcept { return static_cast(ems) != 0; } - FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT { + FMT_CONSTEXPR detail::color_type get_foreground() const 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_CONSTEXPR detail::color_type get_background() const noexcept { FMT_ASSERT(has_background(), "no background specified for this style"); return background_color; } - FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { + FMT_CONSTEXPR emphasis get_emphasis() const 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() { + detail::color_type text_color) noexcept + : set_foreground_color(), set_background_color(), ems() { if (is_foreground) { foreground_color = text_color; set_foreground_color = true; @@ -316,36 +298,9 @@ class text_style { } } - // 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(static_cast(ems) & - static_cast(rhs.ems)); - return *this; - } - - friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground) - FMT_NOEXCEPT; + friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept; - friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background) - FMT_NOEXCEPT; + friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept; detail::color_type foreground_color; detail::color_type background_color; @@ -355,17 +310,16 @@ class text_style { }; /** Creates a text style from the foreground (text) color. */ -FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT { +FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) 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 { +FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept { return text_style(false, background); } -FMT_CONSTEXPR inline text_style operator|(emphasis lhs, - emphasis rhs) FMT_NOEXCEPT { +FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept { return text_style(lhs) | rhs; } @@ -373,7 +327,7 @@ FMT_BEGIN_DETAIL_NAMESPACE template struct ansi_color_escape { FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, - const char* esc) FMT_NOEXCEPT { + const char* esc) noexcept { // If we have a terminal color, we need to output another escape code // sequence. if (!text_color.is_rgb) { @@ -408,17 +362,19 @@ template struct ansi_color_escape { to_esc(color.b, buffer + 15, 'm'); buffer[19] = static_cast(0); } - FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { - uint8_t em_codes[4] = {}; - uint8_t em_bits = static_cast(em); - if (em_bits & static_cast(emphasis::bold)) em_codes[0] = 1; - if (em_bits & static_cast(emphasis::italic)) em_codes[1] = 3; - if (em_bits & static_cast(emphasis::underline)) em_codes[2] = 4; - if (em_bits & static_cast(emphasis::strikethrough)) - em_codes[3] = 9; + FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { + uint8_t em_codes[num_emphases] = {}; + if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; + if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; + if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; + if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; + if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; + if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; + if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; + if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; size_t index = 0; - for (int i = 0; i < 4; ++i) { + for (size_t i = 0; i < num_emphases; ++i) { if (!em_codes[i]) continue; buffer[index++] = static_cast('\x1b'); buffer[index++] = static_cast('['); @@ -427,66 +383,76 @@ template struct ansi_color_escape { } buffer[index++] = static_cast(0); } - FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } + FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } - FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } - FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT { + FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; } + FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept { return buffer + std::char_traits::length(buffer); } private: - Char buffer[7u + 3u * 4u + 1u]; + static constexpr size_t num_emphases = 8; + Char buffer[7u + 3u * num_emphases + 1u]; static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, - char delimiter) FMT_NOEXCEPT { + char delimiter) noexcept { out[0] = static_cast('0' + c / 100); out[1] = static_cast('0' + c / 10 % 10); out[2] = static_cast('0' + c % 10); out[3] = static_cast(delimiter); } + static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept { + return static_cast(em) & static_cast(mask); + } }; template FMT_CONSTEXPR ansi_color_escape make_foreground_color( - detail::color_type foreground) FMT_NOEXCEPT { + detail::color_type foreground) noexcept { return ansi_color_escape(foreground, "\x1b[38;2;"); } template FMT_CONSTEXPR ansi_color_escape make_background_color( - detail::color_type background) FMT_NOEXCEPT { + detail::color_type background) noexcept { return ansi_color_escape(background, "\x1b[48;2;"); } template -FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) FMT_NOEXCEPT { +FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) noexcept { return ansi_color_escape(em); } -template -inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { - std::fputs(chars, stream); +template inline void fputs(const Char* chars, FILE* stream) { + int result = std::fputs(chars, stream); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); } -template <> -inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { - std::fputws(chars, stream); +template <> inline void fputs(const wchar_t* chars, FILE* stream) { + int result = std::fputws(chars, stream); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); } -template inline void reset_color(FILE* stream) FMT_NOEXCEPT { +template inline void reset_color(FILE* stream) { fputs("\x1b[0m", stream); } -template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT { +template <> inline void reset_color(FILE* stream) { fputs(L"\x1b[0m", stream); } -template -inline void reset_color(buffer& buffer) FMT_NOEXCEPT { +template inline void reset_color(buffer& buffer) { auto reset_color = string_view("\x1b[0m"); buffer.append(reset_color.begin(), reset_color.end()); } +template struct styled_arg { + const T& value; + text_style style; +}; + template void vformat_to(buffer& buf, const text_style& ts, basic_string_view format_str, @@ -517,9 +483,13 @@ template > void vprint(std::FILE* f, const text_style& ts, const S& format, basic_format_args>> args) { basic_memory_buffer buf; - detail::vformat_to(buf, ts, to_string_view(format), args); - buf.push_back(Char(0)); - detail::fputs(buf.data(), f); + detail::vformat_to(buf, ts, detail::to_string_view(format), args); + if (detail::is_utf8()) { + detail::print(f, basic_string_view(buf.begin(), buf.size())); + } else { + buf.push_back(Char(0)); + detail::fputs(buf.data(), f); + } } /** @@ -538,7 +508,7 @@ template (format_str, args...)); + fmt::make_format_args>>(args...)); } /** @@ -563,7 +533,7 @@ inline std::basic_string vformat( const text_style& ts, const S& format_str, basic_format_args>> args) { basic_memory_buffer buf; - detail::vformat_to(buf, ts, to_string_view(format_str), args); + detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); return fmt::to_string(buf); } @@ -582,8 +552,8 @@ inline std::basic_string vformat( template > inline std::basic_string 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(format_str, args...)); + return fmt::vformat(ts, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); } /** @@ -617,8 +587,62 @@ template typename std::enable_if::type { - return vformat_to(out, ts, to_string_view(format_str), - fmt::make_args_checked(format_str, args...)); + return vformat_to(out, ts, detail::to_string_view(format_str), + fmt::make_format_args>>(args...)); +} + +template +struct formatter, Char> : formatter { + template + auto format(const detail::styled_arg& arg, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto& ts = arg.style; + const auto& value = arg.value; + auto out = ctx.out(); + + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + out = std::copy(emphasis.begin(), emphasis.end(), out); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = + detail::make_foreground_color(ts.get_foreground()); + out = std::copy(foreground.begin(), foreground.end(), out); + } + if (ts.has_background()) { + has_style = true; + auto background = + detail::make_background_color(ts.get_background()); + out = std::copy(background.begin(), background.end(), out); + } + out = formatter::format(value, ctx); + if (has_style) { + auto reset_color = string_view("\x1b[0m"); + out = std::copy(reset_color.begin(), reset_color.end(), out); + } + return out; + } +}; + +/** + \rst + Returns an argument that will be formatted using ANSI escape sequences, + to be used in a formatting function. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", + fmt::styled(1.23, fmt::fg(fmt::color::green) | + fmt::bg(fmt::color::blue))); + \endrst + */ +template +FMT_CONSTEXPR auto styled(const T& value, text_style ts) + -> detail::styled_arg> { + return detail::styled_arg>{value, ts}; } FMT_MODULE_EXPORT_END diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/compile.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/compile.h index 00000c92e..933668c41 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/compile.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/compile.h @@ -13,48 +13,9 @@ 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 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(n); - return it; - } - - value_type operator*() const { return {}; } -}; - template -inline counting_iterator copy_str(InputIt begin, InputIt end, - counting_iterator it) { +FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, + counting_iterator it) { return it + (end - begin); } @@ -75,8 +36,7 @@ template class truncating_iterator_base { using difference_type = std::ptrdiff_t; using pointer = void; using reference = void; - using _Unchecked_type = - truncating_iterator_base; // Mark iterator as checked. + FMT_UNCHECKED_ITERATOR(truncating_iterator_base); OutputIt base() const { return out_; } size_t count() const { return count_; } @@ -156,19 +116,19 @@ struct is_compiled_string : std::is_base_of {}; std::string s = fmt::format(FMT_COMPILE("{}"), 42); \endrst */ -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) # 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 +#if FMT_USE_NONTYPE_TEMPLATE_ARGS template Str> struct udl_compiled_string : compiled_string { using char_type = Char; - constexpr operator basic_string_view() const { + explicit constexpr operator basic_string_view() const { return {Str.data, N - 1}; } }; @@ -179,7 +139,7 @@ const T& first(const T& value, const Tail&...) { return value; } -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template struct type_list {}; // Returns a reference to the argument at index N from [first, rest...]. @@ -190,7 +150,7 @@ constexpr const auto& get([[maybe_unused]] const T& first, if constexpr (N == 0) return first; else - return get(rest...); + return detail::get(rest...); } template @@ -202,7 +162,8 @@ constexpr int get_arg_index_by_name(basic_string_view name, template struct get_type_impl; template struct get_type_impl> { - using type = remove_cvref_t(std::declval()...))>; + using type = + remove_cvref_t(std::declval()...))>; }; template @@ -242,7 +203,7 @@ template struct code_unit { // This ensures that the argument type is convertible to `const T&`. template constexpr const T& get_arg_checked(const Args&... args) { - const auto& arg = get(args...); + const auto& arg = detail::get(args...); if constexpr (detail::is_named_arg>()) { return arg.value; } else { @@ -289,7 +250,7 @@ template struct runtime_named_field { 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"); + FMT_THROW(format_error("argument with specified name is not found")); } return out; } @@ -376,10 +337,11 @@ template constexpr parse_specs_result parse_specs(basic_string_view str, size_t pos, int next_arg_id) { str.remove_prefix(pos); - auto ctx = basic_format_parse_context(str, {}, next_arg_id); + auto ctx = compile_parse_context(str, max_value(), nullptr, {}, + next_arg_id); auto f = formatter(); auto end = f.parse(ctx); - return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1, + return {f, pos + fmt::detail::to_unsigned(end - str.data()), next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; } @@ -399,7 +361,9 @@ template struct arg_id_handler { return 0; } - constexpr void on_error(const char* message) { throw format_error(message); } + constexpr void on_error(const char* message) { + FMT_THROW(format_error(message)); + } }; template struct parse_arg_id_result { @@ -433,13 +397,20 @@ constexpr auto parse_replacement_field_then_tail(S format_str) { return parse_tail( field::type, ARG_INDEX>(), format_str); - } else if constexpr (c == ':') { + } else if constexpr (c != ':') { + FMT_THROW(format_error("expected ':'")); + } else { constexpr auto result = parse_specs::type>( str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); - return parse_tail( - spec_field::type, ARG_INDEX>{ - result.fmt}, - format_str); + if constexpr (result.end >= str.size() || str[result.end] != '}') { + FMT_THROW(format_error("expected '}'")); + return 0; + } else { + return parse_tail( + spec_field::type, ARG_INDEX>{ + result.fmt}, + format_str); + } } } @@ -451,7 +422,7 @@ constexpr auto compile_format_string(S format_str) { constexpr auto str = basic_string_view(format_str); if constexpr (str[POS] == '{') { if constexpr (POS + 1 == str.size()) - throw format_error("unmatched '{' in format string"); + FMT_THROW(format_error("unmatched '{' in format string")); if constexpr (str[POS + 1] == '{') { return parse_tail(make_text(str, POS, 1), format_str); } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { @@ -500,7 +471,7 @@ constexpr auto compile_format_string(S format_str) { } } else if constexpr (str[POS] == '}') { if constexpr (POS + 1 == str.size()) - throw format_error("unmatched '}' in format string"); + FMT_THROW(format_error("unmatched '}' in format string")); return parse_tail(make_text(str, POS, 1), format_str); } else { constexpr auto end = parse_text(str, POS + 1); @@ -527,12 +498,12 @@ constexpr auto compile(S format_str) { return result; } } -#endif // __cpp_if_constexpr +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) } // namespace detail FMT_MODULE_EXPORT_BEGIN -#ifdef __cpp_if_constexpr +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template format(const S&, constexpr auto compiled = detail::compile(S()); if constexpr (std::is_same, detail::unknown_format>()) { - return format(static_cast>(S()), - std::forward(args)...); + return fmt::format( + static_cast>(S()), + std::forward(args)...); } else { - return format(compiled, std::forward(args)...); + return fmt::format(compiled, std::forward(args)...); } } @@ -583,11 +555,11 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { constexpr auto compiled = detail::compile(S()); if constexpr (std::is_same, detail::unknown_format>()) { - return format_to(out, - static_cast>(S()), - std::forward(args)...); + return fmt::format_to( + out, static_cast>(S()), + std::forward(args)...); } else { - return format_to(out, compiled, std::forward(args)...); + return fmt::format_to(out, compiled, std::forward(args)...); } } #endif @@ -596,22 +568,24 @@ template ::value)> format_to_n_result format_to_n(OutputIt out, size_t n, const S& format_str, Args&&... args) { - auto it = format_to(detail::truncating_iterator(out, n), format_str, - std::forward(args)...); + auto it = fmt::format_to(detail::truncating_iterator(out, n), + format_str, std::forward(args)...); return {it.base(), it.count()}; } template ::value)> -size_t formatted_size(const S& format_str, const Args&... args) { - return format_to(detail::counting_iterator(), format_str, args...).count(); +FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, + const Args&... args) { + return fmt::format_to(detail::counting_iterator(), format_str, args...) + .count(); } template ::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...); + fmt::format_to(std::back_inserter(buffer), format_str, args...); detail::print(f, {buffer.data(), buffer.size()}); } @@ -621,14 +595,12 @@ void print(const S& format_str, const Args&... args) { print(stdout, format_str, args...); } -#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +#if FMT_USE_NONTYPE_TEMPLATE_ARGS inline namespace literals { -template -constexpr detail::udl_compiled_string< - remove_cvref_t, - sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> -operator""_cf() { - return {}; +template constexpr auto operator""_cf() { + using char_t = remove_cvref_t; + return detail::udl_compiled_string(); } } // namespace literals #endif diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/core.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/core.h index d058398ac..f6a37af9e 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/core.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/core.h @@ -8,65 +8,70 @@ #ifndef FMT_CORE_H_ #define FMT_CORE_H_ -#include // std::FILE -#include +#include // std::byte +#include // std::FILE +#include // std::strlen #include #include #include #include // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 80001 +#define FMT_VERSION 90100 -#ifdef __clang__ +#if defined(__clang__) && !defined(__ibmxl__) # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) #else # define FMT_CLANG_VERSION 0 #endif -#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ + !defined(__NVCOMPILER) # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_PRAGMA(arg) _Pragma(arg) #else # define FMT_GCC_VERSION 0 -# define FMT_GCC_PRAGMA(arg) #endif -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) -# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION -#else -# define FMT_HAS_GXX_CXX11 0 +#ifndef FMT_GCC_PRAGMA +// Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884. +# if FMT_GCC_VERSION >= 504 +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +# else +# define FMT_GCC_PRAGMA(arg) +# endif #endif -#if defined(__INTEL_COMPILER) +#ifdef __ICL +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) # define FMT_ICC_VERSION __INTEL_COMPILER #else # define FMT_ICC_VERSION 0 #endif -#ifdef __NVCC__ -# define FMT_NVCC __NVCC__ -#else -# define FMT_NVCC 0 -#endif - #ifdef _MSC_VER -# define FMT_MSC_VER _MSC_VER +# define FMT_MSC_VERSION _MSC_VER # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) #else -# define FMT_MSC_VER 0 +# define FMT_MSC_VERSION 0 # define FMT_MSC_WARNING(...) #endif +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + #ifdef __has_feature # define FMT_HAS_FEATURE(x) __has_feature(x) #else # define FMT_HAS_FEATURE(x) 0 #endif -#if defined(__has_include) && \ - (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \ - (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600) +#if (defined(__has_include) || FMT_ICC_VERSION >= 1600 || \ + FMT_MSC_VERSION > 1900) && \ + !defined(__INTELLISENSE__) # define FMT_HAS_INCLUDE(x) __has_include(x) #else # define FMT_HAS_INCLUDE(x) 0 @@ -79,117 +84,102 @@ #endif #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ - (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ - (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) // Check if relaxed C++14 constexpr is supported. // GCC doesn't allow throw in constexpr until version 6 (bug 67371). #ifndef FMT_USE_CONSTEXPR -# define FMT_USE_CONSTEXPR \ - (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ - (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ - !FMT_NVCC && !FMT_ICC_VERSION +# if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \ + (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \ + !FMT_ICC_VERSION && !defined(__NVCC__) +# define FMT_USE_CONSTEXPR 1 +# else +# define FMT_USE_CONSTEXPR 0 +# endif #endif #if FMT_USE_CONSTEXPR # define FMT_CONSTEXPR constexpr -# define FMT_CONSTEXPR_DECL constexpr #else # define FMT_CONSTEXPR -# define FMT_CONSTEXPR_DECL #endif -// Check if constexpr std::char_traits<>::compare,length is supported. +#if ((FMT_CPLUSPLUS >= 202002L) && \ + (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \ + (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002) +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEXPR20 +#endif + +// Check if constexpr std::char_traits<>::{compare,length} are supported. #if defined(__GLIBCXX__) -# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ +# if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \ _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. # define FMT_CONSTEXPR_CHAR_TRAITS constexpr # endif -#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \ +#elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \ _LIBCPP_VERSION >= 4000 # define FMT_CONSTEXPR_CHAR_TRAITS constexpr -#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L +#elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L # define FMT_CONSTEXPR_CHAR_TRAITS constexpr #endif #ifndef FMT_CONSTEXPR_CHAR_TRAITS # define FMT_CONSTEXPR_CHAR_TRAITS #endif -#ifndef FMT_OVERRIDE -# if FMT_HAS_FEATURE(cxx_override_control) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 -# define FMT_OVERRIDE override -# else -# define FMT_OVERRIDE -# endif -#endif - // Check if exceptions are disabled. #ifndef FMT_EXCEPTIONS # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ - FMT_MSC_VER && !_HAS_EXCEPTIONS + (FMT_MSC_VERSION && !_HAS_EXCEPTIONS) # define FMT_EXCEPTIONS 0 # else # define FMT_EXCEPTIONS 1 # endif #endif -// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -# define FMT_USE_NOEXCEPT 0 -#endif - -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 -# define FMT_DETECTED_NOEXCEPT noexcept -# define FMT_HAS_CXX11_NOEXCEPT 1 -#else -# define FMT_DETECTED_NOEXCEPT throw() -# define FMT_HAS_CXX11_NOEXCEPT 0 -#endif - -#ifndef FMT_NOEXCEPT -# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT -# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +#ifndef FMT_DEPRECATED +# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900 +# define FMT_DEPRECATED [[deprecated]] # else -# define FMT_NOEXCEPT +# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +# define FMT_DEPRECATED __attribute__((deprecated)) +# elif FMT_MSC_VERSION +# define FMT_DEPRECATED __declspec(deprecated) +# else +# define FMT_DEPRECATED /* deprecated */ +# endif # endif #endif // [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code // warnings. -#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ - !FMT_NVCC +#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \ + !defined(__NVCC__) # define FMT_NORETURN [[noreturn]] #else # define FMT_NORETURN #endif -#ifndef FMT_MAYBE_UNUSED -# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) -# define FMT_MAYBE_UNUSED [[maybe_unused]] -# else -# define FMT_MAYBE_UNUSED -# endif +#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +# define FMT_FALLTHROUGH [[fallthrough]] +#elif defined(__clang__) +# define FMT_FALLTHROUGH [[clang::fallthrough]] +#elif FMT_GCC_VERSION >= 700 && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) +# define FMT_FALLTHROUGH [[gnu::fallthrough]] +#else +# define FMT_FALLTHROUGH #endif -#if __cplusplus == 201103L || __cplusplus == 201402L -# if defined(__INTEL_COMPILER) || defined(__PGI) -# define FMT_FALLTHROUGH -# elif defined(__clang__) -# define FMT_FALLTHROUGH [[clang::fallthrough]] -# elif FMT_GCC_VERSION >= 700 && \ - (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) -# define FMT_FALLTHROUGH [[gnu::fallthrough]] +#ifndef FMT_NODISCARD +# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] # else -# define FMT_FALLTHROUGH +# define FMT_NODISCARD # endif -#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \ - (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define FMT_FALLTHROUGH [[fallthrough]] -#else -# define FMT_FALLTHROUGH #endif #ifndef FMT_USE_FLOAT @@ -210,31 +200,23 @@ # endif #endif -#ifndef FMT_USE_INLINE_NAMESPACES -# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ - (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED)) -# define FMT_USE_INLINE_NAMESPACES 1 -# else -# define FMT_USE_INLINE_NAMESPACES 0 -# endif +// An inline std::forward replacement. +#define FMT_FORWARD(...) static_cast(__VA_ARGS__) + +#ifdef _MSC_VER +# define FMT_UNCHECKED_ITERATOR(It) \ + using _Unchecked_type = It // Mark iterator as checked. +#else +# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It #endif #ifndef FMT_BEGIN_NAMESPACE -# if FMT_USE_INLINE_NAMESPACES -# define FMT_INLINE_NAMESPACE inline namespace -# define FMT_END_NAMESPACE \ - } \ - } -# else -# define FMT_INLINE_NAMESPACE namespace -# define FMT_END_NAMESPACE \ - } \ - using namespace v8; \ - } -# endif # define FMT_BEGIN_NAMESPACE \ namespace fmt { \ - FMT_INLINE_NAMESPACE v8 { + inline namespace v9 { +# define FMT_END_NAMESPACE \ + } \ + } #endif #ifndef FMT_MODULE_EXPORT @@ -264,32 +246,26 @@ # define FMT_API #endif -#if FMT_GCC_VERSION -# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) -#else -# define FMT_GCC_VISIBILITY_HIDDEN -#endif - // libc++ supports string_view in pre-c++17. -#if (FMT_HAS_INCLUDE() && \ - (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ - (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +#if FMT_HAS_INCLUDE() && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) # include # define FMT_USE_STRING_VIEW -#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L +#elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L # include # define FMT_USE_EXPERIMENTAL_STRING_VIEW #endif #ifndef FMT_UNICODE -# define FMT_UNICODE !FMT_MSC_VER +# define FMT_UNICODE !FMT_MSC_VERSION #endif #ifndef FMT_CONSTEVAL -# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ - __cplusplus > 201703L) || \ - (defined(__cpp_consteval) && \ - !FMT_MSC_VER) // consteval is broken in MSVC. +# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ + FMT_CPLUSPLUS >= 202002L && !defined(__apple_build_version__)) || \ + (defined(__cpp_consteval) && \ + (!FMT_MSC_VERSION || _MSC_FULL_VER >= 193030704)) +// consteval is broken in MSVC before VS2022 and Apple clang 13. # define FMT_CONSTEVAL consteval # define FMT_HAS_CONSTEVAL # else @@ -297,19 +273,20 @@ # endif #endif -#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -# if defined(__cpp_nontype_template_args) && \ - ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ - __cpp_nontype_template_args >= 201911L) -# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 +#ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS +# if defined(__cpp_nontype_template_args) && \ + ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \ + __cpp_nontype_template_args >= 201911L) && \ + !defined(__NVCOMPILER) +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 # else -# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 # endif #endif // Enable minimal optimizations for more compact code in debug mode. FMT_GCC_PRAGMA("GCC push_options") -#ifndef __OPTIMIZE__ +#if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER) FMT_GCC_PRAGMA("GCC optimize(\"Og\")") #endif @@ -325,19 +302,30 @@ template using bool_constant = std::integral_constant; template using remove_reference_t = typename std::remove_reference::type; template +using remove_const_t = typename std::remove_const::type; +template using remove_cvref_t = typename std::remove_cv>::type; template struct type_identity { using type = T; }; template using type_identity_t = typename type_identity::type; +template +using underlying_t = typename std::underlying_type::type; + +template struct disjunction : std::false_type {}; +template struct disjunction

: P {}; +template +struct disjunction + : conditional_t> {}; + +template struct conjunction : std::true_type {}; +template struct conjunction

: P {}; +template +struct conjunction + : conditional_t, P1> {}; struct monostate { constexpr monostate() {} }; -// Suppress "unused variable" warnings with the method described in -// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. -// (void)var does not work on many Intel compilers. -template FMT_CONSTEXPR void ignore_unused(const T&...) {} - // An enable_if helper to be used in template parameters which results in much // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed // to workaround a bug in MSVC 2019 (see #1140 and #1186). @@ -349,25 +337,34 @@ template FMT_CONSTEXPR void ignore_unused(const T&...) {} FMT_BEGIN_DETAIL_NAMESPACE -constexpr FMT_INLINE auto is_constant_evaluated() FMT_NOEXCEPT -> bool { +// Suppresses "unused variable" warnings with the method described in +// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +// (void)var does not work on many Intel compilers. +template FMT_CONSTEXPR void ignore_unused(const T&...) {} + +constexpr FMT_INLINE auto is_constant_evaluated( + bool default_value = false) noexcept -> bool { #ifdef __cpp_lib_is_constant_evaluated + ignore_unused(default_value); return std::is_constant_evaluated(); #else - return false; + return default_value; #endif } -// A function to suppress "conditional expression is constant" warnings. -template constexpr auto const_check(T value) -> T { return value; } +// Suppresses "conditional expression is constant" warnings. +template constexpr FMT_INLINE auto const_check(T value) -> T { + return value; +} FMT_NORETURN FMT_API void assert_fail(const char* file, int line, const char* message); #ifndef FMT_ASSERT # ifdef NDEBUG -// FMT_ASSERT is not empty to avoid -Werror=empty-body. +// FMT_ASSERT is not empty to avoid -Wempty-body. # define FMT_ASSERT(condition, message) \ - ::fmt::ignore_unused((condition), (message)) + ::fmt::detail::ignore_unused((condition), (message)) # else # define FMT_ASSERT(condition, message) \ ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ @@ -387,11 +384,11 @@ template struct std_string_view {}; #ifdef FMT_USE_INT128 // Do nothing. -#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ - !(FMT_CLANG_VERSION && FMT_MSC_VER) +#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ + !(FMT_CLANG_VERSION && FMT_MSC_VERSION) # define FMT_USE_INT128 1 -using int128_t = __int128_t; -using uint128_t = __uint128_t; +using int128_opt = __int128_t; // An optional native 128-bit integer. +using uint128_opt = __uint128_t; template inline auto convert_for_visit(T value) -> T { return value; } @@ -399,27 +396,24 @@ template inline auto convert_for_visit(T value) -> T { # define FMT_USE_INT128 0 #endif #if !FMT_USE_INT128 -enum class int128_t {}; -enum class uint128_t {}; +enum class int128_opt {}; +enum class uint128_opt {}; // Reduce template instantiations. -template inline auto convert_for_visit(T) -> monostate { - return {}; -} +template auto convert_for_visit(T) -> monostate { return {}; } #endif // Casts a nonnegative integer to unsigned. template FMT_CONSTEXPR auto to_unsigned(Int value) -> typename std::make_unsigned::type { - FMT_ASSERT(value >= 0, "negative value"); + FMT_ASSERT(std::is_unsigned::value || value >= 0, "negative value"); return static_cast::type>(value); } FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5"; constexpr auto is_utf8() -> bool { - // Avoid buggy sign extensions in MSVC's constant evaluation mode. - // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612 + // Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297). using uchar = unsigned char; return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 && uchar(micro[1]) == 0xB5); @@ -442,12 +436,11 @@ template class basic_string_view { using value_type = Char; using iterator = const Char*; - constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} + constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {} /** Constructs a string reference object from a C string and a size. */ - constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT - : data_(s), - size_(count) {} + constexpr basic_string_view(const Char* s, size_t count) noexcept + : data_(s), size_(count) {} /** \rst @@ -457,40 +450,38 @@ template class basic_string_view { */ FMT_CONSTEXPR_CHAR_TRAITS FMT_INLINE - basic_string_view(const Char* s) : data_(s) { - if (detail::const_check(std::is_same::value && - !detail::is_constant_evaluated())) - size_ = std::strlen(reinterpret_cast(s)); - else - size_ = std::char_traits::length(s); - } + basic_string_view(const Char* s) + : data_(s), + size_(detail::const_check(std::is_same::value && + !detail::is_constant_evaluated(true)) + ? std::strlen(reinterpret_cast(s)) + : std::char_traits::length(s)) {} /** Constructs a string reference from a ``std::basic_string`` object. */ template FMT_CONSTEXPR basic_string_view( - const std::basic_string& s) FMT_NOEXCEPT - : data_(s.data()), - size_(s.size()) {} + const std::basic_string& s) noexcept + : data_(s.data()), size_(s.size()) {} template >::value)> - FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), - size_(s.size()) {} + FMT_CONSTEXPR basic_string_view(S s) noexcept + : data_(s.data()), size_(s.size()) {} /** Returns a pointer to the string data. */ - constexpr auto data() const -> const Char* { return data_; } + constexpr auto data() const noexcept -> const Char* { return data_; } /** Returns the string size. */ - constexpr auto size() const -> size_t { return size_; } + constexpr auto size() const noexcept -> size_t { return size_; } - constexpr auto begin() const -> iterator { return data_; } - constexpr auto end() const -> iterator { return data_ + size_; } + constexpr auto begin() const noexcept -> iterator { return data_; } + constexpr auto end() const noexcept -> iterator { return data_ + size_; } - constexpr auto operator[](size_t pos) const -> const Char& { + constexpr auto operator[](size_t pos) const noexcept -> const Char& { return data_[pos]; } - FMT_CONSTEXPR void remove_prefix(size_t n) { + FMT_CONSTEXPR void remove_prefix(size_t n) noexcept { data_ += n; size_ -= n; } @@ -532,6 +523,14 @@ using string_view = basic_string_view; template struct is_char : std::false_type {}; template <> struct is_char : std::true_type {}; +FMT_BEGIN_DETAIL_NAMESPACE + +// A base class for compile-time strings. +struct compile_string {}; + +template +struct is_compile_string : std::is_base_of {}; + // Returns a string view of `s`. template ::value)> FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { @@ -548,33 +547,21 @@ constexpr auto to_string_view(basic_string_view s) return s; } template >::value)> -inline auto to_string_view(detail::std_string_view s) - -> basic_string_view { + FMT_ENABLE_IF(!std::is_empty>::value)> +inline auto to_string_view(std_string_view s) -> basic_string_view { return s; } - -// A base class for compile-time strings. It is defined in the fmt namespace to -// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). -struct compile_string {}; - -template -struct is_compile_string : std::is_base_of {}; - template ::value)> constexpr auto to_string_view(const S& s) -> basic_string_view { return basic_string_view(s); } - -FMT_BEGIN_DETAIL_NAMESPACE - void to_string_view(...); -using fmt::v8::to_string_view; // Specifies whether S is a string type convertible to fmt::basic_string_view. // It should be a constexpr function but MSVC 2017 fails to compile it in // enable_if and MSVC 2015 fails to compile it as an alias template. +// ADL invocation of to_string_view is DEPRECATED! template struct is_string : std::is_class()))> { }; @@ -585,24 +572,71 @@ template struct char_t_impl::value>> { using type = typename result::value_type; }; -// Reports a compile-time error if S is not a valid format string. -template ::value)> -FMT_INLINE void check_format_string(const S&) { -#ifdef FMT_ENFORCE_COMPILE_STRING - static_assert(is_compile_string::value, - "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " - "FMT_STRING."); -#endif +enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type +}; + +// Maps core type T to the corresponding type enum constant. +template +struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + +FMT_TYPE_CONSTANT(int, int_type); +FMT_TYPE_CONSTANT(unsigned, uint_type); +FMT_TYPE_CONSTANT(long long, long_long_type); +FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +FMT_TYPE_CONSTANT(int128_opt, int128_type); +FMT_TYPE_CONSTANT(uint128_opt, uint128_type); +FMT_TYPE_CONSTANT(bool, bool_type); +FMT_TYPE_CONSTANT(Char, char_type); +FMT_TYPE_CONSTANT(float, float_type); +FMT_TYPE_CONSTANT(double, double_type); +FMT_TYPE_CONSTANT(long double, long_double_type); +FMT_TYPE_CONSTANT(const Char*, cstring_type); +FMT_TYPE_CONSTANT(basic_string_view, string_type); +FMT_TYPE_CONSTANT(const void*, pointer_type); + +constexpr bool is_integral_type(type t) { + return t > type::none_type && t <= type::last_integer_type; } -template ::value)> -void check_format_string(S); + +constexpr bool is_arithmetic_type(type t) { + return t > type::none_type && t <= type::last_numeric_type; +} + +FMT_NORETURN FMT_API void throw_format_error(const char* message); struct error_handler { constexpr error_handler() = default; constexpr error_handler(const error_handler&) = default; // This function is intentionally not constexpr to give a compile-time error. - FMT_NORETURN FMT_API void on_error(const char* message); + FMT_NORETURN void on_error(const char* message) { + throw_format_error(message); + } }; FMT_END_DETAIL_NAMESPACE @@ -622,6 +656,8 @@ class basic_format_parse_context : private ErrorHandler { basic_string_view format_str_; int next_arg_id_; + FMT_CONSTEXPR void do_check_arg_id(int id); + public: using char_type = Char; using iterator = typename basic_string_view::iterator; @@ -635,16 +671,14 @@ class basic_format_parse_context : private ErrorHandler { Returns an iterator to the beginning of the format string range being parsed. */ - constexpr auto begin() const FMT_NOEXCEPT -> iterator { + constexpr auto begin() const noexcept -> iterator { return format_str_.begin(); } /** Returns an iterator past the end of the format string range being parsed. */ - constexpr auto end() const FMT_NOEXCEPT -> iterator { - return format_str_.end(); - } + constexpr auto end() const noexcept -> iterator { return format_str_.end(); } /** Advances the begin iterator to ``it``. */ FMT_CONSTEXPR void advance_to(iterator it) { @@ -656,25 +690,29 @@ class basic_format_parse_context : private ErrorHandler { the next argument index and switches to the automatic indexing. */ FMT_CONSTEXPR auto next_arg_id() -> int { - // Don't check if the argument id is valid to avoid overhead and because it - // will be checked during formatting anyway. - if (next_arg_id_ >= 0) return next_arg_id_++; - on_error("cannot switch from manual to automatic argument indexing"); - return 0; + if (next_arg_id_ < 0) { + on_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + int id = next_arg_id_++; + do_check_arg_id(id); + return id; } /** Reports an error if using the automatic argument indexing; otherwise switches to the manual indexing. */ - FMT_CONSTEXPR void check_arg_id(int) { - if (next_arg_id_ > 0) + FMT_CONSTEXPR void check_arg_id(int id) { + if (next_arg_id_ > 0) { on_error("cannot switch from automatic to manual argument indexing"); - else - next_arg_id_ = -1; + return; + } + next_arg_id_ = -1; + do_check_arg_id(id); } - FMT_CONSTEXPR void check_arg_id(basic_string_view) {} + FMT_CONSTEXPR void check_dynamic_spec(int arg_id); FMT_CONSTEXPR void on_error(const char* message) { ErrorHandler::on_error(message); @@ -685,6 +723,65 @@ class basic_format_parse_context : private ErrorHandler { using format_parse_context = basic_format_parse_context; +FMT_BEGIN_DETAIL_NAMESPACE +// A parse context with extra data used only in compile-time checks. +template +class compile_parse_context + : public basic_format_parse_context { + private: + int num_args_; + const type* types_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, int num_args, const type* types, + ErrorHandler eh = {}, int next_arg_id = 0) + : base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {} + + constexpr auto num_args() const -> int { return num_args_; } + constexpr auto arg_type(int id) const -> type { return types_[id]; } + + FMT_CONSTEXPR auto next_arg_id() -> int { + int id = base::next_arg_id(); + if (id >= num_args_) this->on_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) this->on_error("argument not found"); + } + using base::check_arg_id; + + FMT_CONSTEXPR void check_dynamic_spec(int arg_id) { + if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) + this->on_error("width/precision is not integer"); + } +}; +FMT_END_DETAIL_NAMESPACE + +template +FMT_CONSTEXPR void +basic_format_parse_context::do_check_arg_id(int id) { + // Argument id is only checked at compile-time during parsing because + // formatting has its own validation. + if (detail::is_constant_evaluated() && FMT_GCC_VERSION >= 1200) { + using context = detail::compile_parse_context; + if (id >= static_cast(this)->num_args()) + on_error("argument not found"); + } +} + +template +FMT_CONSTEXPR void +basic_format_parse_context::check_dynamic_spec(int arg_id) { + if (detail::is_constant_evaluated()) { + using context = detail::compile_parse_context; + static_cast(this)->check_dynamic_spec(arg_id); + } +} + template class basic_format_arg; template class basic_format_args; template class dynamic_format_arg_store; @@ -711,14 +808,30 @@ class appender; FMT_BEGIN_DETAIL_NAMESPACE +template +constexpr auto has_const_formatter_impl(T*) + -> decltype(typename Context::template formatter_type().format( + std::declval(), std::declval()), + true) { + return true; +} +template +constexpr auto has_const_formatter_impl(...) -> bool { + return false; +} +template +constexpr auto has_const_formatter() -> bool { + return has_const_formatter_impl(static_cast(nullptr)); +} + // Extracts a reference to the container from back_insert_iterator. template inline auto get_container(std::back_insert_iterator it) -> Container& { - using bi_iterator = std::back_insert_iterator; - struct accessor : bi_iterator { - accessor(bi_iterator iter) : bi_iterator(iter) {} - using bi_iterator::container; + using base = std::back_insert_iterator; + struct accessor : base { + accessor(base b) : base(b) {} + using base::container; }; return *accessor(it).container; } @@ -730,13 +843,13 @@ FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) return out; } -template ::value)> -FMT_CONSTEXPR auto copy_str(const Char* begin, const Char* end, Char* out) - -> Char* { - if (is_constant_evaluated()) - return copy_str(begin, end, out); +template , U>::value&& is_char::value)> +FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* { + if (is_constant_evaluated()) return copy_str(begin, end, out); auto size = to_unsigned(end - begin); - memcpy(out, begin, size); + memcpy(out, begin, size * sizeof(U)); return out + size; } @@ -755,24 +868,22 @@ template class buffer { protected: // Don't initialize ptr_ since it is not accessed to save a few cycles. FMT_MSC_WARNING(suppress : 26495) - buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} + buffer(size_t sz) noexcept : size_(sz), capacity_(sz) {} - buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT - : ptr_(p), - size_(sz), - capacity_(cap) {} + FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) noexcept + : ptr_(p), size_(sz), capacity_(cap) {} - ~buffer() = default; + FMT_CONSTEXPR20 ~buffer() = default; buffer(buffer&&) = default; /** Sets the buffer data and capacity. */ - void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept { ptr_ = buf_data; capacity_ = buf_capacity; } /** Increases the buffer capacity to hold at least *capacity* elements. */ - virtual void grow(size_t capacity) = 0; + virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0; public: using value_type = T; @@ -781,30 +892,30 @@ template class buffer { buffer(const buffer&) = delete; void operator=(const buffer&) = delete; - auto begin() FMT_NOEXCEPT -> T* { return ptr_; } - auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; } + auto begin() noexcept -> T* { return ptr_; } + auto end() noexcept -> T* { return ptr_ + size_; } - auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; } - auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; } + auto begin() const noexcept -> const T* { return ptr_; } + auto end() const noexcept -> const T* { return ptr_ + size_; } /** Returns the size of this buffer. */ - auto size() const FMT_NOEXCEPT -> size_t { return size_; } + constexpr auto size() const noexcept -> size_t { return size_; } /** Returns the capacity of this buffer. */ - auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } + constexpr auto capacity() const noexcept -> size_t { return capacity_; } /** Returns a pointer to the buffer data. */ - auto data() FMT_NOEXCEPT -> T* { return ptr_; } + FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; } /** Returns a pointer to the buffer data. */ - auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } + FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } /** Clears this buffer. */ void clear() { size_ = 0; } // Tries resizing the buffer to contain *count* elements. If T is a POD type // the new elements may not be initialized. - void try_resize(size_t count) { + FMT_CONSTEXPR20 void try_resize(size_t count) { try_reserve(count); size_ = count <= capacity_ ? count : capacity_; } @@ -813,11 +924,11 @@ template class buffer { // capacity by a smaller amount than requested but guarantees there is space // for at least one additional element either by increasing the capacity or by // flushing the buffer if it is full. - void try_reserve(size_t new_capacity) { + FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) { if (new_capacity > capacity_) grow(new_capacity); } - void push_back(const T& value) { + FMT_CONSTEXPR20 void push_back(const T& value) { try_reserve(size_ + 1); ptr_[size_++] = value; } @@ -825,8 +936,11 @@ template class buffer { /** Appends data to the end of the buffer. */ template void append(const U* begin, const U* end); - template auto operator[](I index) -> T& { return ptr_[index]; } - template auto operator[](I index) const -> const T& { + template FMT_CONSTEXPR auto operator[](Idx index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](Idx index) const -> const T& { return ptr_[index]; } }; @@ -861,7 +975,7 @@ class iterator_buffer final : public Traits, public buffer { T data_[buffer_size]; protected: - void grow(size_t) final FMT_OVERRIDE { + FMT_CONSTEXPR20 void grow(size_t) override { if (this->size() == buffer_size) flush(); } @@ -885,9 +999,55 @@ class iterator_buffer final : public Traits, public buffer { auto count() const -> size_t { return Traits::count() + this->size(); } }; +template +class iterator_buffer final + : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + FMT_CONSTEXPR20 void grow(size_t) override { + if (this->size() == this->capacity()) flush(); + } + + void flush() { + size_t n = this->limit(this->size()); + if (this->data() == out_) { + out_ += n; + this->set(data_, buffer_size); + } + this->clear(); + } + + public: + explicit iterator_buffer(T* out, size_t n = buffer_size) + : fixed_buffer_traits(n), buffer(out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : fixed_buffer_traits(other), + buffer(std::move(other)), + out_(other.out_) { + if (this->data() != out_) { + this->set(data_, buffer_size); + this->clear(); + } + } + ~iterator_buffer() { flush(); } + + auto out() -> T* { + flush(); + return out_; + } + auto count() const -> size_t { + return fixed_buffer_traits::count() + this->size(); + } +}; + template class iterator_buffer final : public buffer { protected: - void grow(size_t) final FMT_OVERRIDE {} + FMT_CONSTEXPR20 void grow(size_t) override {} public: explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} @@ -905,7 +1065,7 @@ class iterator_buffer, Container& container_; protected: - void grow(size_t capacity) final FMT_OVERRIDE { + FMT_CONSTEXPR20 void grow(size_t capacity) override { container_.resize(capacity); this->set(&container_[0], capacity); } @@ -915,6 +1075,7 @@ class iterator_buffer, : buffer(c.size()), container_(c) {} explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) : iterator_buffer(get_container(out)) {} + auto out() -> std::back_insert_iterator { return std::back_inserter(container_); } @@ -928,7 +1089,7 @@ template class counting_buffer final : public buffer { size_t count_ = 0; protected: - void grow(size_t) final FMT_OVERRIDE { + FMT_CONSTEXPR20 void grow(size_t) override { if (this->size() != buffer_size) return; count_ += this->size(); this->clear(); @@ -966,7 +1127,11 @@ struct fallback_formatter { // Specifies if T has an enabled fallback_formatter specialization. template using has_fallback_formatter = +#ifdef FMT_DEPRECATED_OSTREAM std::is_constructible>; +#else + std::false_type; +#endif struct view {}; @@ -1045,60 +1210,15 @@ template constexpr auto count_named_args() -> size_t { return count::value...>(); } -enum class type { - none_type, - // Integer types should go first, - int_type, - uint_type, - long_long_type, - ulong_long_type, - int128_type, - uint128_type, - bool_type, - char_type, - last_integer_type = char_type, - // followed by floating-point types. - float_type, - double_type, - long_double_type, - last_numeric_type = long_double_type, - cstring_type, - string_type, - pointer_type, - custom_type -}; - -// Maps core type T to the corresponding type enum constant. -template -struct type_constant : std::integral_constant {}; - -#define FMT_TYPE_CONSTANT(Type, constant) \ - template \ - struct type_constant \ - : std::integral_constant {} - -FMT_TYPE_CONSTANT(int, int_type); -FMT_TYPE_CONSTANT(unsigned, uint_type); -FMT_TYPE_CONSTANT(long long, long_long_type); -FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); -FMT_TYPE_CONSTANT(int128_t, int128_type); -FMT_TYPE_CONSTANT(uint128_t, uint128_type); -FMT_TYPE_CONSTANT(bool, bool_type); -FMT_TYPE_CONSTANT(Char, char_type); -FMT_TYPE_CONSTANT(float, float_type); -FMT_TYPE_CONSTANT(double, double_type); -FMT_TYPE_CONSTANT(long double, long_double_type); -FMT_TYPE_CONSTANT(const Char*, cstring_type); -FMT_TYPE_CONSTANT(basic_string_view, string_type); -FMT_TYPE_CONSTANT(const void*, pointer_type); - -constexpr bool is_integral_type(type t) { - return t > type::none_type && t <= type::last_integer_type; +template +constexpr auto count_statically_named_args() -> size_t { + return count::value...>(); } -constexpr bool is_arithmetic_type(type t) { - return t > type::none_type && t <= type::last_numeric_type; -} +struct unformattable {}; +struct unformattable_char : unformattable {}; +struct unformattable_const : unformattable {}; +struct unformattable_pointer : unformattable {}; template struct string_value { const Char* data; @@ -1112,8 +1232,8 @@ template struct named_arg_value { template struct custom_value { using parse_context = typename Context::parse_context_type; - const void* value; - void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); }; // A formatting argument value. @@ -1127,8 +1247,8 @@ template class value { unsigned uint_value; long long long_long_value; unsigned long long ulong_long_value; - int128_t int128_value; - uint128_t uint128_value; + int128_opt int128_value; + uint128_opt uint128_value; bool bool_value; char_type char_value; float float_value; @@ -1145,10 +1265,10 @@ template class value { constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} constexpr FMT_INLINE value(long long val) : long_long_value(val) {} constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} - FMT_INLINE value(int128_t val) : int128_value(val) {} - FMT_INLINE value(uint128_t val) : uint128_value(val) {} - FMT_INLINE value(float val) : float_value(val) {} - FMT_INLINE value(double val) : double_value(val) {} + FMT_INLINE value(int128_opt val) : int128_value(val) {} + FMT_INLINE value(uint128_opt val) : uint128_value(val) {} + constexpr FMT_INLINE value(float val) : float_value(val) {} + constexpr FMT_INLINE value(double val) : double_value(val) {} FMT_INLINE value(long double val) : long_double_value(val) {} constexpr FMT_INLINE value(bool val) : bool_value(val) {} constexpr FMT_INLINE value(char_type val) : char_value(val) {} @@ -1164,31 +1284,39 @@ template class value { FMT_INLINE value(const named_arg_info* args, size_t size) : named_args{args, size} {} - template FMT_CONSTEXPR FMT_INLINE value(const T& val) { - custom.value = &val; + template FMT_CONSTEXPR FMT_INLINE value(T& val) { + using value_type = remove_cvref_t; + custom.value = const_cast(&val); // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and // `printf_formatter` for `printf`. custom.format = format_custom_arg< - T, conditional_t::value, - typename Context::template formatter_type, - fallback_formatter>>; + value_type, + conditional_t::value, + typename Context::template formatter_type, + fallback_formatter>>; } + value(unformattable); + value(unformattable_char); + value(unformattable_const); + value(unformattable_pointer); private: // Formats an argument of a custom type, such as a user-defined class. template - static void format_custom_arg(const void* arg, + static void format_custom_arg(void* arg, typename Context::parse_context_type& parse_ctx, Context& ctx) { - Formatter f; + auto f = Formatter(); parse_ctx.advance_to(f.parse(parse_ctx)); - ctx.advance_to(f.format(*static_cast(arg), ctx)); + using qualified_type = + conditional_t(), const T, T>; + ctx.advance_to(f.format(*static_cast(arg), ctx)); } }; template -FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg; +FMT_CONSTEXPR auto make_arg(T&& value) -> basic_format_arg; // To minimize the number of types we need to deal with, long is translated // either to int or to long long depending on its size. @@ -1196,9 +1324,24 @@ enum { long_short = sizeof(long) == sizeof(int) }; using long_type = conditional_t; using ulong_type = conditional_t; -struct unformattable {}; +#ifdef __cpp_lib_byte +inline auto format_as(std::byte b) -> unsigned char { + return static_cast(b); +} +#endif + +template struct has_format_as { + template ::value&& std::is_integral::value)> + static auto check(U*) -> std::true_type; + static auto check(...) -> std::false_type; + + enum { value = decltype(check(static_cast(nullptr)))::value }; +}; // Maps formatting arguments to core types. +// arg_mapper reports errors by returning unformattable instead of using +// static_assert because it's used in the is_formattable trait. template struct arg_mapper { using char_type = typename Context::char_type; @@ -1221,17 +1364,30 @@ template struct arg_mapper { -> unsigned long long { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; } + FMT_CONSTEXPR FMT_INLINE auto map(int128_opt val) -> int128_opt { + return val; + } + FMT_CONSTEXPR FMT_INLINE auto map(uint128_opt val) -> uint128_opt { + return val; + } FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } - template ::value)> + template ::value || + std::is_same::value)> FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { - static_assert( - std::is_same::value || std::is_same::value, - "mixing character types is disallowed"); return val; } + template ::value || +#ifdef __cpp_char8_t + std::is_same::value || +#endif + std::is_same::value || + std::is_same::value) && + !std::is_same::value, + int> = 0> + FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { + return {}; + } FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } @@ -1245,49 +1401,38 @@ template struct arg_mapper { FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { return val; } - template ::value)> + template ::value && !std::is_pointer::value && + std::is_same>::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> basic_string_view { - static_assert(std::is_same>::value, - "mixing character types is disallowed"); return to_string_view(val); } + template ::value && !std::is_pointer::value && + !std::is_same>::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { + return {}; + } template , T>::value && + std::is_convertible>::value && !is_string::value && !has_formatter::value && !has_fallback_formatter::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> basic_string_view { return basic_string_view(val); } - template < - typename T, - FMT_ENABLE_IF( - std::is_constructible, T>::value && - !std::is_constructible, T>::value && - !is_string::value && !has_formatter::value && - !has_fallback_formatter::value)> + template >::value && + !std::is_convertible>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> basic_string_view { return std_string_view(val); } - FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); - } - FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* { - static_assert(std::is_same::value, "invalid string type"); - return reinterpret_cast(val); - } - FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> const char* { - const auto* const_val = val; - return map(const_val); - } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> const char* { - const auto* const_val = val; - return map(const_val); - } FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* { @@ -1299,37 +1444,76 @@ template struct arg_mapper { // We use SFINAE instead of a const T* parameter to avoid conflicting with // the C array overload. - template - FMT_CONSTEXPR auto map(T) -> enable_if_t::value, int> { - // Formatting of arbitrary pointers is disallowed. If you want to output - // a pointer cast it to "void *" or "const void *". In particular, this - // forbids formatting of "[const] volatile char *" which is printed as bool - // by iostreams. - static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); - return 0; + template < + typename T, + FMT_ENABLE_IF( + std::is_pointer::value || std::is_member_pointer::value || + std::is_function::type>::value || + (std::is_convertible::value && + !std::is_convertible::value && + !has_formatter::value))> + FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { + return {}; } - template + template ::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { return values; } template ::value && - !has_formatter::value && - !has_fallback_formatter::value)> - FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + FMT_ENABLE_IF( + std::is_enum::value&& std::is_convertible::value && + !has_format_as::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> decltype(std::declval().map( - static_cast::type>(val))) { - return map(static_cast::type>(val)); + static_cast>(val))) { + return map(static_cast>(val)); } - template ::value && !is_char::value && - (has_formatter::value || - has_fallback_formatter::value))> - FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> const T& { + + template ::value && + !has_formatter::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> decltype(std::declval().map(format_as(T()))) { + return map(format_as(val)); + } + + template > + struct formattable + : bool_constant() || + !std::is_const>::value || + has_fallback_formatter::value> {}; + +#if (FMT_MSC_VERSION != 0 && FMT_MSC_VERSION < 1910) || \ + FMT_ICC_VERSION != 0 || defined(__NVCC__) + // Workaround a bug in MSVC and Intel (Issue 2746). + template FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { + return val; + } +#else + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&& val) -> T& { return val; } + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto do_map(T&&) -> unformattable_const { + return {}; + } +#endif + + template , + FMT_ENABLE_IF(!is_string::value && !is_char::value && + !std::is_array::value && + !std::is_pointer::value && + !has_format_as::value && + (has_formatter::value || + has_fallback_formatter::value))> + FMT_CONSTEXPR FMT_INLINE auto map(T&& val) + -> decltype(this->do_map(std::forward(val))) { + return do_map(std::forward(val)); + } template ::value)> FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) @@ -1366,19 +1550,11 @@ class appender : public std::back_insert_iterator> { public: using std::back_insert_iterator>::back_insert_iterator; - appender(base it) : base(it) {} - using _Unchecked_type = appender; // Mark iterator as checked. + appender(base it) noexcept : base(it) {} + FMT_UNCHECKED_ITERATOR(appender); - auto operator++() -> appender& { - base::operator++(); - return *this; - } - - auto operator++(int) -> appender { - auto tmp = *this; - ++*this; - return tmp; - } + auto operator++() noexcept -> appender& { return *this; } + auto operator++(int) noexcept -> appender { return *this; } }; // A formatting argument. It is a trivially copyable/constructible type to @@ -1389,7 +1565,7 @@ template class basic_format_arg { detail::type type_; template - friend FMT_CONSTEXPR auto detail::make_arg(const T& value) + friend FMT_CONSTEXPR auto detail::make_arg(T&& value) -> basic_format_arg; template @@ -1424,7 +1600,7 @@ template class basic_format_arg { constexpr basic_format_arg() : type_(detail::type::none_type) {} - constexpr explicit operator bool() const FMT_NOEXCEPT { + constexpr explicit operator bool() const noexcept { return type_ != detail::type::none_type; } @@ -1492,6 +1668,11 @@ auto copy_str(InputIt begin, InputIt end, appender out) -> appender { return out; } +template +FMT_CONSTEXPR auto copy_str(R&& rng, OutputIt out) -> OutputIt { + return detail::copy_str(rng.begin(), rng.end(), out); +} + #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 // A workaround for gcc 4.8 to make void_t work in a SFINAE context. template struct void_t_impl { using type = void; }; @@ -1525,7 +1706,7 @@ struct is_contiguous_back_insert_iterator> template <> struct is_contiguous_back_insert_iterator : std::true_type {}; -// A type-erased reference to an std::locale to avoid heavy include. +// A type-erased reference to an std::locale to avoid a heavy include. class locale_ref { private: const void* locale_; // A type-erased pointer to std::locale. @@ -1534,7 +1715,7 @@ class locale_ref { constexpr locale_ref() : locale_(nullptr) {} template explicit locale_ref(const Locale& loc); - explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } + explicit operator bool() const noexcept { return locale_ != nullptr; } template auto get() const -> Locale; }; @@ -1550,10 +1731,40 @@ constexpr auto encode_types() -> unsigned long long { } template -FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg { +FMT_CONSTEXPR FMT_INLINE auto make_value(T&& val) -> value { + const auto& arg = arg_mapper().map(FMT_FORWARD(val)); + + constexpr bool formattable_char = + !std::is_same::value; + static_assert(formattable_char, "Mixing character types is disallowed."); + + constexpr bool formattable_const = + !std::is_same::value; + static_assert(formattable_const, "Cannot format a const argument."); + + // Formatting of arbitrary pointers is disallowed. If you want to output + // a pointer cast it to "void *" or "const void *". In particular, this + // forbids formatting of "[const] volatile char *" which is printed as bool + // by iostreams. + constexpr bool formattable_pointer = + !std::is_same::value; + static_assert(formattable_pointer, + "Formatting of non-void pointers is disallowed."); + + constexpr bool formattable = + !std::is_same::value; + static_assert( + formattable, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return {arg}; +} + +template +FMT_CONSTEXPR auto make_arg(T&& value) -> basic_format_arg { basic_format_arg arg; arg.type_ = mapped_type_constant::value; - arg.value_ = arg_mapper().map(value); + arg.value_ = make_value(value); return arg; } @@ -1562,18 +1773,13 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg { // another (not recommended). template -FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value { - const auto& arg = arg_mapper().map(val); - static_assert( - !std::is_same::value, - "Cannot format an argument. To make type T formattable provide a " - "formatter specialization: https://fmt.dev/latest/api.html#udt"); - return {arg}; +FMT_CONSTEXPR FMT_INLINE auto make_arg(T&& val) -> value { + return make_value(val); } template -inline auto make_arg(const T& value) -> basic_format_arg { +FMT_CONSTEXPR inline auto make_arg(T&& value) -> basic_format_arg { return make_arg(value); } FMT_END_DETAIL_NAMESPACE @@ -1643,9 +1849,9 @@ using format_context = buffer_context; template using is_formattable = bool_constant< - !std::is_same>().map( - std::declval())), - detail::unformattable>::value && + !std::is_base_of>().map( + std::declval()))>::value && !detail::has_fallback_formatter::value>; /** @@ -1684,14 +1890,16 @@ class format_arg_store : 0); public: - FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args) + template + FMT_CONSTEXPR FMT_INLINE format_arg_store(T&&... args) : #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 basic_format_args(*this), #endif data_{detail::make_arg< is_packed, Context, - detail::mapped_type_constant::value>(args)...} { + detail::mapped_type_constant, Context>::value>( + FMT_FORWARD(args))...} { detail::init_named_args(data_.named_args(), 0, 0, args...); } }; @@ -1705,9 +1913,9 @@ class format_arg_store \endrst */ template -constexpr auto make_format_args(const Args&... args) - -> format_arg_store { - return {args...}; +constexpr auto make_format_args(Args&&... args) + -> format_arg_store...> { + return {FMT_FORWARD(args)...}; } /** @@ -1853,21 +2061,27 @@ template class basic_format_args { // between clang and gcc on ARM (#1919). using format_args = basic_format_args; -// We cannot use enum classes as bit fields because of a gcc bug -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. +// We cannot use enum classes as bit fields because of a gcc bug, so we put them +// in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414). +// Additionally, if an underlying type is specified, older gcc incorrectly warns +// that the type is too small. Both bugs are fixed in gcc 9.3. +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903 +# define FMT_ENUM_UNDERLYING_TYPE(type) +#else +# define FMT_ENUM_UNDERLYING_TYPE(type) : type +#endif namespace align { -enum type { none, left, right, center, numeric }; +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, left, right, center, + numeric}; } using align_t = align::type; namespace sign { -enum type { none, minus, plus, space }; +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space}; } using sign_t = sign::type; FMT_BEGIN_DETAIL_NAMESPACE -void throw_format_error(const char* message); - // Workaround an array initialization issue in gcc 4.8. template struct fill_t { private: @@ -1893,11 +2107,34 @@ template struct fill_t { }; FMT_END_DETAIL_NAMESPACE +enum class presentation_type : unsigned char { + none, + // Integer types should go first, + dec, // 'd' + oct, // 'o' + hex_lower, // 'x' + hex_upper, // 'X' + bin_lower, // 'b' + bin_upper, // 'B' + hexfloat_lower, // 'a' + hexfloat_upper, // 'A' + exp_lower, // 'e' + exp_upper, // 'E' + fixed_lower, // 'f' + fixed_upper, // 'F' + general_lower, // 'g' + general_upper, // 'G' + chr, // 'c' + string, // 's' + pointer, // 'p' + debug // '?' +}; + // Format specifiers for built-in and string types. template struct basic_format_specs { int width; int precision; - char type; + presentation_type type; align_t align : 4; sign_t sign : 3; bool alt : 1; // Alternate form ('#'). @@ -1907,7 +2144,7 @@ template struct basic_format_specs { constexpr basic_format_specs() : width(0), precision(-1), - type(0), + type(presentation_type::none), align(align::none), sign(sign::none), alt(false), @@ -1987,9 +2224,7 @@ template class specs_setter { } FMT_CONSTEXPR void end_precision() {} - FMT_CONSTEXPR void on_type(Char type) { - specs_.type = static_cast(type); - } + FMT_CONSTEXPR void on_type(presentation_type type) { specs_.type = type; } }; // Format spec handler that saves references to arguments representing dynamic @@ -2029,11 +2264,14 @@ class dynamic_specs_handler FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type { context_.check_arg_id(arg_id); + context_.check_dynamic_spec(arg_id); return arg_ref_type(arg_id); } FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type { - return arg_ref_type(context_.next_arg_id()); + int arg_id = context_.next_arg_id(); + context_.check_dynamic_spec(arg_id); + return arg_ref_type(arg_id); } FMT_CONSTEXPR auto make_arg_ref(basic_string_view arg_id) @@ -2051,21 +2289,23 @@ template constexpr bool is_ascii_letter(Char c) { // Converts a character to ASCII. Returns a number > 127 on conversion failure. template ::value)> -constexpr auto to_ascii(Char value) -> Char { - return value; +constexpr auto to_ascii(Char c) -> Char { + return c; } template ::value)> -constexpr auto to_ascii(Char value) -> - typename std::underlying_type::type { - return value; +constexpr auto to_ascii(Char c) -> underlying_t { + return c; +} + +FMT_CONSTEXPR inline auto code_point_length_impl(char c) -> int { + return "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" + [static_cast(c) >> 3]; } template FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { if (const_check(sizeof(Char) != 1)) return 1; - constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; - int len = lengths[static_cast(*begin) >> 3]; + int len = code_point_length_impl(static_cast(*begin)); // Compute the pointer to the next character early so that the next // iteration can start working on the next character. Neither Clang @@ -2122,7 +2362,7 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, FMT_ASSERT(begin != end, ""); auto align = align::none; auto p = begin + code_point_length(begin); - if (p >= end) p = begin; + if (end - p <= 0) p = begin; for (;;) { switch (to_ascii(*p)) { case '<': @@ -2271,6 +2511,50 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, return begin; } +template +FMT_CONSTEXPR auto parse_presentation_type(Char type) -> presentation_type { + switch (to_ascii(type)) { + case 'd': + return presentation_type::dec; + case 'o': + return presentation_type::oct; + case 'x': + return presentation_type::hex_lower; + case 'X': + return presentation_type::hex_upper; + case 'b': + return presentation_type::bin_lower; + case 'B': + return presentation_type::bin_upper; + case 'a': + return presentation_type::hexfloat_lower; + case 'A': + return presentation_type::hexfloat_upper; + case 'e': + return presentation_type::exp_lower; + case 'E': + return presentation_type::exp_upper; + case 'f': + return presentation_type::fixed_lower; + case 'F': + return presentation_type::fixed_upper; + case 'g': + return presentation_type::general_lower; + case 'G': + return presentation_type::general_upper; + case 'c': + return presentation_type::chr; + case 's': + return presentation_type::string; + case 'p': + return presentation_type::pointer; + case '?': + return presentation_type::debug; + default: + return presentation_type::none; + } +} + // Parses standard format specifiers and sends notifications about parsed // components to handler. template @@ -2278,9 +2562,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, const Char* end, SpecHandler&& handler) -> const Char* { - if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) && + if (1 < end - begin && begin[1] == '}' && is_ascii_letter(*begin) && *begin != 'L') { - handler.on_type(*begin++); + presentation_type type = parse_presentation_type(*begin++); + if (type == presentation_type::none) + handler.on_error("invalid type specifier"); + handler.on_type(type); return begin; } @@ -2334,7 +2621,12 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin, } // Parse type. - if (begin != end && *begin != '}') handler.on_type(*begin++); + if (begin != end && *begin != '}') { + presentation_type type = parse_presentation_type(*begin++); + if (type == presentation_type::none) + handler.on_error("invalid type specifier"); + handler.on_type(type); + } return begin; } @@ -2381,7 +2673,7 @@ FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, template FMT_CONSTEXPR FMT_INLINE void parse_format_string( basic_string_view format_str, Handler&& handler) { - // this is most likely a name-lookup defect in msvc's modules implementation + // Workaround a name-lookup bug in MSVC's modules implementation. using detail::find; auto begin = format_str.data(); @@ -2405,21 +2697,21 @@ FMT_CONSTEXPR FMT_INLINE void parse_format_string( return; } struct writer { - FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { - if (pbegin == pend) return; + FMT_CONSTEXPR void operator()(const Char* from, const Char* to) { + if (from == to) return; for (;;) { const Char* p = nullptr; - if (!find(pbegin, pend, Char('}'), p)) - return handler_.on_text(pbegin, pend); + if (!find(from, to, Char('}'), p)) + return handler_.on_text(from, to); ++p; - if (p == pend || *p != '}') + if (p == to || *p != '}') return handler_.on_error("unmatched '}' in format string"); - handler_.on_text(pbegin, p); - pbegin = p + 1; + handler_.on_text(from, p); + from = p + 1; } } Handler& handler_; - } write{handler}; + } write = {handler}; while (begin != end) { // Doing two passes with memchr (one for '{' and another for '}') is up to // 2.5x faster than the naive one-pass implementation on big format strings. @@ -2431,73 +2723,43 @@ FMT_CONSTEXPR FMT_INLINE void parse_format_string( } } +template ::value> struct strip_named_arg { + using type = T; +}; +template struct strip_named_arg { + using type = remove_cvref_t; +}; + template FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) -> decltype(ctx.begin()) { using char_type = typename ParseContext::char_type; using context = buffer_context; + using stripped_type = typename strip_named_arg::type; using mapped_type = conditional_t< mapped_type_constant::value != type::custom_type, - decltype(arg_mapper().map(std::declval())), T>; + decltype(arg_mapper().map(std::declval())), + stripped_type>; auto f = conditional_t::value, formatter, - fallback_formatter>(); + fallback_formatter>(); return f.parse(ctx); } -// A parse context with extra argument id checks. It is only used at compile -// time because adding checks at runtime would introduce substantial overhead -// and would be redundant since argument ids are checked when arguments are -// retrieved anyway. -template -class compile_parse_context - : public basic_format_parse_context { - private: - int num_args_; - using base = basic_format_parse_context; - - public: - explicit FMT_CONSTEXPR compile_parse_context( - basic_string_view format_str, - int num_args = (std::numeric_limits::max)(), ErrorHandler eh = {}) - : base(format_str, eh), num_args_(num_args) {} - - FMT_CONSTEXPR auto next_arg_id() -> int { - int id = base::next_arg_id(); - if (id >= num_args_) this->on_error("argument not found"); - return id; - } - - FMT_CONSTEXPR void check_arg_id(int id) { - base::check_arg_id(id); - if (id >= num_args_) this->on_error("argument not found"); - } - using base::check_arg_id; -}; - template -FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) { - switch (spec) { - case 0: - case 'd': - case 'x': - case 'X': - case 'b': - case 'B': - case 'o': - case 'c': - break; - default: +FMT_CONSTEXPR void check_int_type_spec(presentation_type type, + ErrorHandler&& eh) { + if (type > presentation_type::bin_upper && type != presentation_type::chr) eh.on_error("invalid type specifier"); - break; - } } // Checks char specs and returns true if the type spec is char (and not int). template FMT_CONSTEXPR auto check_char_specs(const basic_format_specs& specs, ErrorHandler&& eh = {}) -> bool { - if (specs.type && specs.type != 'c') { + if (specs.type != presentation_type::none && + specs.type != presentation_type::chr && + specs.type != presentation_type::debug) { check_int_type_spec(specs.type, eh); return false; } @@ -2521,7 +2783,6 @@ struct float_specs { bool upper : 1; bool locale : 1; bool binary32 : 1; - bool use_grisu : 1; bool showpoint : 1; }; @@ -2533,33 +2794,33 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, result.showpoint = specs.alt; result.locale = specs.localized; switch (specs.type) { - case 0: + case presentation_type::none: result.format = float_format::general; break; - case 'G': + case presentation_type::general_upper: result.upper = true; FMT_FALLTHROUGH; - case 'g': + case presentation_type::general_lower: result.format = float_format::general; break; - case 'E': + case presentation_type::exp_upper: result.upper = true; FMT_FALLTHROUGH; - case 'e': + case presentation_type::exp_lower: result.format = float_format::exp; result.showpoint |= specs.precision != 0; break; - case 'F': + case presentation_type::fixed_upper: result.upper = true; FMT_FALLTHROUGH; - case 'f': + case presentation_type::fixed_lower: result.format = float_format::fixed; result.showpoint |= specs.precision != 0; break; - case 'A': + case presentation_type::hexfloat_upper: result.upper = true; FMT_FALLTHROUGH; - case 'a': + case presentation_type::hexfloat_lower: result.format = float_format::hex; break; default: @@ -2569,22 +2830,29 @@ FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs& specs, return result; } -template -FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {}) - -> bool { - if (spec == 0 || spec == 's') return true; - if (spec != 'p') eh.on_error("invalid type specifier"); +template +FMT_CONSTEXPR auto check_cstring_type_spec(presentation_type type, + ErrorHandler&& eh = {}) -> bool { + if (type == presentation_type::none || type == presentation_type::string || + type == presentation_type::debug) + return true; + if (type != presentation_type::pointer) eh.on_error("invalid type specifier"); return false; } -template -FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh = {}) { - if (spec != 0 && spec != 's') eh.on_error("invalid type specifier"); +template +FMT_CONSTEXPR void check_string_type_spec(presentation_type type, + ErrorHandler&& eh = {}) { + if (type != presentation_type::none && type != presentation_type::string && + type != presentation_type::debug) + eh.on_error("invalid type specifier"); } -template -FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) { - if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier"); +template +FMT_CONSTEXPR void check_pointer_type_spec(presentation_type type, + ErrorHandler&& eh) { + if (type != presentation_type::none && type != presentation_type::pointer) + eh.on_error("invalid type specifier"); } // A parse_format_specs handler that checks if specifiers are consistent with @@ -2610,7 +2878,8 @@ template class specs_checker : public Handler { FMT_CONSTEXPR void on_sign(sign_t s) { require_numeric_argument(); if (is_integral_type(arg_type_) && arg_type_ != type::int_type && - arg_type_ != type::long_long_type && arg_type_ != type::char_type) { + arg_type_ != type::long_long_type && arg_type_ != type::int128_type && + arg_type_ != type::char_type) { this->on_error("format specifier requires signed argument"); } Handler::on_sign(s); @@ -2639,53 +2908,54 @@ template class specs_checker : public Handler { constexpr int invalid_arg_index = -1; -#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +#if FMT_USE_NONTYPE_TEMPLATE_ARGS template constexpr auto get_arg_index_by_name(basic_string_view name) -> int { if constexpr (detail::is_statically_named_arg()) { if (name == T::name) return N; } - if constexpr (sizeof...(Args) > 0) { + if constexpr (sizeof...(Args) > 0) return get_arg_index_by_name(name); - } else { - (void)name; // Workaround an MSVC bug about "unused" parameter. - return invalid_arg_index; - } + (void)name; // Workaround an MSVC bug about "unused" parameter. + return invalid_arg_index; } #endif template FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { -#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS - if constexpr (sizeof...(Args) > 0) { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + if constexpr (sizeof...(Args) > 0) return get_arg_index_by_name<0, Args...>(name); - } else { - (void)name; - return invalid_arg_index; - } -#else +#endif (void)name; return invalid_arg_index; -#endif } template class format_string_checker { private: + // In the future basic_format_parse_context will replace compile_parse_context + // here and will use is_constant_evaluated and downcasting to access the data + // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. using parse_context_type = compile_parse_context; - enum { num_args = sizeof...(Args) }; + static constexpr int num_args = sizeof...(Args); // Format specifier parsing function. using parse_func = const Char* (*)(parse_context_type&); parse_context_type context_; - parse_func parse_funcs_[num_args > 0 ? num_args : 1]; + parse_func parse_funcs_[num_args > 0 ? static_cast(num_args) : 1]; + type types_[num_args > 0 ? static_cast(num_args) : 1]; public: explicit FMT_CONSTEXPR format_string_checker( basic_string_view format_str, ErrorHandler eh) - : context_(format_str, num_args, eh), - parse_funcs_{&parse_format_specs...} {} + : context_(format_str, num_args, types_, eh), + parse_funcs_{&parse_format_specs...}, + types_{ + mapped_type_constant>::value...} { + } FMT_CONSTEXPR void on_text(const Char*, const Char*) {} @@ -2694,7 +2964,7 @@ class format_string_checker { return context_.check_arg_id(id), id; } FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { -#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +#if FMT_USE_NONTYPE_TEMPLATE_ARGS auto index = get_arg_index_by_name(id); if (index == invalid_arg_index) on_error("named argument is not found"); return context_.check_arg_id(index), index; @@ -2719,10 +2989,19 @@ class format_string_checker { } }; +// Reports a compile-time error if S is not a valid format string. +template ::value)> +FMT_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif +} template ::value), int>> + FMT_ENABLE_IF(is_compile_string::value)> void check_format_string(S format_str) { - FMT_CONSTEXPR auto s = to_string_view(format_str); + FMT_CONSTEXPR auto s = basic_string_view(format_str); using checker = format_string_checker...>; FMT_CONSTEXPR bool invalid_format = @@ -2769,7 +3048,10 @@ struct formatter::value, + enable_if_t<(U == detail::type::string_type || + U == detail::type::cstring_type || + U == detail::type::char_type), + int> = 0> + FMT_CONSTEXPR void set_debug_format() { + specs_.type = presentation_type::debug; + } + template FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const -> decltype(ctx.out()); }; +#define FMT_FORMAT_AS(Type, Base) \ + template \ + struct formatter : formatter { \ + template \ + auto format(Type const& val, FormatContext& ctx) const \ + -> decltype(ctx.out()) { \ + return formatter::format(static_cast(val), ctx); \ + } \ + } + +FMT_FORMAT_AS(signed char, int); +FMT_FORMAT_AS(unsigned char, unsigned); +FMT_FORMAT_AS(short, int); +FMT_FORMAT_AS(unsigned short, unsigned); +FMT_FORMAT_AS(long, long long); +FMT_FORMAT_AS(unsigned long, unsigned long long); +FMT_FORMAT_AS(Char*, const Char*); +FMT_FORMAT_AS(std::basic_string, basic_string_view); +FMT_FORMAT_AS(std::nullptr_t, const void*); +FMT_FORMAT_AS(detail::std_string_view, basic_string_view); + template struct basic_runtime { basic_string_view str; }; +/** A compile-time format string. */ template class basic_format_string { private: basic_string_view str_; @@ -2832,14 +3145,15 @@ template class basic_format_string { template >::value)> - FMT_CONSTEVAL basic_format_string(const S& s) : str_(s) { + FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { static_assert( detail::count< (std::is_base_of>::value && std::is_reference::value)...>() == 0, "passing views as lvalues is disallowed"); #ifdef FMT_HAS_CONSTEVAL - if constexpr (detail::count_named_args() == 0) { + if constexpr (detail::count_named_args() == + detail::count_statically_named_args()) { using checker = detail::format_string_checker...>; detail::parse_format_string(str_, checker(s, {})); @@ -2855,17 +3169,22 @@ template class basic_format_string { #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 // Workaround broken conversion on older gcc. -template using format_string = string_view; -template auto runtime(const S& s) -> basic_string_view> { - return s; -} +template using format_string = string_view; +inline auto runtime(string_view s) -> string_view { return s; } #else template using format_string = basic_format_string...>; -// Creates a runtime format string. -template auto runtime(const S& s) -> basic_runtime> { - return {{s}}; -} +/** + \rst + Creates a runtime format string. + + **Example**:: + + // Check format string at runtime instead of compile-time. + fmt::print(fmt::runtime("{:d}"), "I am not a number"); + \endrst + */ +inline auto runtime(string_view s) -> basic_runtime { return {{s}}; } #endif FMT_API auto vformat(string_view fmt, format_args args) -> std::string; @@ -2878,11 +3197,12 @@ FMT_API auto vformat(string_view fmt, format_args args) -> std::string; **Example**:: #include - std::string message = fmt::format("The answer is {}", 42); + std::string message = fmt::format("The answer is {}.", 42); \endrst */ template -FMT_INLINE auto format(format_string fmt, T&&... args) -> std::string { +FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) + -> std::string { return vformat(fmt, fmt::make_format_args(args...)); } @@ -2892,7 +3212,7 @@ template OutputIt { using detail::get_buffer; auto&& buf = get_buffer(out); - detail::vformat_to(buf, string_view(fmt), args, {}); + detail::vformat_to(buf, fmt, args, {}); return detail::get_iterator(buf); } @@ -2900,7 +3220,7 @@ auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { \rst Formats ``args`` according to specifications in ``fmt``, writes the result to the output iterator ``out`` and returns the iterator past the end of the output - range. + range. `format_to` does not append a terminating null character. **Example**:: @@ -2926,9 +3246,8 @@ template ::value)> auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) -> format_to_n_result { - using buffer = - detail::iterator_buffer; - auto buf = buffer(out, n); + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); detail::vformat_to(buf, fmt, args, {}); return {buf.out(), buf.count()}; } @@ -2938,18 +3257,20 @@ auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` characters of the result to the output iterator ``out`` and returns the total (not truncated) output size and the iterator past the end of the output range. + `format_to_n` does not append a terminating null character. \endrst */ template ::value)> FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, - const T&... args) -> format_to_n_result { + T&&... args) -> format_to_n_result { return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); } /** Returns the number of chars in the output of ``format(fmt, args...)``. */ template -FMT_INLINE auto formatted_size(format_string fmt, T&&... args) -> size_t { +FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, + T&&... args) -> size_t { auto buf = detail::counting_buffer<>(); detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {}); return buf.count(); diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/fmt.license.rst b/Lumos/External/spdlog/include/spdlog/fmt/bundled/fmt.license.rst new file mode 100644 index 000000000..f0ec3db4d --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/fmt.license.rst @@ -0,0 +1,27 @@ +Copyright (c) 2012 - present, Victor Zverovich + +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. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/format-inl.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/format-inl.h index 94a36d1bc..22b1ec8df 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/format-inl.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/format-inl.h @@ -40,21 +40,12 @@ FMT_FUNC void assert_fail(const char* file, int line, const char* message) { std::terminate(); } -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; +FMT_FUNC void throw_format_error(const char* message) { + FMT_THROW(format_error(message)); } -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER FMT_FUNC void format_error_code(detail::buffer& out, int error_code, - string_view message) FMT_NOEXCEPT { + string_view message) noexcept { // Report error code making sure that the output fits into // inline_buffer_size to avoid dynamic memory allocation and potential // bad_alloc. @@ -77,7 +68,7 @@ FMT_FUNC void format_error_code(detail::buffer& out, int error_code, } FMT_FUNC void report_error(format_func func, int error_code, - const char* message) FMT_NOEXCEPT { + const char* message) noexcept { memory_buffer full_message; func(full_message, error_code, message); // Don't use fwrite_fully because the latter may throw. @@ -89,7 +80,8 @@ FMT_FUNC void report_error(format_func func, int error_code, inline void fwrite_fully(const void* ptr, size_t size, size_t count, FILE* stream) { size_t written = std::fwrite(ptr, size, count, stream); - if (written < count) FMT_THROW(system_error(errno, "cannot write to file")); + if (written < count) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); } #ifndef FMT_STATIC_THOUSANDS_SEPARATOR @@ -125,8 +117,8 @@ template FMT_FUNC Char decimal_point_impl(locale_ref) { #endif } // namespace detail -#if !FMT_MSC_VER -FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default; +#if !FMT_MSC_VERSION +FMT_API FMT_FUNC format_error::~format_error() noexcept = default; #endif FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, @@ -137,703 +129,31 @@ FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str, namespace detail { -template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) { - // fallback_uintptr is always stored in little endian. - int i = static_cast(sizeof(void*)) - 1; - while (i > 0 && n.value[i] == 0) --i; - auto char_digits = std::numeric_limits::digits / 4; - return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; -} - -#if __cplusplus < 201703L -template constexpr const char basic_data::digits[][2]; -template constexpr const char basic_data::hex_digits[]; -template constexpr const char basic_data::signs[]; -template constexpr const unsigned basic_data::prefixes[]; -template constexpr const char basic_data::left_padding_shifts[]; -template -constexpr const char basic_data::right_padding_shifts[]; -#endif - -template struct bits { - static FMT_CONSTEXPR_DECL const int value = - static_cast(sizeof(T) * std::numeric_limits::digits); -}; - -class fp; -template fp normalize(fp value); - -// Lower (upper) boundary is a value half way between a floating-point value -// and its predecessor (successor). Boundaries have the same exponent as the -// value so only significands are stored. -struct boundaries { - uint64_t lower; - uint64_t upper; -}; - -// A handmade floating-point number f * pow(2, e). -class fp { - private: - using significand_type = uint64_t; - - template - using is_supported_float = bool_constant; - - public: - significand_type f; - int e; - - // All sizes are in bits. - // Subtract 1 to account for an implicit most significant bit in the - // normalized form. - static FMT_CONSTEXPR_DECL const int double_significand_size = - std::numeric_limits::digits - 1; - static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = - 1ULL << double_significand_size; - static FMT_CONSTEXPR_DECL const int significand_size = - bits::value; - - fp() : f(0), e(0) {} - fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} - - // Constructs fp from an IEEE754 double. It is a template to prevent compile - // errors on platforms where double is not IEEE754. - template explicit fp(Double d) { assign(d); } - - // Assigns d to this and return true iff predecessor is closer than successor. - template ::value)> - bool assign(Float d) { - // Assume float is in the format [sign][exponent][significand]. - using limits = std::numeric_limits; - const int float_significand_size = limits::digits - 1; - const int exponent_size = - bits::value - float_significand_size - 1; // -1 for sign - const uint64_t float_implicit_bit = 1ULL << float_significand_size; - const uint64_t significand_mask = float_implicit_bit - 1; - const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask; - const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; - constexpr bool is_double = sizeof(Float) == sizeof(uint64_t); - auto u = bit_cast>(d); - f = u & significand_mask; - int biased_e = - static_cast((u & exponent_mask) >> float_significand_size); - // Predecessor is closer if d is a normalized power of 2 (f == 0) other than - // the smallest normalized number (biased_e > 1). - bool is_predecessor_closer = f == 0 && biased_e > 1; - if (biased_e != 0) - f += float_implicit_bit; - else - biased_e = 1; // Subnormals use biased exponent 1 (min exponent). - e = biased_e - exponent_bias - float_significand_size; - return is_predecessor_closer; - } - - template ::value)> - bool assign(Float) { - *this = fp(); - return false; - } -}; - -// Normalizes the value converted from double and multiplied by (1 << SHIFT). -template fp normalize(fp value) { - // Handle subnormals. - const auto shifted_implicit_bit = fp::implicit_bit << SHIFT; - while ((value.f & shifted_implicit_bit) == 0) { - value.f <<= 1; - --value.e; - } - // Subtract 1 to account for hidden bit. - const auto offset = - fp::significand_size - fp::double_significand_size - SHIFT - 1; - value.f <<= offset; - value.e -= offset; - return value; -} - -inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; } - -// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. -inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { -#if FMT_USE_INT128 - auto product = static_cast<__uint128_t>(lhs) * rhs; - auto f = static_cast(product >> 64); - return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; -#else - // Multiply 32-bit parts of significands. - uint64_t mask = (1ULL << 32) - 1; - uint64_t a = lhs >> 32, b = lhs & mask; - uint64_t c = rhs >> 32, d = rhs & mask; - uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; - // Compute mid 64-bit of result and round. - uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); - return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); -#endif -} - -inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; } - -// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its -// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. -inline fp get_cached_power(int min_exponent, int& pow10_exponent) { - // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. - // These are generated by support/compute-powers.py. - static constexpr const uint64_t pow10_significands[] = { - 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, - 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, - 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, - 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, - 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, - 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, - 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, - 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, - 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, - 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, - 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, - 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, - 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, - 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, - 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, - 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, - 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, - 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, - 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, - 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, - 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, - 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, - 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, - 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, - 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, - 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, - 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, - 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, - 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, - }; - - // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding - // to significands above. - static constexpr const int16_t pow10_exponents[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, - -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, - -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, - -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, - -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, - 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, - 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, - 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; - - const int shift = 32; - const auto significand = static_cast(data::log10_2_significand); - int index = static_cast( - ((min_exponent + fp::significand_size - 1) * (significand >> shift) + - ((int64_t(1) << shift) - 1)) // ceil - >> 32 // arithmetic shift - ); - // Decimal exponent of the first (smallest) cached power of 10. - const int first_dec_exp = -348; - // Difference between 2 consecutive decimal exponents in cached powers of 10. - const int dec_exp_step = 8; - index = (index - first_dec_exp - 1) / dec_exp_step + 1; - pow10_exponent = first_dec_exp + index * dec_exp_step; - return {pow10_significands[index], pow10_exponents[index]}; -} - -// A simple accumulator to hold the sums of terms in bigint::square if uint128_t -// is not available. -struct accumulator { - uint64_t lower; - uint64_t upper; - - accumulator() : lower(0), upper(0) {} - explicit operator uint32_t() const { return static_cast(lower); } - - void operator+=(uint64_t n) { - lower += n; - if (lower < n) ++upper; - } - void operator>>=(int shift) { - FMT_ASSERT(shift == 32, ""); - (void)shift; - lower = (upper << 32) | (lower >> 32); - upper >>= 32; - } -}; - -class bigint { - private: - // A bigint is stored as an array of bigits (big digits), with bigit at index - // 0 being the least significant one. - using bigit = uint32_t; - using double_bigit = uint64_t; - enum { bigits_capacity = 32 }; - basic_memory_buffer bigits_; - int exp_; - - bigit operator[](int index) const { return bigits_[to_unsigned(index)]; } - bigit& operator[](int index) { return bigits_[to_unsigned(index)]; } - - static FMT_CONSTEXPR_DECL const int bigit_bits = bits::value; - - friend struct formatter; - - void subtract_bigits(int index, bigit other, bigit& borrow) { - auto result = static_cast((*this)[index]) - other - borrow; - (*this)[index] = static_cast(result); - borrow = static_cast(result >> (bigit_bits * 2 - 1)); - } - - void remove_leading_zeros() { - int num_bigits = static_cast(bigits_.size()) - 1; - while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; - bigits_.resize(to_unsigned(num_bigits + 1)); - } - - // Computes *this -= other assuming aligned bigints and *this >= other. - void subtract_aligned(const bigint& other) { - FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); - FMT_ASSERT(compare(*this, other) >= 0, ""); - bigit borrow = 0; - int i = other.exp_ - exp_; - for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) - subtract_bigits(i, other.bigits_[j], borrow); - while (borrow > 0) subtract_bigits(i, 0, borrow); - remove_leading_zeros(); - } - - void multiply(uint32_t value) { - const double_bigit wide_value = value; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - double_bigit result = bigits_[i] * wide_value + carry; - bigits_[i] = static_cast(result); - carry = static_cast(result >> bigit_bits); - } - if (carry != 0) bigits_.push_back(carry); - } - - void multiply(uint64_t value) { - const bigit mask = ~bigit(0); - const double_bigit lower = value & mask; - const double_bigit upper = value >> bigit_bits; - double_bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - double_bigit result = bigits_[i] * lower + (carry & mask); - carry = - bigits_[i] * upper + (result >> bigit_bits) + (carry >> bigit_bits); - bigits_[i] = static_cast(result); - } - while (carry != 0) { - bigits_.push_back(carry & mask); - carry >>= bigit_bits; - } - } - - public: - bigint() : exp_(0) {} - explicit bigint(uint64_t n) { assign(n); } - ~bigint() { FMT_ASSERT(bigits_.capacity() <= bigits_capacity, ""); } - - bigint(const bigint&) = delete; - void operator=(const bigint&) = delete; - - void assign(const bigint& other) { - auto size = other.bigits_.size(); - bigits_.resize(size); - auto data = other.bigits_.data(); - std::copy(data, data + size, make_checked(bigits_.data(), size)); - exp_ = other.exp_; - } - - void assign(uint64_t n) { - size_t num_bigits = 0; - do { - bigits_[num_bigits++] = n & ~bigit(0); - n >>= bigit_bits; - } while (n != 0); - bigits_.resize(num_bigits); - exp_ = 0; - } - - int num_bigits() const { return static_cast(bigits_.size()) + exp_; } - - FMT_NOINLINE bigint& operator<<=(int shift) { - FMT_ASSERT(shift >= 0, ""); - exp_ += shift / bigit_bits; - shift %= bigit_bits; - if (shift == 0) return *this; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - bigit c = bigits_[i] >> (bigit_bits - shift); - bigits_[i] = (bigits_[i] << shift) + carry; - carry = c; - } - if (carry != 0) bigits_.push_back(carry); - return *this; - } - - template bigint& operator*=(Int value) { - FMT_ASSERT(value > 0, ""); - multiply(uint32_or_64_or_128_t(value)); - return *this; - } - - friend int compare(const bigint& lhs, const bigint& rhs) { - int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); - if (num_lhs_bigits != num_rhs_bigits) - return num_lhs_bigits > num_rhs_bigits ? 1 : -1; - int i = static_cast(lhs.bigits_.size()) - 1; - int j = static_cast(rhs.bigits_.size()) - 1; - int end = i - j; - if (end < 0) end = 0; - for (; i >= end; --i, --j) { - bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; - if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; - } - if (i != j) return i > j ? 1 : -1; - return 0; - } - - // Returns compare(lhs1 + lhs2, rhs). - friend int add_compare(const bigint& lhs1, const bigint& lhs2, - const bigint& rhs) { - int max_lhs_bigits = (std::max)(lhs1.num_bigits(), lhs2.num_bigits()); - int num_rhs_bigits = rhs.num_bigits(); - if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; - if (max_lhs_bigits > num_rhs_bigits) return 1; - auto get_bigit = [](const bigint& n, int i) -> bigit { - return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; - }; - double_bigit borrow = 0; - int min_exp = (std::min)((std::min)(lhs1.exp_, lhs2.exp_), rhs.exp_); - for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { - double_bigit sum = - static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); - bigit rhs_bigit = get_bigit(rhs, i); - if (sum > rhs_bigit + borrow) return 1; - borrow = rhs_bigit + borrow - sum; - if (borrow > 1) return -1; - borrow <<= bigit_bits; - } - return borrow != 0 ? -1 : 0; - } - - // Assigns pow(10, exp) to this bigint. - void assign_pow10(int exp) { - FMT_ASSERT(exp >= 0, ""); - if (exp == 0) return assign(1); - // Find the top bit. - int bitmask = 1; - while (exp >= bitmask) bitmask <<= 1; - bitmask >>= 1; - // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by - // repeated squaring and multiplication. - assign(5); - bitmask >>= 1; - while (bitmask != 0) { - square(); - if ((exp & bitmask) != 0) *this *= 5; - bitmask >>= 1; - } - *this <<= exp; // Multiply by pow(2, exp) by shifting. - } - - void square() { - int num_bigits = static_cast(bigits_.size()); - int num_result_bigits = 2 * num_bigits; - basic_memory_buffer n(std::move(bigits_)); - bigits_.resize(to_unsigned(num_result_bigits)); - using accumulator_t = conditional_t; - auto sum = accumulator_t(); - for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { - // Compute bigit at position bigit_index of the result by adding - // cross-product terms n[i] * n[j] such that i + j == bigit_index. - for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { - // Most terms are multiplied twice which can be optimized in the future. - sum += static_cast(n[i]) * n[j]; - } - (*this)[bigit_index] = static_cast(sum); - sum >>= bits::value; // Compute the carry. - } - // Do the same for the top half. - for (int bigit_index = num_bigits; bigit_index < num_result_bigits; - ++bigit_index) { - for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) - sum += static_cast(n[i++]) * n[j--]; - (*this)[bigit_index] = static_cast(sum); - sum >>= bits::value; - } - remove_leading_zeros(); - exp_ *= 2; - } - - // If this bigint has a bigger exponent than other, adds trailing zero to make - // exponents equal. This simplifies some operations such as subtraction. - void align(const bigint& other) { - int exp_difference = exp_ - other.exp_; - if (exp_difference <= 0) return; - int num_bigits = static_cast(bigits_.size()); - bigits_.resize(to_unsigned(num_bigits + exp_difference)); - for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) - bigits_[j] = bigits_[i]; - std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); - exp_ -= exp_difference; - } - - // Divides this bignum by divisor, assigning the remainder to this and - // returning the quotient. - int divmod_assign(const bigint& divisor) { - FMT_ASSERT(this != &divisor, ""); - if (compare(*this, divisor) < 0) return 0; - FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); - align(divisor); - int quotient = 0; - do { - subtract_aligned(divisor); - ++quotient; - } while (compare(*this, divisor) >= 0); - return quotient; - } -}; - -enum class round_direction { unknown, up, down }; - -// Given the divisor (normally a power of 10), the remainder = v % divisor for -// some number v and the error, returns whether v should be rounded up, down, or -// whether the rounding direction can't be determined due to error. -// error should be less than divisor / 2. -inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder, - uint64_t error) { - FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. - FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. - FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. - // Round down if (remainder + error) * 2 <= divisor. - if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) - return round_direction::down; - // Round up if (remainder - error) * 2 >= divisor. - if (remainder >= error && - remainder - error >= divisor - (remainder - error)) { - return round_direction::up; - } - return round_direction::unknown; -} - -namespace digits { -enum result { - more, // Generate more digits. - done, // Done generating digits. - error // Digit generation cancelled due to an error. -}; +template inline bool operator==(basic_fp x, basic_fp y) { + return x.f == y.f && x.e == y.e; } -inline uint64_t power_of_10_64(int exp) { - static constexpr const uint64_t data[] = {1, FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; - return data[exp]; +// Compilers should be able to optimize this into the ror instruction. +FMT_CONSTEXPR inline uint32_t rotr(uint32_t n, uint32_t r) noexcept { + r &= 31; + return (n >> r) | (n << (32 - r)); } - -// Generates output using the Grisu digit-gen algorithm. -// error: the size of the region (lower, upper) outside of which numbers -// definitely do not round to value (Delta in Grisu3). -template -FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, - Handler& handler) { - const fp one(1ULL << -value.e, value.e); - // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be - // zero because it contains a product of two 64-bit numbers with MSB set (due - // to normalization) - 1, shifted right by at most 60 bits. - auto integral = static_cast(value.f >> -one.e); - FMT_ASSERT(integral != 0, ""); - FMT_ASSERT(integral == value.f >> -one.e, ""); - // The fractional part of scaled value (p2 in Grisu) c = value % one. - uint64_t fractional = value.f & (one.f - 1); - exp = count_digits(integral); // kappa in Grisu. - // Divide by 10 to prevent overflow. - auto result = handler.on_start(power_of_10_64(exp - 1) << -one.e, - value.f / 10, error * 10, exp); - if (result != digits::more) return result; - // Generate digits for the integral part. This can produce up to 10 digits. - do { - uint32_t digit = 0; - auto divmod_integral = [&](uint32_t divisor) { - digit = integral / divisor; - integral %= divisor; - }; - // This optimization by Milo Yip reduces the number of integer divisions by - // one per iteration. - switch (exp) { - case 10: - divmod_integral(1000000000); - break; - case 9: - divmod_integral(100000000); - break; - case 8: - divmod_integral(10000000); - break; - case 7: - divmod_integral(1000000); - break; - case 6: - divmod_integral(100000); - break; - case 5: - divmod_integral(10000); - break; - case 4: - divmod_integral(1000); - break; - case 3: - divmod_integral(100); - break; - case 2: - divmod_integral(10); - break; - case 1: - digit = integral; - integral = 0; - break; - default: - FMT_ASSERT(false, "invalid number of digits"); - } - --exp; - auto remainder = (static_cast(integral) << -one.e) + fractional; - result = handler.on_digit(static_cast('0' + digit), - power_of_10_64(exp) << -one.e, remainder, error, - exp, true); - if (result != digits::more) return result; - } while (exp > 0); - // Generate digits for the fractional part. - for (;;) { - fractional *= 10; - error *= 10; - char digit = static_cast('0' + (fractional >> -one.e)); - fractional &= one.f - 1; - --exp; - result = handler.on_digit(digit, one.f, fractional, error, exp, false); - if (result != digits::more) return result; - } +FMT_CONSTEXPR inline uint64_t rotr(uint64_t n, uint32_t r) noexcept { + r &= 63; + return (n >> r) | (n << (64 - r)); } -// The fixed precision digit handler. -struct fixed_handler { - char* buf; - int size; - int precision; - int exp10; - bool fixed; - - digits::result on_start(uint64_t divisor, uint64_t remainder, uint64_t error, - int& exp) { - // Non-fixed formats require at least one digit and no precision adjustment. - if (!fixed) return digits::more; - // Adjust fixed precision by exponent because it is relative to decimal - // point. - precision += exp + exp10; - // Check if precision is satisfied just by leading zeros, e.g. - // format("{:.2f}", 0.001) gives "0.00" without generating any digits. - if (precision > 0) return digits::more; - if (precision < 0) return digits::done; - auto dir = get_round_direction(divisor, remainder, error); - if (dir == round_direction::unknown) return digits::error; - buf[size++] = dir == round_direction::up ? '1' : '0'; - return digits::done; - } - - digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, - uint64_t error, int, bool integral) { - FMT_ASSERT(remainder < divisor, ""); - buf[size++] = digit; - if (!integral && error >= remainder) return digits::error; - if (size < precision) return digits::more; - if (!integral) { - // Check if error * 2 < divisor with overflow prevention. - // The check is not needed for the integral part because error = 1 - // and divisor > (1 << 32) there. - if (error >= divisor || error >= divisor - error) return digits::error; - } else { - FMT_ASSERT(error == 1 && divisor > 2, ""); - } - auto dir = get_round_direction(divisor, remainder, error); - if (dir != round_direction::up) - return dir == round_direction::down ? digits::done : digits::error; - ++buf[size - 1]; - for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] > '9') { - buf[0] = '1'; - if (fixed) - buf[size++] = '0'; - else - ++exp10; - } - return digits::done; - } -}; - -// A 128-bit integer type used internally, -struct uint128_wrapper { - uint128_wrapper() = default; - -#if FMT_USE_INT128 - uint128_t internal_; - - constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT - : internal_{static_cast(low) | - (static_cast(high) << 64)} {} - - constexpr uint128_wrapper(uint128_t u) : internal_{u} {} - - constexpr uint64_t high() const FMT_NOEXCEPT { - return uint64_t(internal_ >> 64); - } - constexpr uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); } - - uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { - internal_ += n; - return *this; - } -#else - uint64_t high_; - uint64_t low_; - - constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT - : high_{high}, - low_{low} {} - - constexpr uint64_t high() const FMT_NOEXCEPT { return high_; } - constexpr uint64_t low() const FMT_NOEXCEPT { return low_; } - - uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT { -# if defined(_MSC_VER) && defined(_M_X64) - unsigned char carry = _addcarry_u64(0, low_, n, &low_); - _addcarry_u64(carry, high_, 0, &high_); - return *this; -# else - uint64_t sum = low_ + n; - high_ += (sum < low_ ? 1 : 0); - low_ = sum; - return *this; -# endif - } -#endif -}; - -// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. -namespace dragonbox { // Computes 128-bit result of multiplication of two 64-bit unsigned integers. -inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT { +inline uint128_fallback umul128(uint64_t x, uint64_t y) noexcept { #if FMT_USE_INT128 - return static_cast(x) * static_cast(y); + auto p = static_cast(x) * static_cast(y); + return {static_cast(p >> 64), static_cast(p)}; #elif defined(_MSC_VER) && defined(_M_X64) - uint128_wrapper result; - result.low_ = _umul128(x, y, &result.high_); + auto result = uint128_fallback(); + result.lo_ = _umul128(x, y, &result.hi_); return result; #else - const uint64_t mask = (uint64_t(1) << 32) - uint64_t(1); + const uint64_t mask = static_cast(max_value()); uint64_t a = x >> 32; uint64_t b = x & mask; @@ -852,10 +172,12 @@ inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT { #endif } +// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +namespace dragonbox { // Computes upper 64 bits of multiplication of two 64-bit unsigned integers. -inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT { +inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept { #if FMT_USE_INT128 - auto p = static_cast(x) * static_cast(y); + auto p = static_cast(x) * static_cast(y); return static_cast(p >> 64); #elif defined(_MSC_VER) && defined(_M_X64) return __umulh(x, y); @@ -864,172 +186,105 @@ inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT { #endif } -// Computes upper 64 bits of multiplication of a 64-bit unsigned integer and a +// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a // 128-bit unsigned integer. -inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { - uint128_wrapper g0 = umul128(x, y.high()); - g0 += umul128_upper64(x, y.low()); - return g0.high(); +inline uint128_fallback umul192_upper128(uint64_t x, + uint128_fallback y) noexcept { + uint128_fallback r = umul128(x, y.high()); + r += umul128_upper64(x, y.low()); + return r; } -// Computes upper 32 bits of multiplication of a 32-bit unsigned integer and a +// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a // 64-bit unsigned integer. -inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT { - return static_cast(umul128_upper64(x, y)); +inline uint64_t umul96_upper64(uint32_t x, uint64_t y) noexcept { + return umul128_upper64(static_cast(x) << 32, y); } -// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a +// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a // 128-bit unsigned integer. -inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT { - uint64_t g01 = x * y.high(); - uint64_t g10 = umul128_upper64(x, y.low()); - return g01 + g10; +inline uint128_fallback umul192_lower128(uint64_t x, + uint128_fallback y) noexcept { + uint64_t high = x * y.high(); + uint128_fallback high_low = umul128(x, y.low()); + return {high + high_low.high(), high_low.low()}; } // Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a // 64-bit unsigned integer. -inline uint64_t umul96_lower64(uint32_t x, uint64_t y) FMT_NOEXCEPT { +inline uint64_t umul96_lower64(uint32_t x, uint64_t y) noexcept { return x * y; } -// Computes floor(log10(pow(2, e))) for e in [-1700, 1700] using the method from -// https://fmt.dev/papers/Grisu-Exact.pdf#page=5, section 3.4. -inline int floor_log10_pow2(int e) FMT_NOEXCEPT { - FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); - const int shift = 22; - return (e * static_cast(data::log10_2_significand >> (64 - shift))) >> - shift; +// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from +// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. +inline int floor_log10_pow2(int e) noexcept { + FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent"); + static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); + return (e * 315653) >> 20; } // Various fast log computations. -inline int floor_log2_pow10(int e) FMT_NOEXCEPT { +inline int floor_log2_pow10(int e) noexcept { FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); - const uint64_t log2_10_integer_part = 3; - const uint64_t log2_10_fractional_digits = 0x5269e12f346e2bf9; - const int shift_amount = 19; - return (e * static_cast( - (log2_10_integer_part << shift_amount) | - (log2_10_fractional_digits >> (64 - shift_amount)))) >> - shift_amount; + return (e * 1741647) >> 19; } -inline int floor_log10_pow2_minus_log10_4_over_3(int e) FMT_NOEXCEPT { - FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent"); - const uint64_t log10_4_over_3_fractional_digits = 0x1ffbfc2bbc780375; - const int shift_amount = 22; - return (e * static_cast(data::log10_2_significand >> - (64 - shift_amount)) - - static_cast(log10_4_over_3_fractional_digits >> - (64 - shift_amount))) >> - shift_amount; +inline int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept { + FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); + return (e * 631305 - 261663) >> 21; } -// Returns true iff x is divisible by pow(2, exp). -inline bool divisible_by_power_of_2(uint32_t x, int exp) FMT_NOEXCEPT { - FMT_ASSERT(exp >= 1, ""); - FMT_ASSERT(x != 0, ""); -#ifdef FMT_BUILTIN_CTZ - return FMT_BUILTIN_CTZ(x) >= exp; -#else - return exp < num_bits() && x == ((x >> exp) << exp); -#endif -} -inline bool divisible_by_power_of_2(uint64_t x, int exp) FMT_NOEXCEPT { - FMT_ASSERT(exp >= 1, ""); - FMT_ASSERT(x != 0, ""); -#ifdef FMT_BUILTIN_CTZLL - return FMT_BUILTIN_CTZLL(x) >= exp; -#else - return exp < num_bits() && x == ((x >> exp) << exp); -#endif -} - -// Table entry type for divisibility test. -template struct divtest_table_entry { - T mod_inv; - T max_quotient; -}; +static constexpr struct { + uint32_t divisor; + int shift_amount; +} div_small_pow10_infos[] = {{10, 16}, {100, 16}}; -// Returns true iff x is divisible by pow(5, exp). -inline bool divisible_by_power_of_5(uint32_t x, int exp) FMT_NOEXCEPT { - FMT_ASSERT(exp <= 10, "too large exponent"); - static constexpr const divtest_table_entry divtest_table[] = { - {0x00000001, 0xffffffff}, {0xcccccccd, 0x33333333}, - {0xc28f5c29, 0x0a3d70a3}, {0x26e978d5, 0x020c49ba}, - {0x3afb7e91, 0x0068db8b}, {0x0bcbe61d, 0x0014f8b5}, - {0x68c26139, 0x000431bd}, {0xae8d46a5, 0x0000d6bf}, - {0x22e90e21, 0x00002af3}, {0x3a2e9c6d, 0x00000897}, - {0x3ed61f49, 0x000001b7}}; - return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; -} -inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT { - FMT_ASSERT(exp <= 23, "too large exponent"); - static constexpr const divtest_table_entry divtest_table[] = { - {0x0000000000000001, 0xffffffffffffffff}, - {0xcccccccccccccccd, 0x3333333333333333}, - {0x8f5c28f5c28f5c29, 0x0a3d70a3d70a3d70}, - {0x1cac083126e978d5, 0x020c49ba5e353f7c}, - {0xd288ce703afb7e91, 0x0068db8bac710cb2}, - {0x5d4e8fb00bcbe61d, 0x0014f8b588e368f0}, - {0x790fb65668c26139, 0x000431bde82d7b63}, - {0xe5032477ae8d46a5, 0x0000d6bf94d5e57a}, - {0xc767074b22e90e21, 0x00002af31dc46118}, - {0x8e47ce423a2e9c6d, 0x0000089705f4136b}, - {0x4fa7f60d3ed61f49, 0x000001b7cdfd9d7b}, - {0x0fee64690c913975, 0x00000057f5ff85e5}, - {0x3662e0e1cf503eb1, 0x000000119799812d}, - {0xa47a2cf9f6433fbd, 0x0000000384b84d09}, - {0x54186f653140a659, 0x00000000b424dc35}, - {0x7738164770402145, 0x0000000024075f3d}, - {0xe4a4d1417cd9a041, 0x000000000734aca5}, - {0xc75429d9e5c5200d, 0x000000000170ef54}, - {0xc1773b91fac10669, 0x000000000049c977}, - {0x26b172506559ce15, 0x00000000000ec1e4}, - {0xd489e3a9addec2d1, 0x000000000002f394}, - {0x90e860bb892c8d5d, 0x000000000000971d}, - {0x502e79bf1b6f4f79, 0x0000000000001e39}, - {0xdcd618596be30fe5, 0x000000000000060b}}; - return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient; -} - -// Replaces n by floor(n / pow(5, N)) returning true if and only if n is -// divisible by pow(5, N). -// Precondition: n <= 2 * pow(5, N + 1). +// Replaces n by floor(n / pow(10, N)) returning true if and only if n is +// divisible by pow(10, N). +// Precondition: n <= pow(10, N + 1). template -bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT { - static constexpr struct { - uint32_t magic_number; - int bits_for_comparison; - uint32_t threshold; - int shift_amount; - } infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}}; - constexpr auto info = infos[N - 1]; - n *= info.magic_number; - const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1; - bool result = (n & comparison_mask) <= info.threshold; +bool check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept { + // The numbers below are chosen such that: + // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100, + // 2. nm mod 2^k < m if and only if n is divisible by d, + // where m is magic_number, k is shift_amount + // and d is divisor. + // + // Item 1 is a common technique of replacing division by a constant with + // multiplication, see e.g. "Division by Invariant Integers Using + // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set + // to ceil(2^k/d) for large enough k. + // The idea for item 2 originates from Schubfach. + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + n *= magic_number; + const uint32_t comparison_mask = (1u << info.shift_amount) - 1; + bool result = (n & comparison_mask) < magic_number; n >>= info.shift_amount; return result; } // Computes floor(n / pow(10, N)) for small n and N. // Precondition: n <= pow(10, N + 1). -template uint32_t small_division_by_pow10(uint32_t n) FMT_NOEXCEPT { - static constexpr struct { - uint32_t magic_number; - int shift_amount; - uint32_t divisor_times_10; - } infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}}; - constexpr auto info = infos[N - 1]; - FMT_ASSERT(n <= info.divisor_times_10, "n is too large"); - return n * info.magic_number >> info.shift_amount; +template uint32_t small_division_by_pow10(uint32_t n) noexcept { + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + return (n * magic_number) >> info.shift_amount; } // Computes floor(n / 10^(kappa + 1)) (float) -inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) FMT_NOEXCEPT { - return n / float_info::big_divisor; +inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) noexcept { + // 1374389535 = ceil(2^37/100) + return static_cast((static_cast(n) * 1374389535) >> 37); } // Computes floor(n / 10^(kappa + 1)) (double) -inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) FMT_NOEXCEPT { - return umul128_upper64(n, 0x83126e978d4fdf3c) >> 9; +inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) noexcept { + // 2361183241434822607 = ceil(2^(64+7)/1000) + return umul128_upper64(n, 2361183241434822607ull) >> 7; } // Various subroutines using pow10 cache @@ -1039,10 +294,10 @@ template <> struct cache_accessor { using carrier_uint = float_info::carrier_uint; using cache_entry_type = uint64_t; - static uint64_t get_cached_power(int k) FMT_NOEXCEPT { + static uint64_t get_cached_power(int k) noexcept { FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, "k is out of range"); - constexpr const uint64_t pow10_significands[] = { + static constexpr const uint64_t pow10_significands[] = { 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, @@ -1062,54 +317,65 @@ template <> struct cache_accessor { 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, - 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984, - 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, 0xfc6f7c4045812296, - 0x9dc5ada82b70b59d, 0xc5371912364ce305, 0xf684df56c3e01bc6, - 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20, - 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd, - 0x92efd1b8d0cf37be, 0xb7abc627050305ad, 0xe596b7b0c643c719, - 0x8f7e32ce7bea5c6f, 0xb35dbf821ae4f38b, 0xe0352f62a19e306e}; + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985, + 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, + 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7, + 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21, + 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, + 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; return pow10_significands[k - float_info::min_k]; } - static carrier_uint compute_mul(carrier_uint u, - const cache_entry_type& cache) FMT_NOEXCEPT { - return umul96_upper32(u, cache); + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static compute_mul_result compute_mul( + carrier_uint u, const cache_entry_type& cache) noexcept { + auto r = umul96_upper64(u, cache); + return {static_cast(r >> 32), + static_cast(r) == 0}; } static uint32_t compute_delta(const cache_entry_type& cache, - int beta_minus_1) FMT_NOEXCEPT { - return static_cast(cache >> (64 - 1 - beta_minus_1)); + int beta) noexcept { + return static_cast(cache >> (64 - 1 - beta)); } - static bool compute_mul_parity(carrier_uint two_f, - const cache_entry_type& cache, - int beta_minus_1) FMT_NOEXCEPT { - FMT_ASSERT(beta_minus_1 >= 1, ""); - FMT_ASSERT(beta_minus_1 < 64, ""); + static compute_mul_parity_result compute_mul_parity( + carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); - return ((umul96_lower64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0; + auto r = umul96_lower64(two_f, cache); + return {((r >> (64 - beta)) & 1) != 0, + static_cast(r >> (32 - beta)) == 0}; } static carrier_uint compute_left_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + const cache_entry_type& cache, int beta) noexcept { return static_cast( - (cache - (cache >> (float_info::significand_bits + 2))) >> - (64 - float_info::significand_bits - 1 - beta_minus_1)); + (cache - (cache >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta)); } static carrier_uint compute_right_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + const cache_entry_type& cache, int beta) noexcept { return static_cast( - (cache + (cache >> (float_info::significand_bits + 1))) >> - (64 - float_info::significand_bits - 1 - beta_minus_1)); + (cache + (cache >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta)); } static carrier_uint compute_round_up_for_shorter_interval_case( - const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + const cache_entry_type& cache, int beta) noexcept { return (static_cast( - cache >> - (64 - float_info::significand_bits - 2 - beta_minus_1)) + + cache >> (64 - num_significand_bits() - 2 - beta)) + 1) / 2; } @@ -1117,13 +383,13 @@ template <> struct cache_accessor { template <> struct cache_accessor { using carrier_uint = float_info::carrier_uint; - using cache_entry_type = uint128_wrapper; + using cache_entry_type = uint128_fallback; - static uint128_wrapper get_cached_power(int k) FMT_NOEXCEPT { + static uint128_fallback get_cached_power(int k) noexcept { FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, "k is out of range"); - static constexpr const uint128_wrapper pow10_significands[] = { + static constexpr const uint128_fallback pow10_significands[] = { #if FMT_USE_FULL_CACHE_DRAGONBOX {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, {0x9faacf3df73609b1, 0x77b191618c54e9ad}, @@ -1473,278 +739,278 @@ template <> struct cache_accessor { {0x85a36366eb71f041, 0x47a6da2b7f864750}, {0xa70c3c40a64e6c51, 0x999090b65f67d924}, {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, - {0x82818f1281ed449f, 0xbff8f10e7a8921a4}, - {0xa321f2d7226895c7, 0xaff72d52192b6a0d}, - {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490}, - {0xfee50b7025c36a08, 0x02f236d04753d5b4}, - {0x9f4f2726179a2245, 0x01d762422c946590}, - {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5}, - {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2}, - {0x9b934c3b330c8577, 0x63cc55f49f88eb2f}, - {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb}, - {0xf316271c7fc3908a, 0x8bef464e3945ef7a}, - {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac}, - {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317}, - {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd}, - {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a}, - {0xb975d6b6ee39e436, 0xb3e2fd538e122b44}, - {0xe7d34c64a9c85d44, 0x60dbbca87196b616}, - {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd}, - {0xb51d13aea4a488dd, 0x6babab6398bdbe41}, - {0xe264589a4dcdab14, 0xc696963c7eed2dd1}, - {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2}, - {0xb0de65388cc8ada8, 0x3b25a55f43294bcb}, - {0xdd15fe86affad912, 0x49ef0eb713f39ebe}, - {0x8a2dbf142dfcc7ab, 0x6e3569326c784337}, - {0xacb92ed9397bf996, 0x49c2c37f07965404}, - {0xd7e77a8f87daf7fb, 0xdc33745ec97be906}, - {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3}, - {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c}, - {0xd2d80db02aabd62b, 0xf50a3fa490c30190}, - {0x83c7088e1aab65db, 0x792667c6da79e0fa}, - {0xa4b8cab1a1563f52, 0x577001b891185938}, - {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, - {0x80b05e5ac60b6178, 0x544f8158315b05b4}, - {0xa0dc75f1778e39d6, 0x696361ae3db1c721}, - {0xc913936dd571c84c, 0x03bc3a19cd1e38e9}, - {0xfb5878494ace3a5f, 0x04ab48a04065c723}, - {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76}, - {0xc45d1df942711d9a, 0x3ba5d0bd324f8394}, - {0xf5746577930d6500, 0xca8f44ec7ee36479}, - {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb}, - {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e}, - {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e}, - {0x95d04aee3b80ece5, 0xbba1f1d158724a12}, - {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97}, - {0xea1575143cf97226, 0xf52d09d71a3293bd}, - {0x924d692ca61be758, 0x593c2626705f9c56}, - {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c}, - {0xe498f455c38b997a, 0x0b6dfb9c0f956447}, - {0x8edf98b59a373fec, 0x4724bd4189bd5eac}, - {0xb2977ee300c50fe7, 0x58edec91ec2cb657}, - {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed}, - {0x8b865b215899f46c, 0xbd79e0d20082ee74}, - {0xae67f1e9aec07187, 0xecd8590680a3aa11}, - {0xda01ee641a708de9, 0xe80e6f4820cc9495}, - {0x884134fe908658b2, 0x3109058d147fdcdd}, - {0xaa51823e34a7eede, 0xbd4b46f0599fd415}, - {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a}, - {0x850fadc09923329e, 0x03e2cf6bc604ddb0}, - {0xa6539930bf6bff45, 0x84db8346b786151c}, - {0xcfe87f7cef46ff16, 0xe612641865679a63}, - {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e}, - {0xa26da3999aef7749, 0xe3be5e330f38f09d}, - {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5}, - {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6}, - {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa}, - {0xc646d63501a1511d, 0xb281e1fd541501b8}, - {0xf7d88bc24209a565, 0x1f225a7ca91a4226}, - {0x9ae757596946075f, 0x3375788de9b06958}, - {0xc1a12d2fc3978937, 0x0052d6b1641c83ae}, - {0xf209787bb47d6b84, 0xc0678c5dbd23a49a}, - {0x9745eb4d50ce6332, 0xf840b7ba963646e0}, - {0xbd176620a501fbff, 0xb650e5a93bc3d898}, - {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe}, - {0x93ba47c980e98cdf, 0xc66f336c36b10137}, - {0xb8a8d9bbe123f017, 0xb80b0047445d4184}, - {0xe6d3102ad96cec1d, 0xa60dc059157491e5}, - {0x9043ea1ac7e41392, 0x87c89837ad68db2f}, - {0xb454e4a179dd1877, 0x29babe4598c311fb}, - {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a}, - {0x8ce2529e2734bb1d, 0x1899e4a65f58660c}, - {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f}, - {0xdc21a1171d42645d, 0x76707543f4fa1f73}, - {0x899504ae72497eba, 0x6a06494a791c53a8}, - {0xabfa45da0edbde69, 0x0487db9d17636892}, - {0xd6f8d7509292d603, 0x45a9d2845d3c42b6}, - {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, - {0xa7f26836f282b732, 0x8e6cac7768d7141e}, - {0xd1ef0244af2364ff, 0x3207d795430cd926}, - {0x8335616aed761f1f, 0x7f44e6bd49e807b8}, - {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6}, - {0xcd036837130890a1, 0x36dba887c37a8c0f}, - {0x802221226be55a64, 0xc2494954da2c9789}, - {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c}, - {0xc83553c5c8965d3d, 0x6f92829494e5acc7}, - {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9}, - {0x9c69a97284b578d7, 0xff2a760414536efb}, - {0xc38413cf25e2d70d, 0xfef5138519684aba}, - {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69}, - {0x98bf2f79d5993802, 0xef2f773ffbd97a61}, - {0xbeeefb584aff8603, 0xaafb550ffacfd8fa}, - {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38}, - {0x952ab45cfa97a0b2, 0xdd945a747bf26183}, - {0xba756174393d88df, 0x94f971119aeef9e4}, - {0xe912b9d1478ceb17, 0x7a37cd5601aab85d}, - {0x91abb422ccb812ee, 0xac62e055c10ab33a}, - {0xb616a12b7fe617aa, 0x577b986b314d6009}, - {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b}, - {0x8e41ade9fbebc27d, 0x14588f13be847307}, - {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8}, - {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb}, - {0x8aec23d680043bee, 0x25de7bb9480d5854}, - {0xada72ccc20054ae9, 0xaf561aa79a10ae6a}, - {0xd910f7ff28069da4, 0x1b2ba1518094da04}, - {0x87aa9aff79042286, 0x90fb44d2f05d0842}, - {0xa99541bf57452b28, 0x353a1607ac744a53}, - {0xd3fa922f2d1675f2, 0x42889b8997915ce8}, - {0x847c9b5d7c2e09b7, 0x69956135febada11}, - {0xa59bc234db398c25, 0x43fab9837e699095}, - {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb}, - {0x8161afb94b44f57d, 0x1d1be0eebac278f5}, - {0xa1ba1ba79e1632dc, 0x6462d92a69731732}, - {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe}, - {0xfcb2cb35e702af78, 0x5cda735244c3d43e}, - {0x9defbf01b061adab, 0x3a0888136afa64a7}, - {0xc56baec21c7a1916, 0x088aaa1845b8fdd0}, - {0xf6c69a72a3989f5b, 0x8aad549e57273d45}, - {0x9a3c2087a63f6399, 0x36ac54e2f678864b}, - {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd}, - {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5}, - {0x969eb7c47859e743, 0x9f644ae5a4b1b325}, - {0xbc4665b596706114, 0x873d5d9f0dde1fee}, - {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea}, - {0x9316ff75dd87cbd8, 0x09a7f12442d588f2}, - {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f}, - {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa}, - {0x8fa475791a569d10, 0xf96e017d694487bc}, - {0xb38d92d760ec4455, 0x37c981dcc395a9ac}, - {0xe070f78d3927556a, 0x85bbe253f47b1417}, - {0x8c469ab843b89562, 0x93956d7478ccec8e}, - {0xaf58416654a6babb, 0x387ac8d1970027b2}, - {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e}, - {0x88fcf317f22241e2, 0x441fece3bdf81f03}, - {0xab3c2fddeeaad25a, 0xd527e81cad7626c3}, - {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074}, - {0x85c7056562757456, 0xf6872d5667844e49}, - {0xa738c6bebb12d16c, 0xb428f8ac016561db}, - {0xd106f86e69d785c7, 0xe13336d701beba52}, - {0x82a45b450226b39c, 0xecc0024661173473}, - {0xa34d721642b06084, 0x27f002d7f95d0190}, - {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4}, - {0xff290242c83396ce, 0x7e67047175a15271}, - {0x9f79a169bd203e41, 0x0f0062c6e984d386}, - {0xc75809c42c684dd1, 0x52c07b78a3e60868}, - {0xf92e0c3537826145, 0xa7709a56ccdf8a82}, - {0x9bbcc7a142b17ccb, 0x88a66076400bb691}, - {0xc2abf989935ddbfe, 0x6acff893d00ea435}, - {0xf356f7ebf83552fe, 0x0583f6b8c4124d43}, - {0x98165af37b2153de, 0xc3727a337a8b704a}, - {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c}, - {0xeda2ee1c7064130c, 0x1162def06f79df73}, - {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8}, - {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692}, - {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437}, - {0x910ab1d4db9914a0, 0x1d9c9892400a22a2}, - {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b}, - {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d}, - {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, - {0xb10d8e1456105dad, 0x7425a83e872c5f47}, - {0xdd50f1996b947518, 0xd12f124e28f77719}, - {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f}, - {0xace73cbfdc0bfb7b, 0x636cc64d1001550b}, - {0xd8210befd30efa5a, 0x3c47f7e05401aa4e}, - {0x8714a775e3e95c78, 0x65acfaec34810a71}, - {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d}, - {0xd31045a8341ca07c, 0x1ede48111209a050}, - {0x83ea2b892091e44d, 0x934aed0aab460432}, - {0xa4e4b66b68b65d60, 0xf81da84d5617853f}, - {0xce1de40642e3f4b9, 0x36251260ab9d668e}, - {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019}, - {0xa1075a24e4421730, 0xb24cf65b8612f81f}, - {0xc94930ae1d529cfc, 0xdee033f26797b627}, - {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1}, - {0x9d412e0806e88aa5, 0x8e1f289560ee864e}, - {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2}, - {0xf5b5d7ec8acb58a2, 0xae10af696774b1db}, - {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29}, - {0xbff610b0cc6edd3f, 0x17fd090a58d32af3}, - {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0}, - {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e}, - {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1}, - {0xea53df5fd18d5513, 0x84c86189216dc5ed}, - {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4}, - {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1}, - {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, - {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e}, - {0xb2c71d5bca9023f8, 0x743e20e9ef511012}, - {0xdf78e4b2bd342cf6, 0x914da9246b255416}, - {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e}, - {0xae9672aba3d0c320, 0xa184ac2473b529b1}, - {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e}, - {0x8865899617fb1871, 0x7e2fa67c7a658892}, - {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7}, - {0xd51ea6fa85785631, 0x552a74227f3ea565}, - {0x8533285c936b35de, 0xd53a88958f87275f}, - {0xa67ff273b8460356, 0x8a892abaf368f137}, - {0xd01fef10a657842c, 0x2d2b7569b0432d85}, - {0x8213f56a67f6b29b, 0x9c3b29620e29fc73}, - {0xa298f2c501f45f42, 0x8349f3ba91b47b8f}, - {0xcb3f2f7642717713, 0x241c70a936219a73}, - {0xfe0efb53d30dd4d7, 0xed238cd383aa0110}, - {0x9ec95d1463e8a506, 0xf4363804324a40aa}, - {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5}, - {0xf81aa16fdc1b81da, 0xdd94b7868e94050a}, - {0x9b10a4e5e9913128, 0xca7cf2b4191c8326}, - {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0}, - {0xf24a01a73cf2dccf, 0xbc633b39673c8cec}, - {0x976e41088617ca01, 0xd5be0503e085d813}, - {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18}, - {0xec9c459d51852ba2, 0xddf8e7d60ed1219e}, - {0x93e1ab8252f33b45, 0xcabb90e5c942b503}, - {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, - {0xe7109bfba19c0c9d, 0x0cc512670a783ad4}, - {0x906a617d450187e2, 0x27fb2b80668b24c5}, - {0xb484f9dc9641e9da, 0xb1f9f660802dedf6}, - {0xe1a63853bbd26451, 0x5e7873f8a0396973}, - {0x8d07e33455637eb2, 0xdb0b487b6423e1e8}, - {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62}, - {0xdc5c5301c56b75f7, 0x7641a140cc7810fb}, - {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d}, - {0xac2820d9623bf429, 0x546345fa9fbdcd44}, - {0xd732290fbacaf133, 0xa97c177947ad4095}, - {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d}, - {0xa81f301449ee8c70, 0x5c68f256bfff5a74}, - {0xd226fc195c6a2f8c, 0x73832eec6fff3111}, - {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab}, - {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55}, - {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb}, - {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3}, - {0xa0555e361951c366, 0xd7e105bcc332621f}, - {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7}, - {0xfa856334878fc150, 0xb14f98f6f0feb951}, - {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3}, - {0xc3b8358109e84f07, 0x0a862f80ec4700c8}, - {0xf4a642e14c6262c8, 0xcd27bb612758c0fa}, - {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c}, - {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3}, - {0xeeea5d5004981478, 0x1858ccfce06cac74}, - {0x95527a5202df0ccb, 0x0f37801e0c43ebc8}, - {0xbaa718e68396cffd, 0xd30560258f54e6ba}, - {0xe950df20247c83fd, 0x47c6b82ef32a2069}, - {0x91d28b7416cdd27e, 0x4cdc331d57fa5441}, - {0xb6472e511c81471d, 0xe0133fe4adf8e952}, - {0xe3d8f9e563a198e5, 0x58180fddd97723a6}, - {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648}, - {0xb201833b35d63f73, 0x2cd2cc6551e513da}, - {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1}, - {0x8b112e86420f6191, 0xfb04afaf27faf782}, - {0xadd57a27d29339f6, 0x79c5db9af1f9b563}, - {0xd94ad8b1c7380874, 0x18375281ae7822bc}, - {0x87cec76f1c830548, 0x8f2293910d0b15b5}, - {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22}, - {0xd433179d9c8cb841, 0x5fa60692a46151eb}, - {0x849feec281d7f328, 0xdbc7c41ba6bcd333}, - {0xa5c7ea73224deff3, 0x12b9b522906c0800}, - {0xcf39e50feae16bef, 0xd768226b34870a00}, - {0x81842f29f2cce375, 0xe6a1158300d46640}, - {0xa1e53af46f801c53, 0x60495ae3c1097fd0}, - {0xca5e89b18b602368, 0x385bb19cb14bdfc4}, - {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5}, - {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1}, - {0xc5a05277621be293, 0xc7098b7305241885}, + {0x82818f1281ed449f, 0xbff8f10e7a8921a5}, + {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, + {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, + {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, + {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, + {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, + {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, + {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, + {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, + {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, + {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, + {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, + {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, + {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, + {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, + {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, + {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, + {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, + {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, + {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, + {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, + {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, + {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, + {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, + {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, + {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, + {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, + {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, + {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, + {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, + {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, + {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, + {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, + {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, + {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, + {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, + {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, + {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, + {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, + {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, + {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, + {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, + {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, + {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, + {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, + {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, + {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, + {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, + {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, + {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, + {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, + {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, + {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, + {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, + {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, + {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, + {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, + {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, + {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, + {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, + {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, + {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, + {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, + {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, + {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, + {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, + {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, + {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, + {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, + {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, + {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, + {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, + {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, + {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, + {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, + {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, + {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, + {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, + {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, + {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, + {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, + {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, + {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, + {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, + {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, + {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, + {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, + {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, + {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, + {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, + {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, + {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, + {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, + {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, + {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, + {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, + {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, + {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, + {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, + {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, + {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, + {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, + {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, + {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, + {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, + {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, + {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, + {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, + {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, + {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, + {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, + {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, + {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, + {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, + {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, + {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, + {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, + {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, + {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, + {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, + {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, + {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, + {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, + {0xc5a05277621be293, 0xc7098b7305241886}, { 0xf70867153aa2db38, - 0xb8cbee4fc66d1ea7 } + 0xb8cbee4fc66d1ea8 } #else {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, @@ -1759,17 +1025,17 @@ template <> struct cache_accessor { {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, {0xc350000000000000, 0x0000000000000000}, {0x9dc5ada82b70b59d, 0xf020000000000000}, - {0xfee50b7025c36a08, 0x02f236d04753d5b4}, - {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86}, - {0xa6539930bf6bff45, 0x84db8346b786151c}, - {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2}, - {0xd910f7ff28069da4, 0x1b2ba1518094da04}, - {0xaf58416654a6babb, 0x387ac8d1970027b2}, - {0x8da471a9de737e24, 0x5ceaecfed289e5d2}, - {0xe4d5e82392a40515, 0x0fabaf3feaa5334a}, - {0xb8da1662e7b00a17, 0x3d6a751f3b936243}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, { 0x95527a5202df0ccb, - 0x0f37801e0c43ebc8 } + 0x0f37801e0c43ebc9 } #endif }; @@ -1787,15 +1053,6 @@ template <> struct cache_accessor { 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; - static constexpr const uint32_t pow10_recovery_errors[] = { - 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 0x00000001, - 0x50000000, 0x00104000, 0x54010004, 0x05004001, 0x55555544, 0x41545555, - 0x54040551, 0x15445545, 0x51555514, 0x10000015, 0x00101100, 0x01100015, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04450514, 0x45414110, - 0x55555145, 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454, - 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 0x55551014, - 0x69514555, 0x05151109, 0x00155555}; - static const int compression_ratio = 27; // Compute base index. @@ -1804,7 +1061,7 @@ template <> struct cache_accessor { int offset = k - kb; // Get base cache. - uint128_wrapper base_cache = pow10_significands[cache_index]; + uint128_fallback base_cache = pow10_significands[cache_index]; if (offset == 0) return base_cache; // Compute the required amount of bit-shift. @@ -1813,9 +1070,8 @@ template <> struct cache_accessor { // Try to recover the real cache. uint64_t pow5 = powers_of_5_64[offset]; - uint128_wrapper recovered_cache = umul128(base_cache.high(), pow5); - uint128_wrapper middle_low = - umul128(base_cache.low() - (kb < 0 ? 1u : 0u), pow5); + uint128_fallback recovered_cache = umul128(base_cache.high(), pow5); + uint128_fallback middle_low = umul128(base_cache.low(), pow5); recovered_cache += middle_low.high(); @@ -1823,60 +1079,60 @@ template <> struct cache_accessor { uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); recovered_cache = - uint128_wrapper{(recovered_cache.low() >> alpha) | high_to_middle, - ((middle_low.low() >> alpha) | middle_to_low)}; - - if (kb < 0) recovered_cache += 1; - - // Get error. - int error_idx = (k - float_info::min_k) / 16; - uint32_t error = (pow10_recovery_errors[error_idx] >> - ((k - float_info::min_k) % 16) * 2) & - 0x3; - - // Add the error back. - FMT_ASSERT(recovered_cache.low() + error >= recovered_cache.low(), ""); - return {recovered_cache.high(), recovered_cache.low() + error}; + uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle, + ((middle_low.low() >> alpha) | middle_to_low)}; + FMT_ASSERT(recovered_cache.low() + 1 != 0, ""); + return {recovered_cache.high(), recovered_cache.low() + 1}; #endif } - static carrier_uint compute_mul(carrier_uint u, - const cache_entry_type& cache) FMT_NOEXCEPT { - return umul192_upper64(u, cache); + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static compute_mul_result compute_mul( + carrier_uint u, const cache_entry_type& cache) noexcept { + auto r = umul192_upper128(u, cache); + return {r.high(), r.low() == 0}; } static uint32_t compute_delta(cache_entry_type const& cache, - int beta_minus_1) FMT_NOEXCEPT { - return static_cast(cache.high() >> (64 - 1 - beta_minus_1)); + int beta) noexcept { + return static_cast(cache.high() >> (64 - 1 - beta)); } - static bool compute_mul_parity(carrier_uint two_f, - const cache_entry_type& cache, - int beta_minus_1) FMT_NOEXCEPT { - FMT_ASSERT(beta_minus_1 >= 1, ""); - FMT_ASSERT(beta_minus_1 < 64, ""); + static compute_mul_parity_result compute_mul_parity( + carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); - return ((umul192_middle64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0; + auto r = umul192_lower128(two_f, cache); + return {((r.high() >> (64 - beta)) & 1) != 0, + ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; } static carrier_uint compute_left_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + const cache_entry_type& cache, int beta) noexcept { return (cache.high() - - (cache.high() >> (float_info::significand_bits + 2))) >> - (64 - float_info::significand_bits - 1 - beta_minus_1); + (cache.high() >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta); } static carrier_uint compute_right_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { + const cache_entry_type& cache, int beta) noexcept { return (cache.high() + - (cache.high() >> (float_info::significand_bits + 1))) >> - (64 - float_info::significand_bits - 1 - beta_minus_1); + (cache.high() >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta); } static carrier_uint compute_round_up_for_shorter_interval_case( - const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT { - return ((cache.high() >> - (64 - float_info::significand_bits - 2 - beta_minus_1)) + + const cache_entry_type& cache, int beta) noexcept { + return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + 1) / 2; } @@ -1884,166 +1140,104 @@ template <> struct cache_accessor { // Various integer checks template -bool is_left_endpoint_integer_shorter_interval(int exponent) FMT_NOEXCEPT { - return exponent >= - float_info< - T>::case_shorter_interval_left_endpoint_lower_threshold && - exponent <= - float_info::case_shorter_interval_left_endpoint_upper_threshold; -} -template -bool is_endpoint_integer(typename float_info::carrier_uint two_f, - int exponent, int minus_k) FMT_NOEXCEPT { - if (exponent < float_info::case_fc_pm_half_lower_threshold) return false; - // For k >= 0. - if (exponent <= float_info::case_fc_pm_half_upper_threshold) return true; - // For k < 0. - if (exponent > float_info::divisibility_check_by_5_threshold) return false; - return divisible_by_power_of_5(two_f, minus_k); -} - -template -bool is_center_integer(typename float_info::carrier_uint two_f, int exponent, - int minus_k) FMT_NOEXCEPT { - // Exponent for 5 is negative. - if (exponent > float_info::divisibility_check_by_5_threshold) return false; - if (exponent > float_info::case_fc_upper_threshold) - return divisible_by_power_of_5(two_f, minus_k); - // Both exponents are nonnegative. - if (exponent >= float_info::case_fc_lower_threshold) return true; - // Exponent for 2 is negative. - return divisible_by_power_of_2(two_f, minus_k - exponent + 1); +bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept { + const int case_shorter_interval_left_endpoint_lower_threshold = 2; + const int case_shorter_interval_left_endpoint_upper_threshold = 3; + return exponent >= case_shorter_interval_left_endpoint_lower_threshold && + exponent <= case_shorter_interval_left_endpoint_upper_threshold; } // Remove trailing zeros from n and return the number of zeros removed (float) -FMT_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT { -#ifdef FMT_BUILTIN_CTZ - int t = FMT_BUILTIN_CTZ(n); -#else - int t = ctz(n); -#endif - if (t > float_info::max_trailing_zeros) - t = float_info::max_trailing_zeros; - - const uint32_t mod_inv1 = 0xcccccccd; - const uint32_t max_quotient1 = 0x33333333; - const uint32_t mod_inv2 = 0xc28f5c29; - const uint32_t max_quotient2 = 0x0a3d70a3; +FMT_INLINE int remove_trailing_zeros(uint32_t& n) noexcept { + FMT_ASSERT(n != 0, ""); + const uint32_t mod_inv_5 = 0xcccccccd; + const uint32_t mod_inv_25 = mod_inv_5 * mod_inv_5; int s = 0; - for (; s < t - 1; s += 2) { - if (n * mod_inv2 > max_quotient2) break; - n *= mod_inv2; + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; } - if (s < t && n * mod_inv1 <= max_quotient1) { - n *= mod_inv1; - ++s; + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; } - n >>= s; + return s; } // Removes trailing zeros and returns the number of zeros removed (double) -FMT_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT { -#ifdef FMT_BUILTIN_CTZLL - int t = FMT_BUILTIN_CTZLL(n); -#else - int t = ctzll(n); -#endif - if (t > float_info::max_trailing_zeros) - t = float_info::max_trailing_zeros; - // Divide by 10^8 and reduce to 32-bits - // Since ret_value.significand <= (2^64 - 1) / 1000 < 10^17, - // both of the quotient and the r should fit in 32-bits - - const uint32_t mod_inv1 = 0xcccccccd; - const uint32_t max_quotient1 = 0x33333333; - const uint64_t mod_inv8 = 0xc767074b22e90e21; - const uint64_t max_quotient8 = 0x00002af31dc46118; - - // If the number is divisible by 1'0000'0000, work with the quotient - if (t >= 8) { - auto quotient_candidate = n * mod_inv8; - - if (quotient_candidate <= max_quotient8) { - auto quotient = static_cast(quotient_candidate >> 8); - - int s = 8; - for (; s < t; ++s) { - if (quotient * mod_inv1 > max_quotient1) break; - quotient *= mod_inv1; - } - quotient >>= (s - 8); - n = quotient; - return s; +FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { + FMT_ASSERT(n != 0, ""); + + // This magic number is ceil(2^90 / 10^8). + constexpr uint64_t magic_number = 12379400392853802749ull; + auto nm = umul128(n, magic_number); + + // Is n is divisible by 10^8? + if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) { + // If yes, work with the quotient. + auto n32 = static_cast(nm.high() >> (90 - 64)); + + const uint32_t mod_inv_5 = 0xcccccccd; + const uint32_t mod_inv_25 = mod_inv_5 * mod_inv_5; + + int s = 8; + while (true) { + auto q = rotr(n32 * mod_inv_25, 2); + if (q > max_value() / 100) break; + n32 = q; + s += 2; + } + auto q = rotr(n32 * mod_inv_5, 1); + if (q <= max_value() / 10) { + n32 = q; + s |= 1; } - } - - // Otherwise, work with the remainder - auto quotient = static_cast(n / 100000000); - auto remainder = static_cast(n - 100000000 * quotient); - - if (t == 0 || remainder * mod_inv1 > max_quotient1) { - return 0; - } - remainder *= mod_inv1; - - if (t == 1 || remainder * mod_inv1 > max_quotient1) { - n = (remainder >> 1) + quotient * 10000000ull; - return 1; - } - remainder *= mod_inv1; - - if (t == 2 || remainder * mod_inv1 > max_quotient1) { - n = (remainder >> 2) + quotient * 1000000ull; - return 2; - } - remainder *= mod_inv1; - if (t == 3 || remainder * mod_inv1 > max_quotient1) { - n = (remainder >> 3) + quotient * 100000ull; - return 3; + n = n32; + return s; } - remainder *= mod_inv1; - if (t == 4 || remainder * mod_inv1 > max_quotient1) { - n = (remainder >> 4) + quotient * 10000ull; - return 4; - } - remainder *= mod_inv1; + // If n is not divisible by 10^8, work with n itself. + const uint64_t mod_inv_5 = 0xcccccccccccccccd; + const uint64_t mod_inv_25 = mod_inv_5 * mod_inv_5; - if (t == 5 || remainder * mod_inv1 > max_quotient1) { - n = (remainder >> 5) + quotient * 1000ull; - return 5; + int s = 0; + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; } - remainder *= mod_inv1; - - if (t == 6 || remainder * mod_inv1 > max_quotient1) { - n = (remainder >> 6) + quotient * 100ull; - return 6; + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; } - remainder *= mod_inv1; - n = (remainder >> 7) + quotient * 10ull; - return 7; + return s; } // The main algorithm for shorter interval case template -FMT_INLINE decimal_fp shorter_interval_case(int exponent) FMT_NOEXCEPT { +FMT_INLINE decimal_fp shorter_interval_case(int exponent) noexcept { decimal_fp ret_value; // Compute k and beta const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); - const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k); + const int beta = exponent + floor_log2_pow10(-minus_k); // Compute xi and zi using cache_entry_type = typename cache_accessor::cache_entry_type; const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( - cache, beta_minus_1); + cache, beta); auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( - cache, beta_minus_1); + cache, beta); // If the left endpoint is not an integer, increase it if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; @@ -2060,8 +1254,8 @@ FMT_INLINE decimal_fp shorter_interval_case(int exponent) FMT_NOEXCEPT { // Otherwise, compute the round-up of y ret_value.significand = - cache_accessor::compute_round_up_for_shorter_interval_case( - cache, beta_minus_1); + cache_accessor::compute_round_up_for_shorter_interval_case(cache, + beta); ret_value.exponent = minus_k; // When tie occurs, choose one of them according to the rule @@ -2076,7 +1270,7 @@ FMT_INLINE decimal_fp shorter_interval_case(int exponent) FMT_NOEXCEPT { return ret_value; } -template decimal_fp to_decimal(T x) FMT_NOEXCEPT { +template decimal_fp to_decimal(T x) noexcept { // Step 1: integer promotion & Schubfach multiplier calculation. using carrier_uint = typename float_info::carrier_uint; @@ -2085,23 +1279,25 @@ template decimal_fp to_decimal(T x) FMT_NOEXCEPT { // Extract significand bits and exponent bits. const carrier_uint significand_mask = - (static_cast(1) << float_info::significand_bits) - 1; + (static_cast(1) << num_significand_bits()) - 1; carrier_uint significand = (br & significand_mask); - int exponent = static_cast((br & exponent_mask()) >> - float_info::significand_bits); + int exponent = + static_cast((br & exponent_mask()) >> num_significand_bits()); if (exponent != 0) { // Check if normal. - exponent += float_info::exponent_bias - float_info::significand_bits; + exponent -= exponent_bias() + num_significand_bits(); // Shorter interval case; proceed like Schubfach. + // In fact, when exponent == 1 and significand == 0, the interval is + // regular. However, it can be shown that the end-results are anyway same. if (significand == 0) return shorter_interval_case(exponent); - significand |= - (static_cast(1) << float_info::significand_bits); + significand |= (static_cast(1) << num_significand_bits()); } else { // Subnormal case; the interval is always regular. if (significand == 0) return {0, 0}; - exponent = float_info::min_exponent - float_info::significand_bits; + exponent = + std::numeric_limits::min_exponent - num_significand_bits() - 1; } const bool include_left_endpoint = (significand % 2 == 0); @@ -2110,402 +1306,116 @@ template decimal_fp to_decimal(T x) FMT_NOEXCEPT { // Compute k and beta. const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); - const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k); + const int beta = exponent + floor_log2_pow10(-minus_k); - // Compute zi and deltai + // Compute zi and deltai. // 10^kappa <= deltai < 10^(kappa + 1) - const uint32_t deltai = cache_accessor::compute_delta(cache, beta_minus_1); + const uint32_t deltai = cache_accessor::compute_delta(cache, beta); const carrier_uint two_fc = significand << 1; - const carrier_uint two_fr = two_fc | 1; - const carrier_uint zi = - cache_accessor::compute_mul(two_fr << beta_minus_1, cache); - // Step 2: Try larger divisor; remove trailing zeros if necessary + // For the case of binary32, the result of integer check is not correct for + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, + // and they are the unique counterexamples. However, since 29711844 is even, + // this does not cause any problem for the endpoints calculations; it can only + // cause a problem when we need to perform integer check for the center. + // Fortunately, with these inputs, that branch is never executed, so we are + // fine. + const typename cache_accessor::compute_mul_result z_mul = + cache_accessor::compute_mul((two_fc | 1) << beta, cache); + + // Step 2: Try larger divisor; remove trailing zeros if necessary. // Using an upper bound on zi, we might be able to optimize the division - // better than the compiler; we are computing zi / big_divisor here + // better than the compiler; we are computing zi / big_divisor here. decimal_fp ret_value; - ret_value.significand = divide_by_10_to_kappa_plus_1(zi); - uint32_t r = static_cast(zi - float_info::big_divisor * - ret_value.significand); + ret_value.significand = divide_by_10_to_kappa_plus_1(z_mul.result); + uint32_t r = static_cast(z_mul.result - float_info::big_divisor * + ret_value.significand); - if (r > deltai) { - goto small_divisor_case_label; - } else if (r < deltai) { - // Exclude the right endpoint if necessary - if (r == 0 && !include_right_endpoint && - is_endpoint_integer(two_fr, exponent, minus_k)) { + if (r < deltai) { + // Exclude the right endpoint if necessary. + if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) { --ret_value.significand; r = float_info::big_divisor; goto small_divisor_case_label; } + } else if (r > deltai) { + goto small_divisor_case_label; } else { - // r == deltai; compare fractional parts - // Check conditions in the order different from the paper - // to take advantage of short-circuiting - const carrier_uint two_fl = two_fc - 1; - if ((!include_left_endpoint || - !is_endpoint_integer(two_fl, exponent, minus_k)) && - !cache_accessor::compute_mul_parity(two_fl, cache, beta_minus_1)) { + // r == deltai; compare fractional parts. + const typename cache_accessor::compute_mul_parity_result x_mul = + cache_accessor::compute_mul_parity(two_fc - 1, cache, beta); + + if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint))) goto small_divisor_case_label; - } } ret_value.exponent = minus_k + float_info::kappa + 1; - // We may need to remove trailing zeros + // We may need to remove trailing zeros. ret_value.exponent += remove_trailing_zeros(ret_value.significand); return ret_value; - // Step 3: Find the significand with the smaller divisor + // Step 3: Find the significand with the smaller divisor. small_divisor_case_label: ret_value.significand *= 10; ret_value.exponent = minus_k + float_info::kappa; - const uint32_t mask = (1u << float_info::kappa) - 1; - auto dist = r - (deltai / 2) + (float_info::small_divisor / 2); - - // Is dist divisible by 2^kappa? - if ((dist & mask) == 0) { - const bool approx_y_parity = - ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; - dist >>= float_info::kappa; - - // Is dist divisible by 5^kappa? - if (check_divisibility_and_divide_by_pow5::kappa>(dist)) { - ret_value.significand += dist; - - // Check z^(f) >= epsilon^(f) - // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, - // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f) - // Since there are only 2 possibilities, we only need to care about the - // parity. Also, zi and r should have the same parity since the divisor - // is an even number - if (cache_accessor::compute_mul_parity(two_fc, cache, beta_minus_1) != - approx_y_parity) { - --ret_value.significand; - } else { - // If z^(f) >= epsilon^(f), we might have a tie - // when z^(f) == epsilon^(f), or equivalently, when y is an integer - if (is_center_integer(two_fc, exponent, minus_k)) { - ret_value.significand = ret_value.significand % 2 == 0 - ? ret_value.significand - : ret_value.significand - 1; - } - } - } - // Is dist not divisible by 5^kappa? - else { - ret_value.significand += dist; - } - } - // Is dist not divisible by 2^kappa? - else { - // Since we know dist is small, we might be able to optimize the division - // better than the compiler; we are computing dist / small_divisor here - ret_value.significand += - small_division_by_pow10::kappa>(dist); - } + uint32_t dist = r - (deltai / 2) + (float_info::small_divisor / 2); + const bool approx_y_parity = + ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; + + // Is dist divisible by 10^kappa? + const bool divisible_by_small_divisor = + check_divisibility_and_divide_by_pow10::kappa>(dist); + + // Add dist / 10^kappa to the significand. + ret_value.significand += dist; + + if (!divisible_by_small_divisor) return ret_value; + + // Check z^(f) >= epsilon^(f). + // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). + // Since there are only 2 possibilities, we only need to care about the + // parity. Also, zi and r should have the same parity since the divisor + // is an even number. + const auto y_mul = cache_accessor::compute_mul_parity(two_fc, cache, beta); + + // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f), + // or equivalently, when y is an integer. + if (y_mul.parity != approx_y_parity) + --ret_value.significand; + else if (y_mul.is_integer & (ret_value.significand % 2 != 0)) + --ret_value.significand; return ret_value; } } // namespace dragonbox -// Formats value using a variation of the Fixed-Precision Positive -// Floating-Point Printout ((FPP)^2) algorithm by Steele & White: -// https://fmt.dev/papers/p372-steele.pdf. -template -void fallback_format(Double d, int num_digits, bool binary32, buffer& buf, - int& exp10) { - bigint numerator; // 2 * R in (FPP)^2. - bigint denominator; // 2 * S in (FPP)^2. - // lower and upper are differences between value and corresponding boundaries. - bigint lower; // (M^- in (FPP)^2). - bigint upper_store; // upper's value if different from lower. - bigint* upper = nullptr; // (M^+ in (FPP)^2). - fp value; - // Shift numerator and denominator by an extra bit or two (if lower boundary - // is closer) to make lower and upper integers. This eliminates multiplication - // by 2 during later computations. - const bool is_predecessor_closer = - binary32 ? value.assign(static_cast(d)) : value.assign(d); - int shift = is_predecessor_closer ? 2 : 1; - uint64_t significand = value.f << shift; - if (value.e >= 0) { - numerator.assign(significand); - numerator <<= value.e; - lower.assign(1); - lower <<= value.e; - if (shift != 1) { - upper_store.assign(1); - upper_store <<= value.e + 1; - upper = &upper_store; - } - denominator.assign_pow10(exp10); - denominator <<= shift; - } else if (exp10 < 0) { - numerator.assign_pow10(-exp10); - lower.assign(numerator); - if (shift != 1) { - upper_store.assign(numerator); - upper_store <<= 1; - upper = &upper_store; - } - numerator *= significand; - denominator.assign(1); - denominator <<= shift - value.e; - } else { - numerator.assign(significand); - denominator.assign_pow10(exp10); - denominator <<= shift - value.e; - lower.assign(1); - if (shift != 1) { - upper_store.assign(1ULL << 1); - upper = &upper_store; - } - } - // Invariant: value == (numerator / denominator) * pow(10, exp10). - if (num_digits < 0) { - // Generate the shortest representation. - if (!upper) upper = &lower; - bool even = (value.f & 1) == 0; - num_digits = 0; - char* data = buf.data(); - for (;;) { - int digit = numerator.divmod_assign(denominator); - bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. - // numerator + upper >[=] pow10: - bool high = add_compare(numerator, *upper, denominator) + even > 0; - data[num_digits++] = static_cast('0' + digit); - if (low || high) { - if (!low) { - ++data[num_digits - 1]; - } else if (high) { - int result = add_compare(numerator, numerator, denominator); - // Round half to even. - if (result > 0 || (result == 0 && (digit % 2) != 0)) - ++data[num_digits - 1]; - } - buf.try_resize(to_unsigned(num_digits)); - exp10 -= num_digits - 1; - return; - } - numerator *= 10; - lower *= 10; - if (upper != &lower) *upper *= 10; - } - } - // Generate the given number of digits. - exp10 -= num_digits - 1; - if (num_digits == 0) { - buf.try_resize(1); - denominator *= 10; - buf[0] = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; - return; - } - buf.try_resize(to_unsigned(num_digits)); - for (int i = 0; i < num_digits - 1; ++i) { - int digit = numerator.divmod_assign(denominator); - buf[i] = static_cast('0' + digit); - numerator *= 10; - } - int digit = numerator.divmod_assign(denominator); - auto result = add_compare(numerator, numerator, denominator); - if (result > 0 || (result == 0 && (digit % 2) != 0)) { - if (digit == 9) { - const auto overflow = '0' + 10; - buf[num_digits - 1] = overflow; - // Propagate the carry. - for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] == overflow) { - buf[0] = '1'; - ++exp10; - } - return; - } - ++digit; - } - buf[num_digits - 1] = static_cast('0' + digit); +#ifdef _MSC_VER +FMT_FUNC auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...) + -> int { + auto args = va_list(); + va_start(args, fmt); + int result = vsnprintf_s(buf, size, _TRUNCATE, fmt, args); + va_end(args); + return result; } - -template -int format_float(T value, int precision, float_specs specs, buffer& buf) { - static_assert(!std::is_same::value, ""); - FMT_ASSERT(value >= 0, "value is negative"); - - const bool fixed = specs.format == float_format::fixed; - if (value <= 0) { // <= instead of == to silence a warning. - if (precision <= 0 || !fixed) { - buf.push_back('0'); - return 0; - } - buf.try_resize(to_unsigned(precision)); - std::uninitialized_fill_n(buf.data(), precision, '0'); - return -precision; - } - - if (!specs.use_grisu) return snprintf_float(value, precision, specs, buf); - - if (precision < 0) { - // Use Dragonbox for the shortest format. - if (specs.binary32) { - auto dec = dragonbox::to_decimal(static_cast(value)); - write(buffer_appender(buf), dec.significand); - return dec.exponent; - } - auto dec = dragonbox::to_decimal(static_cast(value)); - write(buffer_appender(buf), dec.significand); - return dec.exponent; - } - - // Use Grisu + Dragon4 for the given precision: - // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. - int exp = 0; - const int min_exp = -60; // alpha in Grisu. - int cached_exp10 = 0; // K in Grisu. - fp normalized = normalize(fp(value)); - const auto cached_pow = get_cached_power( - min_exp - (normalized.e + fp::significand_size), cached_exp10); - normalized = normalized * cached_pow; - // Limit precision to the maximum possible number of significant digits in an - // IEEE754 double because we don't need to generate zeros. - const int max_double_digits = 767; - if (precision > max_double_digits) precision = max_double_digits; - fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; - if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error) { - exp += handler.size - cached_exp10 - 1; - fallback_format(value, handler.precision, specs.binary32, buf, exp); - } else { - exp += handler.exp10; - buf.try_resize(to_unsigned(handler.size)); - } - if (!fixed && !specs.showpoint) { - // Remove trailing zeros. - auto num_digits = buf.size(); - while (num_digits > 0 && buf[num_digits - 1] == '0') { - --num_digits; - ++exp; - } - buf.try_resize(num_digits); - } - return exp; -} // namespace detail - -template -int snprintf_float(T value, int precision, float_specs specs, - buffer& buf) { - // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. - FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); - static_assert(!std::is_same::value, ""); - - // Subtract 1 to account for the difference in precision since we use %e for - // both general and exponent format. - if (specs.format == float_format::general || - specs.format == float_format::exp) - precision = (precision >= 0 ? precision : 6) - 1; - - // Build the format string. - enum { max_format_size = 7 }; // The longest format is "%#.*Le". - char format[max_format_size]; - char* format_ptr = format; - *format_ptr++ = '%'; - if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#'; - if (precision >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - if (std::is_same()) *format_ptr++ = 'L'; - *format_ptr++ = specs.format != float_format::hex - ? (specs.format == float_format::fixed ? 'f' : 'e') - : (specs.upper ? 'A' : 'a'); - *format_ptr = '\0'; - - // Format using snprintf. - auto offset = buf.size(); - for (;;) { - auto begin = buf.data() + offset; - auto capacity = buf.capacity() - offset; -#ifdef FMT_FUZZ - if (precision > 100000) - throw std::runtime_error( - "fuzz mode - avoid large allocation inside snprintf"); #endif - // Suppress the warning about a nonliteral format string. - // Cannot use auto because of a bug in MinGW (#1532). - int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; - int result = precision >= 0 - ? snprintf_ptr(begin, capacity, format, precision, value) - : snprintf_ptr(begin, capacity, format, value); - if (result < 0) { - // The buffer will grow exponentially. - buf.try_reserve(buf.capacity() + 1); - continue; - } - auto size = to_unsigned(result); - // Size equal to capacity means that the last character was truncated. - if (size >= capacity) { - buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'. - continue; - } - auto is_digit = [](char c) { return c >= '0' && c <= '9'; }; - if (specs.format == float_format::fixed) { - if (precision == 0) { - buf.try_resize(size); - return 0; - } - // Find and remove the decimal point. - auto end = begin + size, p = end; - do { - --p; - } while (is_digit(*p)); - int fraction_size = static_cast(end - p - 1); - std::memmove(p, p + 1, to_unsigned(fraction_size)); - buf.try_resize(size - 1); - return -fraction_size; - } - if (specs.format == float_format::hex) { - buf.try_resize(size + offset); - return 0; - } - // Find and parse the exponent. - auto end = begin + size, exp_pos = end; - do { - --exp_pos; - } while (*exp_pos != 'e'); - char sign = exp_pos[1]; - FMT_ASSERT(sign == '+' || sign == '-', ""); - int exp = 0; - auto p = exp_pos + 2; // Skip 'e' and sign. - do { - FMT_ASSERT(is_digit(*p), ""); - exp = exp * 10 + (*p++ - '0'); - } while (p != end); - if (sign == '-') exp = -exp; - int fraction_size = 0; - if (exp_pos != begin + 1) { - // Remove trailing zeros. - auto fraction_end = exp_pos - 1; - while (*fraction_end == '0') --fraction_end; - // Move the fractional part left to get rid of the decimal point. - fraction_size = static_cast(fraction_end - begin - 1); - std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size)); - } - buf.try_resize(to_unsigned(fraction_size) + offset + 1); - return exp - fraction_size; - } -} } // namespace detail template <> struct formatter { - FMT_CONSTEXPR format_parse_context::iterator parse( - format_parse_context& ctx) { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { return ctx.begin(); } - format_context::iterator format(const detail::bigint& n, - format_context& ctx) { + template + auto format(const detail::bigint& n, FormatContext& ctx) const -> + typename FormatContext::iterator { auto out = ctx.out(); bool first = true; for (auto i = n.bigits_.size(); i > 0; --i) { @@ -2525,8 +1435,8 @@ template <> struct formatter { }; FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { - for_each_codepoint(s, [this](uint32_t cp, int error) { - if (error != 0) FMT_THROW(std::runtime_error("invalid utf8")); + for_each_codepoint(s, [this](uint32_t cp, string_view) { + if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); if (cp <= 0xFFFF) { buffer_.push_back(static_cast(cp)); } else { @@ -2534,12 +1444,13 @@ FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { buffer_.push_back(static_cast(0xD800 + (cp >> 10))); buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); } + return true; }); buffer_.push_back(0); } FMT_FUNC void format_system_error(detail::buffer& out, int error_code, - const char* message) FMT_NOEXCEPT { + const char* message) noexcept { FMT_TRY { auto ec = std::error_code(error_code, std::generic_category()); write(std::back_inserter(out), std::system_error(ec, message).what()); @@ -2549,12 +1460,8 @@ FMT_FUNC void format_system_error(detail::buffer& out, int error_code, format_error_code(out, error_code, message); } -FMT_FUNC void detail::error_handler::on_error(const char* message) { - FMT_THROW(format_error(message)); -} - FMT_FUNC void report_system_error(int error_code, - const char* message) FMT_NOEXCEPT { + const char* message) noexcept { report_error(format_system_error, error_code, message); } @@ -2566,17 +1473,13 @@ FMT_FUNC std::string vformat(string_view fmt, format_args args) { return to_string(buffer); } -#ifdef _WIN32 namespace detail { +#ifdef _WIN32 using dword = conditional_t; extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // void*, const void*, dword, dword*, void*); -} // namespace detail -#endif -namespace detail { -FMT_FUNC void print(std::FILE* f, string_view text) { -#ifdef _WIN32 +FMT_FUNC bool write_console(std::FILE* f, string_view text) { auto fd = _fileno(f); if (_isatty(fd)) { detail::utf8_to_utf16 u16(string_view(text.data(), text.size())); @@ -2584,11 +1487,20 @@ FMT_FUNC void print(std::FILE* f, string_view text) { if (detail::WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), static_cast(u16.size()), &written, nullptr)) { - return; + return true; } - // Fallback to fwrite on failure. It can happen if the output has been - // redirected to NUL. } + // We return false if the file descriptor was not TTY, or it was but + // SetConsoleW failed which can happen if the output has been redirected to + // NUL. In both cases when we return false, we should attempt to do regular + // write via fwrite or std::ostream::write. + return false; +} +#endif + +FMT_FUNC void print(std::FILE* f, string_view text) { +#ifdef _WIN32 + if (write_console(f, text)) return; #endif detail::fwrite_fully(text.data(), 1, text.size(), f); } @@ -2615,6 +1527,197 @@ FMT_FUNC void vprint(string_view format_str, format_args args) { vprint(stdout, format_str, args); } +namespace detail { + +struct singleton { + unsigned char upper; + unsigned char lower_count; +}; + +inline auto is_printable(uint16_t x, const singleton* singletons, + size_t singletons_size, + const unsigned char* singleton_lowers, + const unsigned char* normal, size_t normal_size) + -> bool { + auto upper = x >> 8; + auto lower_start = 0; + for (size_t i = 0; i < singletons_size; ++i) { + auto s = singletons[i]; + auto lower_end = lower_start + s.lower_count; + if (upper < s.upper) break; + if (upper == s.upper) { + for (auto j = lower_start; j < lower_end; ++j) { + if (singleton_lowers[j] == (x & 0xff)) return false; + } + } + lower_start = lower_end; + } + + auto xsigned = static_cast(x); + auto current = true; + for (size_t i = 0; i < normal_size; ++i) { + auto v = static_cast(normal[i]); + auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; + xsigned -= len; + if (xsigned < 0) break; + current = !current; + } + return current; +} + +// This code is generated by support/printable.py. +FMT_FUNC auto is_printable(uint32_t cp) -> bool { + static constexpr singleton singletons0[] = { + {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, + {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, + {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, + {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, + {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, + {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, + {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, + }; + static constexpr unsigned char singletons0_lower[] = { + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, + 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, + 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, + 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, + 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, + 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, + 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, + 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, + 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, + 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, + 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, + 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, + 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, + }; + static constexpr singleton singletons1[] = { + {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, + {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, + {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, + {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, + {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, + {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, + {0xfa, 2}, {0xfb, 1}, + }; + static constexpr unsigned char singletons1_lower[] = { + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, + 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, + 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, + 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, + 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, + 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, + 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + }; + static constexpr unsigned char normal0[] = { + 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, + 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, + 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, + 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, + 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, + 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, + 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, + 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, + 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, + 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, + 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, + 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, + 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, + 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, + 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, + 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, + 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, + 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, + 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, + 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, + 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, + 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, + 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, + 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, + 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, + }; + static constexpr unsigned char normal1[] = { + 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, + 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, + 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, + 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, + 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, + 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, + 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, + 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, + 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, + 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, + 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, + 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, + 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, + 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, + 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, + 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, + 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, + 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, + 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, + 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, + 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, + 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, + 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, + 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, + 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, + 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, + 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, + 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, + 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, + 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, + 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, + 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, + 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, + 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, + }; + auto lower = static_cast(cp); + if (cp < 0x10000) { + return is_printable(lower, singletons0, + sizeof(singletons0) / sizeof(*singletons0), + singletons0_lower, normal0, sizeof(normal0)); + } + if (cp < 0x20000) { + return is_printable(lower, singletons1, + sizeof(singletons1) / sizeof(*singletons1), + singletons1_lower, normal1, sizeof(normal1)); + } + if (0x2a6de <= cp && cp < 0x2a700) return false; + if (0x2b735 <= cp && cp < 0x2b740) return false; + if (0x2b81e <= cp && cp < 0x2b820) return false; + if (0x2cea2 <= cp && cp < 0x2ceb0) return false; + if (0x2ebe1 <= cp && cp < 0x2f800) return false; + if (0x2fa1e <= cp && cp < 0x30000) return false; + if (0x3134b <= cp && cp < 0xe0100) return false; + if (0xe01f0 <= cp && cp < 0x110000) return false; + return cp < 0x110000; +} + +} // namespace detail + FMT_END_NAMESPACE #endif // FMT_FORMAT_INL_H_ diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/format.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/format.h index 5398a23a8..7c607dbd3 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/format.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/format.h @@ -1,33 +1,33 @@ /* - Formatting library for C++ - - Copyright (c) 2012 - present, Victor Zverovich - - 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. - - --- Optional exception to the license --- - - As an exception, if, as a result of your compiling your source code, portions - of this Software are embedded into a machine-executable object form of such - source code, you may redistribute such embedded portions in such object form - without including the above copyright and permission notices. + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + + 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. + + --- Optional exception to the license --- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into a machine-executable object form of such + source code, you may redistribute such embedded portions in such object form + without including the above copyright and permission notices. */ #ifndef FMT_FORMAT_H_ @@ -35,20 +35,22 @@ #include // std::signbit #include // uint32_t +#include // std::memcpy #include // std::numeric_limits #include // std::uninitialized_copy #include // std::runtime_error #include // std::system_error -#include // std::swap + +#ifdef __cpp_lib_bit_cast +# include // std::bitcast +#endif #include "core.h" -#ifdef __INTEL_COMPILER -# define FMT_ICC_VERSION __INTEL_COMPILER -#elif defined(__ICL) -# define FMT_ICC_VERSION __ICL +#if FMT_GCC_VERSION +# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) #else -# define FMT_ICC_VERSION 0 +# define FMT_GCC_VISIBILITY_HIDDEN #endif #ifdef __NVCC__ @@ -69,7 +71,7 @@ # define FMT_NOINLINE #endif -#if FMT_MSC_VER +#if FMT_MSC_VERSION # define FMT_MSC_DEFAULT = default #else # define FMT_MSC_DEFAULT @@ -77,7 +79,7 @@ #ifndef FMT_THROW # if FMT_EXCEPTIONS -# if FMT_MSC_VER || FMT_NVCC +# if FMT_MSC_VERSION || defined(__NVCC__) FMT_BEGIN_NAMESPACE namespace detail { template inline void do_throw(const Exception& x) { @@ -108,31 +110,18 @@ FMT_END_NAMESPACE # define FMT_CATCH(x) if (false) #endif -#ifndef FMT_DEPRECATED -# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 -# define FMT_DEPRECATED [[deprecated]] +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] # else -# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) -# define FMT_DEPRECATED __attribute__((deprecated)) -# elif FMT_MSC_VER -# define FMT_DEPRECATED __declspec(deprecated) -# else -# define FMT_DEPRECATED /* deprecated */ -# endif +# define FMT_MAYBE_UNUSED # endif #endif -// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. -#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC -# define FMT_DEPRECATED_ALIAS -#else -# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED -#endif - #ifndef FMT_USE_USER_DEFINED_LITERALS // EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ - FMT_MSC_VER >= 1900) && \ + FMT_MSC_VERSION >= 1900) && \ (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) # define FMT_USE_USER_DEFINED_LITERALS 1 # else @@ -149,33 +138,42 @@ FMT_END_NAMESPACE #endif // __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519 -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctz)) -# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VERSION +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif #endif -#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_ctzll)) -# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) + +// __builtin_ctz is broken in Intel Compiler Classic on Windows: +// https://github.com/fmtlib/fmt/issues/2510. +#ifndef __ICL +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ + defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \ + FMT_ICC_VERSION || defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif #endif -#if FMT_MSC_VER +#if FMT_MSC_VERSION # include // _BitScanReverse[64], _BitScanForward[64], _umul128 #endif // Some compilers masquerade as both MSVC and GCC-likes or otherwise support // __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the // MSVC intrinsics if the clz and clzll builtins are not available. -#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL) +#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \ + !defined(FMT_BUILTIN_CTZLL) FMT_BEGIN_NAMESPACE namespace detail { // Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. # if !defined(__clang__) -# pragma managed(push, off) # pragma intrinsic(_BitScanForward) # pragma intrinsic(_BitScanReverse) # if defined(_WIN64) @@ -237,9 +235,6 @@ inline auto ctzll(uint64_t x) -> int { return static_cast(r); } # define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) -# if !defined(__clang__) -# pragma managed(pop) -# endif } // namespace detail FMT_END_NAMESPACE #endif @@ -247,55 +242,194 @@ FMT_END_NAMESPACE FMT_BEGIN_NAMESPACE namespace detail { -#if __cplusplus >= 202002L || \ - (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) -# define FMT_CONSTEXPR20 constexpr -#else -# define FMT_CONSTEXPR20 +FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { + ignore_unused(condition); +#ifdef FMT_FUZZ + if (condition) throw std::runtime_error("fuzzing limit reached"); +#endif +} + +template struct string_literal { + static constexpr CharT value[sizeof...(C)] = {C...}; + constexpr operator basic_string_view() const { + return {value, sizeof...(C)}; + } +}; + +#if FMT_CPLUSPLUS < 201703L +template +constexpr CharT string_literal::value[sizeof...(C)]; #endif -// An equivalent of `*reinterpret_cast(&source)` that doesn't have -// undefined behavior (e.g. due to type aliasing). -// Example: uint64_t d = bit_cast(2.718); -template -inline auto bit_cast(const Source& source) -> Dest { - static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); - Dest dest; - std::memcpy(&dest, &source, sizeof(dest)); - return dest; +template class formatbuf : public Streambuf { + private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; + + buffer& buffer_; + + public: + explicit formatbuf(buffer& buf) : buffer_(buf) {} + + protected: + // The put area is 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. A 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. + + auto overflow(int_type ch) -> int_type override { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type* s, streamsize count) -> streamsize override { + buffer_.append(s, s + count); + return count; + } +}; + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; } inline auto is_big_endian() -> bool { - const auto u = 1u; +#ifdef _WIN32 + return false; +#elif defined(__BIG_ENDIAN__) + return true; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +#else struct bytes { - char data[sizeof(u)]; + char data[sizeof(int)]; }; - return bit_cast(u).data[0] == 0; + return bit_cast(1).data[0] == 0; +#endif } -// A fallback implementation of uintptr_t for systems that lack it. -struct fallback_uintptr { - unsigned char value[sizeof(void*)]; +class uint128_fallback { + private: + uint64_t lo_, hi_; + + friend uint128_fallback umul128(uint64_t x, uint64_t y) noexcept; + + public: + constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} + constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} + + constexpr uint64_t high() const noexcept { return hi_; } + constexpr uint64_t low() const noexcept { return lo_; } + + template ::value)> + constexpr explicit operator T() const { + return static_cast(lo_); + } + + friend constexpr auto operator==(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; + } + friend constexpr auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return !(lhs == rhs); + } + friend constexpr auto operator>(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; + } + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; + } + friend constexpr auto operator&(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; + } + friend auto operator+(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> uint128_fallback { + auto result = uint128_fallback(lhs); + result += rhs; + return result; + } + friend auto operator*(const uint128_fallback& lhs, uint32_t rhs) + -> uint128_fallback { + FMT_ASSERT(lhs.hi_ == 0, ""); + uint64_t hi = (lhs.lo_ >> 32) * rhs; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; + } + friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) + -> uint128_fallback { + return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; + } + FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { + if (shift == 64) return {0, hi_}; + if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { + if (shift == 64) return {lo_, 0}; + if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; + } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { + return *this = *this >> shift; + } + FMT_CONSTEXPR void operator+=(uint128_fallback n) { + uint64_t new_lo = lo_ + n.lo_; + uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); + FMT_ASSERT(new_hi >= hi_, ""); + lo_ = new_lo; + hi_ = new_hi; + } - fallback_uintptr() = default; - explicit fallback_uintptr(const void* p) { - *this = bit_cast(p); - if (is_big_endian()) { - for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j) - std::swap(value[i], value[j]); + FMT_CONSTEXPR20 uint128_fallback& operator+=(uint64_t n) noexcept { + if (is_constant_evaluated()) { + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); + return *this; } +#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + unsigned long long carry; + lo_ = __builtin_addcll(lo_, n, 0, &carry); + hi_ += carry; +#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) + unsigned long long result; + auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); + lo_ = result; + hi_ += carry; +#elif defined(_MSC_VER) && defined(_M_X64) + auto carry = _addcarry_u64(0, lo_, n, &lo_); + _addcarry_u64(carry, hi_, 0, &hi_); +#else + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); +#endif + return *this; } }; + +using uint128_t = conditional_t; + #ifdef UINTPTR_MAX using uintptr_t = ::uintptr_t; -inline auto to_uintptr(const void* p) -> uintptr_t { - return bit_cast(p); -} #else -using uintptr_t = fallback_uintptr; -inline auto to_uintptr(const void* p) -> fallback_uintptr { - return fallback_uintptr(p); -} +using uintptr_t = uint128_t; #endif // Returns the largest possible value for type T. Same as @@ -307,16 +441,31 @@ template constexpr auto num_bits() -> int { return std::numeric_limits::digits; } // std::numeric_limits::digits may return 0 for 128-bit ints. -template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } template <> constexpr auto num_bits() -> int { return 128; } -template <> constexpr auto num_bits() -> int { - return static_cast(sizeof(void*) * - std::numeric_limits::digits); + +// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t +// and 128-bit pointers to uint128_fallback. +template sizeof(From))> +inline auto bit_cast(const From& from) -> To { + constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); + struct data_t { + unsigned value[static_cast(size)]; + } data = bit_cast(from); + auto result = To(); + if (const_check(is_big_endian())) { + for (int i = 0; i < size; ++i) + result = (result << num_bits()) | data.value[i]; + } else { + for (int i = size - 1; i >= 0; --i) + result = (result << num_bits()) | data.value[i]; + } + return result; } FMT_INLINE void assume(bool condition) { (void)condition; -#if FMT_HAS_BUILTIN(__builtin_assume) +#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION __builtin_assume(condition); #endif } @@ -339,12 +488,15 @@ inline auto get_data(Container& c) -> typename Container::value_type* { #if defined(_SECURE_SCL) && _SECURE_SCL // Make a checked iterator to avoid MSVC warnings. template using checked_ptr = stdext::checked_array_iterator; -template auto make_checked(T* p, size_t size) -> checked_ptr { +template +constexpr auto make_checked(T* p, size_t size) -> checked_ptr { return {p, size}; } #else template using checked_ptr = T*; -template inline auto make_checked(T* p, size_t) -> T* { return p; } +template constexpr auto make_checked(T* p, size_t) -> T* { + return p; +} #endif // Attempts to reserve space for n extra characters in the output range. @@ -455,19 +607,23 @@ FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) constexpr const int shiftc[] = {0, 18, 12, 6, 0}; constexpr const int shifte[] = {0, 6, 4, 2, 0}; - int len = code_point_length(s); - const char* next = s + len; + int len = code_point_length_impl(*s); + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + const char* next = s + len + !len; + + using uchar = unsigned char; // Assume a four-byte character and load four bytes. Unused bits are // shifted out. - *c = uint32_t(s[0] & masks[len]) << 18; - *c |= uint32_t(s[1] & 0x3f) << 12; - *c |= uint32_t(s[2] & 0x3f) << 6; - *c |= uint32_t(s[3] & 0x3f) << 0; + *c = uint32_t(uchar(s[0]) & masks[len]) << 18; + *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; + *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; + *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; *c >>= shiftc[len]; // Accumulate the various error conditions. - using uchar = unsigned char; *e = (*c < mins[len]) << 6; // non-canonical encoding *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? *e |= (*c > 0x10FFFF) << 8; // out of range? @@ -480,27 +636,38 @@ FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) return next; } +constexpr uint32_t invalid_code_point = ~uint32_t(); + +// Invokes f(cp, sv) for every code point cp in s with sv being the string view +// corresponding to the code point. cp is invalid_code_point on error. template FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { - auto decode = [f](const char* p) { + auto decode = [f](const char* buf_ptr, const char* ptr) { auto cp = uint32_t(); auto error = 0; - p = utf8_decode(p, &cp, &error); - f(cp, error); - return p; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, + string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); + return result ? (error ? buf_ptr + 1 : end) : nullptr; }; auto p = s.data(); const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. if (s.size() >= block_size) { - for (auto end = p + s.size() - block_size + 1; p < end;) p = decode(p); + for (auto end = p + s.size() - block_size + 1; p < end;) { + p = decode(p, p); + if (!p) return; + } } if (auto num_chars_left = s.data() + s.size() - p) { char buf[2 * block_size - 1] = {}; copy_str(p, p + num_chars_left, buf); - p = buf; + const char* buf_ptr = buf; do { - p = decode(p); - } while (p - buf < num_chars_left); + auto end = decode(buf_ptr, p); + if (!end) return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); } } @@ -515,10 +682,10 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) { // It is not a lambda for compatibility with C++14. struct count_code_points { size_t* count; - FMT_CONSTEXPR void operator()(uint32_t cp, int error) const { + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { *count += detail::to_unsigned( 1 + - (error == 0 && cp >= 0x1100 && + (cp >= 0x1100 && (cp <= 0x115f || // Hangul Jamo init. consonants cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET @@ -536,6 +703,7 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) { (cp >= 0x1f300 && cp <= 0x1f64f) || // Supplemental Symbols and Pictographs: (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; } }; for_each_codepoint(s, count_code_points{&num_code_points}); @@ -543,8 +711,8 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) { } inline auto compute_width(basic_string_view s) -> size_t { - return compute_width(basic_string_view( - reinterpret_cast(s.data()), s.size())); + return compute_width( + string_view(reinterpret_cast(s.data()), s.size())); } template @@ -554,9 +722,8 @@ inline auto code_point_index(basic_string_view s, size_t n) -> size_t { } // Calculates the index of the nth code point in a UTF-8 string. -inline auto code_point_index(basic_string_view s, size_t n) - -> size_t { - const char8_type* data = s.data(); +inline auto code_point_index(string_view s, size_t n) -> size_t { + const char* data = s.data(); size_t num_code_points = 0; for (size_t i = 0, size = s.size(); i != size; ++i) { if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i; @@ -564,9 +731,37 @@ inline auto code_point_index(basic_string_view s, size_t n) return s.size(); } +inline auto code_point_index(basic_string_view s, size_t n) + -> size_t { + return code_point_index( + string_view(reinterpret_cast(s.data()), s.size()), n); +} + +#ifndef FMT_USE_FLOAT128 +# ifdef __SIZEOF_FLOAT128__ +# define FMT_USE_FLOAT128 1 +# else +# define FMT_USE_FLOAT128 0 +# endif +#endif +#if FMT_USE_FLOAT128 +using float128 = __float128; +#else +using float128 = void; +#endif +template using is_float128 = std::is_same; + +template +using is_floating_point = + bool_constant::value || is_float128::value>; + +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; + template -using is_fast_float = bool_constant::is_iec559 && - sizeof(T) <= sizeof(double)>; +using is_double_double = bool_constant::digits == 106>; #ifndef FMT_USE_FULL_CACHE_DRAGONBOX # define FMT_USE_FULL_CACHE_DRAGONBOX 0 @@ -607,8 +802,8 @@ enum { inline_buffer_size = 500 }; **Example**:: - fmt::memory_buffer out; - format_to(out, "The answer is {}.", 42); + auto out = fmt::memory_buffer(); + format_to(std::back_inserter(out), "The answer is {}.", 42); This will append the following output to the ``out`` object: @@ -629,39 +824,42 @@ class basic_memory_buffer final : public detail::buffer { Allocator alloc_; // Deallocate memory allocated by the buffer. - void deallocate() { + FMT_CONSTEXPR20 void deallocate() { T* data = this->data(); if (data != store_) alloc_.deallocate(data, this->capacity()); } protected: - void grow(size_t size) final FMT_OVERRIDE; + FMT_CONSTEXPR20 void grow(size_t size) override; public: using value_type = T; using const_reference = const T&; - explicit basic_memory_buffer(const Allocator& alloc = Allocator()) + FMT_CONSTEXPR20 explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) : alloc_(alloc) { this->set(store_, SIZE); + if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T()); } - ~basic_memory_buffer() { deallocate(); } + FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } private: // Move data from other to this buffer. - void move(basic_memory_buffer& other) { + FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { alloc_ = std::move(other.alloc_); T* data = other.data(); size_t size = other.size(), capacity = other.capacity(); if (data == other.store_) { this->set(store_, capacity); - std::uninitialized_copy(other.store_, other.store_ + size, - detail::make_checked(store_, capacity)); + detail::copy_str(other.store_, other.store_ + size, + detail::make_checked(store_, capacity)); } else { this->set(data, capacity); // Set pointer to the inline array so that delete is not called // when deallocating. other.set(other.store_, 0); + other.clear(); } this->resize(size); } @@ -673,15 +871,16 @@ class basic_memory_buffer final : public detail::buffer { of the other object to it. \endrst */ - basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); } + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept { + move(other); + } /** \rst Moves the content of the other ``basic_memory_buffer`` object to this one. \endrst */ - auto operator=(basic_memory_buffer&& other) FMT_NOEXCEPT - -> basic_memory_buffer& { + auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& { FMT_ASSERT(this != &other, ""); deallocate(); move(other); @@ -695,7 +894,7 @@ class basic_memory_buffer final : public detail::buffer { Resizes the buffer to contain *count* elements. If T is a POD type new elements may not be initialized. */ - void resize(size_t count) { this->try_resize(count); } + FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } /** Increases the buffer capacity to *new_capacity*. */ void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } @@ -709,10 +908,9 @@ class basic_memory_buffer final : public detail::buffer { }; template -void basic_memory_buffer::grow(size_t size) { -#ifdef FMT_FUZZ - if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much"); -#endif +FMT_CONSTEXPR20 void basic_memory_buffer::grow( + size_t size) { + detail::abort_fuzzing_if(size > 5000); const size_t max_size = std::allocator_traits::max_size(alloc_); size_t old_capacity = this->capacity(); size_t new_capacity = old_capacity + old_capacity / 2; @@ -740,8 +938,11 @@ struct is_contiguous> : std::true_type { }; namespace detail { +#ifdef _WIN32 +FMT_API bool write_console(std::FILE* f, string_view text); +#endif FMT_API void print(std::FILE*, string_view); -} +} // namespace detail /** A formatting error such as invalid format string. */ FMT_CLASS_API @@ -754,39 +955,17 @@ class FMT_API format_error : public std::runtime_error { format_error& operator=(const format_error&) = default; format_error(format_error&&) = default; format_error& operator=(format_error&&) = default; - ~format_error() FMT_NOEXCEPT FMT_OVERRIDE FMT_MSC_DEFAULT; + ~format_error() noexcept override FMT_MSC_DEFAULT; }; -/** - \rst - Constructs a `~fmt::format_arg_store` object that contains references - to arguments and can be implicitly converted to `~fmt::format_args`. - If ``fmt`` is a compile-time string then `make_args_checked` checks - its validity at compile time. - \endrst - */ -template > -FMT_INLINE auto make_args_checked(const S& fmt, - const remove_reference_t&... args) - -> format_arg_store, remove_reference_t...> { - static_assert( - detail::count<( - std::is_base_of>::value && - std::is_reference::value)...>() == 0, - "passing views as lvalues is disallowed"); - detail::check_format_string(fmt); - return {args...}; -} - -// compile-time support namespace detail_exported { -#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +#if FMT_USE_NONTYPE_TEMPLATE_ARGS template struct fixed_string { constexpr fixed_string(const Char (&str)[N]) { detail::copy_str(static_cast(str), str + N, data); } - Char data[N]{}; + Char data[N] = {}; }; #endif @@ -807,35 +986,32 @@ constexpr auto compile_string_to_view(detail::std_string_view s) FMT_BEGIN_DETAIL_NAMESPACE -inline void throw_format_error(const char* message) { - FMT_THROW(format_error(message)); -} - template struct is_integral : std::is_integral {}; -template <> struct is_integral : std::true_type {}; +template <> struct is_integral : std::true_type {}; template <> struct is_integral : std::true_type {}; template using is_signed = std::integral_constant::is_signed || - std::is_same::value>; + std::is_same::value>; // Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. template ::value)> -FMT_CONSTEXPR auto is_negative(T value) -> bool { +constexpr auto is_negative(T value) -> bool { return value < 0; } template ::value)> -FMT_CONSTEXPR auto is_negative(T) -> bool { +constexpr auto is_negative(T) -> bool { return false; } -template ::value)> -FMT_CONSTEXPR auto is_supported_floating_point(T) -> uint16_t { - return (std::is_same::value && FMT_USE_FLOAT) || - (std::is_same::value && FMT_USE_DOUBLE) || - (std::is_same::value && FMT_USE_LONG_DOUBLE); +template +FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { + if (std::is_same()) return FMT_USE_FLOAT; + if (std::is_same()) return FMT_USE_DOUBLE; + if (std::is_same()) return FMT_USE_LONG_DOUBLE; + return true; } // Smallest of uint32_t, uint64_t, uint128_t that is large enough to @@ -853,48 +1029,23 @@ using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; (factor)*1000000, (factor)*10000000, (factor)*100000000, \ (factor)*1000000000 -// Static data is placed in this class template for the header-only config. -template struct basic_data { - // log10(2) = 0x0.4d104d427de7fbcc... - static const uint64_t log10_2_significand = 0x4d104d427de7fbcc; - - // GCC generates slightly better code for pairs than chars. - FMT_API static constexpr const char digits[100][2] = { - {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, - {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, - {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, - {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, - {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, - {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'}, - {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'}, - {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'}, - {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, - {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, - {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'}, - {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'}, - {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'}, - {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, - {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, - {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'}, - {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}}; - - FMT_API static constexpr const char hex_digits[] = "0123456789abcdef"; - FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '}; - FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', - 0x1000000u | ' '}; - FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1, - 0}; - FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1, - 0}; -}; +// Converts value in the range [0, 100) to a string. +constexpr const char* digits2(size_t value) { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} -#ifdef FMT_SHARED -// Required for -flto, -fivisibility=hidden and -shared to work -extern template struct basic_data; +// Sign is a template parameter to workaround a bug in gcc 4.8. +template constexpr Char sign(Sign s) { +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 + static_assert(std::is_same::value, ""); #endif - -// This is a struct rather than an alias to avoid shadowing warnings in gcc. -struct data : basic_data<> {}; + return static_cast("\0-+ "[s]); +} template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { int count = 1; @@ -911,28 +1062,38 @@ template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { } } #if FMT_USE_INT128 -FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int { +FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { return count_digits_fallback(n); } #endif +#ifdef FMT_BUILTIN_CLZLL +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +inline auto do_count_digits(uint64_t n) -> int { + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); +} +#endif + // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { #ifdef FMT_BUILTIN_CLZLL if (!is_constant_evaluated()) { - // https://github.com/fmtlib/format-benchmark/blob/master/digits10 - // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). - constexpr uint16_t bsr2log10[] = { - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, - 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; - auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; - constexpr const uint64_t zero_or_powers_of_10[] = { - 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; - return t - (n < zero_or_powers_of_10[t]); + return do_count_digits(n); } #endif return count_digits_fallback(n); @@ -942,24 +1103,26 @@ FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { template FMT_CONSTEXPR auto count_digits(UInt n) -> int { #ifdef FMT_BUILTIN_CLZ - if (num_bits() == 32) + if (!is_constant_evaluated() && num_bits() == 32) return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; #endif - int num_digits = 0; - do { - ++num_digits; - } while ((n >>= BITS) != 0); - return num_digits; + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); } -template <> auto count_digits<4>(detail::fallback_uintptr n) -> int; - +#ifdef FMT_BUILTIN_CLZ // It is a separate function rather than a part of count_digits to workaround // the lack of static constexpr in constexpr functions. -FMT_INLINE uint64_t count_digits_inc(int n) { - // An optimization by Kendall Willets from https://bit.ly/3uOIQrB. - // This increments the upper 32 bits (log10(T) - 1) when >= T is added. -#define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) +FMT_INLINE auto do_count_digits(uint32_t n) -> int { +// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +# define FMT_INC(T) (((sizeof(# T) - 1ull) << 32) - T) static constexpr uint64_t table[] = { FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 @@ -973,29 +1136,26 @@ FMT_INLINE uint64_t count_digits_inc(int n) { FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M FMT_INC(1000000000), FMT_INC(1000000000) // 4B }; - return table[n]; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); } +#endif // Optional version of count_digits for better performance on 32-bit platforms. FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { #ifdef FMT_BUILTIN_CLZ if (!is_constant_evaluated()) { - auto inc = count_digits_inc(FMT_BUILTIN_CLZ(n | 1) ^ 31); - return static_cast((n + inc) >> 32); + return do_count_digits(n); } #endif return count_digits_fallback(n); } -template constexpr auto digits10() FMT_NOEXCEPT -> int { +template constexpr auto digits10() noexcept -> int { return std::numeric_limits::digits10; } -template <> constexpr auto digits10() FMT_NOEXCEPT -> int { - return 38; -} -template <> constexpr auto digits10() FMT_NOEXCEPT -> int { - return 38; -} +template <> constexpr auto digits10() noexcept -> int { return 38; } +template <> constexpr auto digits10() noexcept -> int { return 38; } template struct thousands_sep_result { std::string grouping; @@ -1032,11 +1192,15 @@ inline auto equal2(const char* lhs, const char* rhs) -> bool { } // Copies two characters from src to dst. -template void copy2(Char* dst, const char* src) { +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { + memcpy(dst, src, 2); + return; + } *dst++ = static_cast(*src++); *dst = static_cast(*src); } -FMT_INLINE void copy2(char* dst, const char* src) { memcpy(dst, src, 2); } template struct format_decimal_result { Iterator begin; @@ -1052,20 +1216,12 @@ FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) FMT_ASSERT(size >= count_digits(value), "invalid digit count"); out += size; Char* end = out; - if (is_constant_evaluated()) { - while (value >= 10) { - *--out = static_cast('0' + value % 10); - value /= 10; - } - *--out = static_cast('0' + value); - return {out, end}; - } while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. out -= 2; - copy2(out, data::digits[value % 100]); + copy2(out, digits2(static_cast(value % 100))); value /= 100; } if (value < 10) { @@ -1073,13 +1229,13 @@ FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) return {out, end}; } out -= 2; - copy2(out, data::digits[value]); + copy2(out, digits2(static_cast(value))); return {out, end}; } template >::value)> -inline auto format_decimal(Iterator out, UInt value, int size) +FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) -> format_decimal_result { // Buffer is large enough to hold all digits (digits10 + 1). Char buffer[digits10() + 1]; @@ -1093,36 +1249,14 @@ FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, buffer += num_digits; Char* end = buffer; do { - const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits; - unsigned digit = (value & ((1 << BASE_BITS) - 1)); + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); } while ((value >>= BASE_BITS) != 0); return end; } -template -auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits, - bool = false) -> Char* { - auto char_digits = std::numeric_limits::digits / 4; - int start = (num_digits + char_digits - 1) / char_digits - 1; - if (int start_digits = num_digits % char_digits) { - unsigned value = n.value[start--]; - buffer = format_uint(buffer, value, start_digits); - } - for (; start >= 0; --start) { - unsigned value = n.value[start]; - buffer += char_digits; - auto p = buffer; - for (int i = 0; i < char_digits; ++i) { - unsigned digit = (value & ((1 << BASE_BITS) - 1)); - *--p = static_cast(data::hex_digits[digit]); - value >>= BASE_BITS; - } - } - return buffer; -} - template inline auto format_uint(It out, UInt value, int num_digits, bool upper = false) -> It { @@ -1152,58 +1286,45 @@ class utf8_to_utf16 { namespace dragonbox { // Type-specific information that Dragonbox uses. -template struct float_info; +template struct float_info; template <> struct float_info { using carrier_uint = uint32_t; - static const int significand_bits = 23; static const int exponent_bits = 8; - static const int min_exponent = -126; - static const int max_exponent = 127; - static const int exponent_bias = -127; - static const int decimal_digits = 9; static const int kappa = 1; static const int big_divisor = 100; static const int small_divisor = 10; static const int min_k = -31; static const int max_k = 46; - static const int cache_bits = 64; - static const int divisibility_check_by_5_threshold = 39; - static const int case_fc_pm_half_lower_threshold = -1; - static const int case_fc_pm_half_upper_threshold = 6; - static const int case_fc_lower_threshold = -2; - static const int case_fc_upper_threshold = 6; - static const int case_shorter_interval_left_endpoint_lower_threshold = 2; - static const int case_shorter_interval_left_endpoint_upper_threshold = 3; static const int shorter_interval_tie_lower_threshold = -35; static const int shorter_interval_tie_upper_threshold = -35; - static const int max_trailing_zeros = 7; }; template <> struct float_info { using carrier_uint = uint64_t; - static const int significand_bits = 52; static const int exponent_bits = 11; - static const int min_exponent = -1022; - static const int max_exponent = 1023; - static const int exponent_bias = -1023; - static const int decimal_digits = 17; static const int kappa = 2; static const int big_divisor = 1000; static const int small_divisor = 100; static const int min_k = -292; static const int max_k = 326; - static const int cache_bits = 128; - static const int divisibility_check_by_5_threshold = 86; - static const int case_fc_pm_half_lower_threshold = -2; - static const int case_fc_pm_half_upper_threshold = 9; - static const int case_fc_lower_threshold = -4; - static const int case_fc_upper_threshold = 9; - static const int case_shorter_interval_left_endpoint_lower_threshold = 2; - static const int case_shorter_interval_left_endpoint_upper_threshold = 3; static const int shorter_interval_tie_lower_threshold = -77; static const int shorter_interval_tie_upper_threshold = -77; - static const int max_trailing_zeros = 16; +}; + +// An 80- or 128-bit floating point number. +template +struct float_info::digits == 64 || + std::numeric_limits::digits == 113 || + is_float128::value>> { + using carrier_uint = detail::uint128_t; + static const int exponent_bits = 15; +}; + +// A double-double floating point number. +template +struct float_info::value>> { + using carrier_uint = detail::uint128_t; }; template struct decimal_fp { @@ -1212,21 +1333,40 @@ template struct decimal_fp { int exponent; }; -template -FMT_API auto to_decimal(T x) FMT_NOEXCEPT -> decimal_fp; +template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; } // namespace dragonbox -template +// Returns true iff Float has the implicit bit which is not stored. +template constexpr bool has_implicit_bit() { + // An 80-bit FP number has a 64-bit significand an no implicit bit. + return std::numeric_limits::digits != 64; +} + +// Returns the number of significand bits stored in Float. The implicit bit is +// not counted since it is not stored. +template constexpr int num_significand_bits() { + // std::numeric_limits may not support __float128. + return is_float128() ? 112 + : (std::numeric_limits::digits - + (has_implicit_bit() ? 1 : 0)); +} + +template constexpr auto exponent_mask() -> - typename dragonbox::float_info::carrier_uint { - using uint = typename dragonbox::float_info::carrier_uint; - return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) - << dragonbox::float_info::significand_bits; + typename dragonbox::float_info::carrier_uint { + using uint = typename dragonbox::float_info::carrier_uint; + return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) + << num_significand_bits(); +} +template constexpr auto exponent_bias() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 16383 + : std::numeric_limits::max_exponent - 1; } // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. template -auto write_exponent(int exp, It it) -> It { +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); if (exp < 0) { *it++ = static_cast('-'); @@ -1235,29 +1375,262 @@ auto write_exponent(int exp, It it) -> It { *it++ = static_cast('+'); } if (exp >= 100) { - const char* top = data::digits[exp / 100]; + const char* top = digits2(to_unsigned(exp / 100)); if (exp >= 1000) *it++ = static_cast(top[0]); *it++ = static_cast(top[1]); exp %= 100; } - const char* d = data::digits[exp]; + const char* d = digits2(to_unsigned(exp)); *it++ = static_cast(d[0]); *it++ = static_cast(d[1]); return it; } -template -auto format_float(T value, int precision, float_specs specs, buffer& buf) - -> int; +// A floating-point number f * pow(2, e) where F is an unsigned type. +template struct basic_fp { + F f; + int e; + + static constexpr const int num_significand_bits = + static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() : f(0), e(0) {} + constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. + template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = + detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto biased_e = static_cast((u & exponent_mask()) >> + num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) + // other than the smallest normalized number (biased_e > 1). + auto is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e == 0) + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); + e = biased_e - exponent_bias() - num_float_significand_bits; + if (!has_implicit_bit()) ++e; + return is_predecessor_closer; + } + + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } +}; + +using fp = basic_fp; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template +FMT_CONSTEXPR basic_fp normalize(basic_fp value) { + // Handle subnormals. + const auto implicit_bit = F(1) << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = basic_fp::num_significand_bits - + num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; +} + +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { +#if FMT_USE_INT128 + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +#else + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); +#endif +} + +FMT_CONSTEXPR inline fp operator*(fp x, fp y) { + return {multiply(x.f, y.f), x.e + y.e + 64}; +} + +template struct basic_data { + // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. + // These are generated by support/compute-powers.py. + static constexpr uint64_t pow10_significands[87] = { + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, + 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, + 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, + 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, + 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, + 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, + }; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnarrowing" +#endif + // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding + // to significands above. + static constexpr int16_t pow10_exponents[87] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, + -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, + -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, + -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, + -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, + 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, + 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, + 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +# pragma GCC diagnostic pop +#endif + + static constexpr uint64_t power_of_10_64[20] = { + 1, FMT_POWERS_OF_10(1ULL), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; +}; + +#if FMT_CPLUSPLUS < 201703L +template constexpr uint64_t basic_data::pow10_significands[]; +template constexpr int16_t basic_data::pow10_exponents[]; +template constexpr uint64_t basic_data::power_of_10_64[]; +#endif + +// This is a struct rather than an alias to avoid shadowing warnings in gcc. +struct data : basic_data<> {}; + +// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its +// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`. +FMT_CONSTEXPR inline fp get_cached_power(int min_exponent, + int& pow10_exponent) { + const int shift = 32; + // log10(2) = 0x0.4d104d427de7fbcc... + const int64_t significand = 0x4d104d427de7fbcc; + int index = static_cast( + ((min_exponent + fp::num_significand_bits - 1) * (significand >> shift) + + ((int64_t(1) << shift) - 1)) // ceil + >> 32 // arithmetic shift + ); + // Decimal exponent of the first (smallest) cached power of 10. + const int first_dec_exp = -348; + // Difference between 2 consecutive decimal exponents in cached powers of 10. + const int dec_exp_step = 8; + index = (index - first_dec_exp - 1) / dec_exp_step + 1; + pow10_exponent = first_dec_exp + index * dec_exp_step; + // Using *(x + index) instead of x[index] avoids an issue with some compilers + // using the EDG frontend (e.g. nvhpc/22.3 in C++17 mode). + return {*(data::pow10_significands + index), + *(data::pow10_exponents + index)}; +} + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else +FMT_API auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...) -> int; +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER -// Formats a floating-point number with snprintf. +// Formats a floating-point number with snprintf using the hexfloat format. template auto snprintf_float(T value, int precision, float_specs specs, - buffer& buf) -> int; + buffer& buf) -> int { + // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. + FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer"); + FMT_ASSERT(specs.format == float_format::hex, ""); + static_assert(!std::is_same::value, ""); + + // Build the format string. + char format[7]; // The longest format is "%#.*Le". + char* format_ptr = format; + *format_ptr++ = '%'; + if (specs.showpoint) *format_ptr++ = '#'; + if (precision >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (std::is_same()) *format_ptr++ = 'L'; + *format_ptr++ = specs.upper ? 'A' : 'a'; + *format_ptr = '\0'; + + // Format using snprintf. + auto offset = buf.size(); + for (;;) { + auto begin = buf.data() + offset; + auto capacity = buf.capacity() - offset; + abort_fuzzing_if(precision > 100000); + // Suppress the warning about a nonliteral format string. + // Cannot use auto because of a bug in MinGW (#1532). + int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; + int result = precision >= 0 + ? snprintf_ptr(begin, capacity, format, precision, value) + : snprintf_ptr(begin, capacity, format, value); + if (result < 0) { + // The buffer will grow exponentially. + buf.try_reserve(buf.capacity() + 1); + continue; + } + auto size = to_unsigned(result); + // Size equal to capacity means that the last character was truncated. + if (size < capacity) { + buf.try_resize(size + offset); + return 0; + } + buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'. + } +} + +template +using convert_float_result = + conditional_t::value || sizeof(T) == sizeof(double), + double, T>; -template auto promote_float(T value) -> T { return value; } -inline auto promote_float(float value) -> double { - return static_cast(value); +template +constexpr auto convert_float(T value) -> convert_float_result { + return static_cast>(value); } template @@ -1282,8 +1655,9 @@ FMT_CONSTEXPR auto write_padded(OutputIt out, static_assert(align == align::left || align == align::right, ""); unsigned spec_width = to_unsigned(specs.width); size_t padding = spec_width > width ? spec_width - width : 0; - auto* shifts = align == align::left ? data::left_padding_shifts - : data::right_padding_shifts; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; size_t left_padding = padding >> shifts[specs.align]; size_t right_padding = padding - left_padding; auto it = reserve(out, size + padding * specs.fill.size()); @@ -1325,11 +1699,172 @@ auto write_ptr(OutputIt out, UIntPtr value, : base_iterator(out, write(reserve(out, size))); } +// Returns true iff the code point cp is printable. +FMT_API auto is_printable(uint32_t cp) -> bool; + +inline auto needs_escape(uint32_t cp) -> bool { + return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || + !is_printable(cp); +} + +template struct find_escape_result { + const Char* begin; + const Char* end; + uint32_t cp; +}; + +template +using make_unsigned_char = + typename conditional_t::value, + std::make_unsigned, + type_identity>::type; + +template +auto find_escape(const Char* begin, const Char* end) + -> find_escape_result { + for (; begin != end; ++begin) { + uint32_t cp = static_cast>(*begin); + if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; + if (needs_escape(cp)) return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char* begin, const char* end) + -> find_escape_result { + if (!is_utf8()) return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), + [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; +} + +#define FMT_STRING_IMPL(s, base, explicit) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ + using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ + operator fmt::basic_string_view() const { \ + return fmt::detail_exported::compile_string_to_view(s); \ + } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() + +/** + \rst + Constructs a compile-time format string from a string literal *s*. + + **Example**:: + + // A compile-time error because 'd' is an invalid specifier for strings. + std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + \endrst + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, ) + +template +auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { + *out++ = static_cast('\\'); + *out++ = static_cast(prefix); + Char buf[width]; + fill_n(buf, width, static_cast('0')); + format_uint<4>(buf, cp, width); + return copy_str(buf, buf + width, out); +} + +template +auto write_escaped_cp(OutputIt out, const find_escape_result& escape) + -> OutputIt { + auto c = static_cast(escape.cp); + switch (escape.cp) { + case '\n': + *out++ = static_cast('\\'); + c = static_cast('n'); + break; + case '\r': + *out++ = static_cast('\\'); + c = static_cast('r'); + break; + case '\t': + *out++ = static_cast('\\'); + c = static_cast('t'); + break; + case '"': + FMT_FALLTHROUGH; + case '\'': + FMT_FALLTHROUGH; + case '\\': + *out++ = static_cast('\\'); + break; + default: + if (is_utf8()) { + if (escape.cp < 0x100) { + return write_codepoint<2, Char>(out, 'x', escape.cp); + } + if (escape.cp < 0x10000) { + return write_codepoint<4, Char>(out, 'u', escape.cp); + } + if (escape.cp < 0x110000) { + return write_codepoint<8, Char>(out, 'U', escape.cp); + } + } + for (Char escape_char : basic_string_view( + escape.begin, to_unsigned(escape.end - escape.begin))) { + out = write_codepoint<2, Char>(out, 'x', + static_cast(escape_char) & 0xFF); + } + return out; + } + *out++ = c; + return out; +} + +template +auto write_escaped_string(OutputIt out, basic_string_view str) + -> OutputIt { + *out++ = static_cast('"'); + auto begin = str.begin(), end = str.end(); + do { + auto escape = find_escape(begin, end); + out = copy_str(begin, escape.begin, out); + begin = escape.end; + if (!begin) break; + out = write_escaped_cp(out, escape); + } while (begin != end); + *out++ = static_cast('"'); + return out; +} + +template +auto write_escaped_char(OutputIt out, Char v) -> OutputIt { + *out++ = static_cast('\''); + if ((needs_escape(static_cast(v)) && v != static_cast('"')) || + v == static_cast('\'')) { + out = write_escaped_cp( + out, find_escape_result{&v, &v + 1, static_cast(v)}); + } else { + *out++ = v; + } + *out++ = static_cast('\''); + return out; +} + template FMT_CONSTEXPR auto write_char(OutputIt out, Char value, const basic_format_specs& specs) -> OutputIt { + bool is_debug = specs.type == presentation_type::debug; return write_padded(out, specs, 1, [=](reserve_iterator it) { + if (is_debug) return write_escaped_char(it, value); *it++ = value; return it; }); @@ -1393,56 +1928,94 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, }); } -template -auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, - const basic_format_specs& specs, locale_ref loc) - -> bool { +template class digit_grouping { + private: + thousands_sep_result sep_; + + struct next_state { + std::string::const_iterator group; + int pos; + }; + next_state initial_state() const { return {sep_.grouping.begin(), 0}; } + + // Returns the next digit group separator position. + int next(next_state& state) const { + if (!sep_.thousands_sep) return max_value(); + if (state.group == sep_.grouping.end()) + return state.pos += sep_.grouping.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + + public: + explicit digit_grouping(locale_ref loc, bool localized = true) { + if (localized) + sep_ = thousands_sep(loc); + else + sep_.thousands_sep = Char(); + } + explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} + + Char separator() const { return sep_.thousands_sep; } + + int count_separators(int num_digits) const { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + Out apply(Out out, basic_string_view digits) const { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) { + if (i >= num_digits) break; + separators.push_back(i); + } + for (int i = 0, sep_index = static_cast(separators.size() - 1); + i < num_digits; ++i) { + if (num_digits - i == separators[sep_index]) { + *out++ = separator(); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; + } +}; + +template +auto write_int_localized(OutputIt out, UInt value, unsigned prefix, + const basic_format_specs& specs, + const digit_grouping& grouping) -> OutputIt { static_assert(std::is_same, UInt>::value, ""); - const auto sep_size = 1; - auto ts = thousands_sep(loc); - if (!ts.thousands_sep) return false; int num_digits = count_digits(value); - int size = num_digits, n = num_digits; - const std::string& groups = ts.grouping; - std::string::const_iterator group = groups.cbegin(); - while (group != groups.cend() && n > *group && *group > 0 && - *group != max_value()) { - size += sep_size; - n -= *group; - ++group; - } - if (group == groups.cend()) size += sep_size * ((n - 1) / groups.back()); char digits[40]; format_decimal(digits, value, num_digits); - basic_memory_buffer buffer; - if (prefix != 0) ++size; - const auto usize = to_unsigned(size); - buffer.resize(usize); - basic_string_view s(&ts.thousands_sep, sep_size); - // Index of a decimal digit with the least significant digit having index 0. - int digit_index = 0; - group = groups.cbegin(); - auto p = buffer.data() + size - 1; - for (int i = num_digits - 1; i > 0; --i) { - *p-- = static_cast(digits[i]); - if (*group <= 0 || ++digit_index % *group != 0 || - *group == max_value()) - continue; - if (group + 1 != groups.cend()) { - digit_index = 0; - ++group; - } - std::uninitialized_copy(s.data(), s.data() + s.size(), - make_checked(p, s.size())); - p -= s.size(); - } - *p-- = static_cast(*digits); - if (prefix != 0) *p = static_cast(prefix); - auto data = buffer.data(); - out = write_padded( - out, specs, usize, usize, [=](reserve_iterator it) { - return copy_str(data, data + size, it); + unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + + grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + if (prefix != 0) { + char sign = static_cast(prefix); + *it++ = static_cast(sign); + } + return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); }); +} + +template +auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, + const basic_format_specs& specs, locale_ref loc) + -> bool { + auto grouping = digit_grouping(loc); + out = write_int_localized(out, value, prefix, specs, grouping); return true; } @@ -1465,7 +2038,9 @@ FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) prefix = 0x01000000 | '-'; abs_value = 0 - abs_value; } else { - prefix = data::prefixes[sign]; + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + prefix = prefixes[sign]; } return {abs_value, prefix}; } @@ -1477,10 +2052,9 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, static_assert(std::is_same>::value, ""); auto abs_value = arg.abs_value; auto prefix = arg.prefix; - auto utype = static_cast(specs.type); switch (specs.type) { - case 0: - case 'd': { + case presentation_type::none: + case presentation_type::dec: { if (specs.localized && write_int_localized(out, static_cast>(abs_value), prefix, specs, loc)) { @@ -1492,52 +2066,61 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, return format_decimal(it, abs_value, num_digits).end; }); } - case 'x': - case 'X': { - if (specs.alt) prefix_append(prefix, (utype << 8) | '0'); - bool upper = specs.type != 'x'; + case presentation_type::hex_lower: + case presentation_type::hex_upper: { + bool upper = specs.type == presentation_type::hex_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); int num_digits = count_digits<4>(abs_value); return write_int( out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<4, Char>(it, abs_value, num_digits, upper); }); } - case 'b': - case 'B': { - if (specs.alt) prefix_append(prefix, (utype << 8) | '0'); + case presentation_type::bin_lower: + case presentation_type::bin_upper: { + bool upper = specs.type == presentation_type::bin_upper; + if (specs.alt) + prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); int num_digits = count_digits<1>(abs_value); return write_int(out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<1, Char>(it, abs_value, num_digits); }); } - case 'o': { + case presentation_type::oct: { int num_digits = count_digits<3>(abs_value); - if (specs.alt && specs.precision <= num_digits && abs_value != 0) { - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) prefix_append(prefix, '0'); - } return write_int(out, num_digits, prefix, specs, [=](reserve_iterator it) { return format_uint<3, Char>(it, abs_value, num_digits); }); } - case 'c': + case presentation_type::chr: return write_char(out, static_cast(abs_value), specs); default: - FMT_THROW(format_error("invalid type specifier")); + throw_format_error("invalid type specifier"); } return out; } +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( + OutputIt out, write_int_arg arg, const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, arg, specs, loc); +} template ::value && !std::is_same::value && std::is_same>::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value, - const basic_format_specs& specs, locale_ref loc) - -> OutputIt { - return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const basic_format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, + loc); } // An inlined version of write used in format string compilation. template FMT_CONSTEXPR void operator=(const T&) {} + }; + + FMT_CONSTEXPR counting_iterator() : count_(0) {} + + FMT_CONSTEXPR size_t count() const { return count_; } + + FMT_CONSTEXPR counting_iterator& operator++() { + ++count_; + return *this; + } + FMT_CONSTEXPR counting_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + FMT_CONSTEXPR friend counting_iterator operator+(counting_iterator it, + difference_type n) { + it.count_ += static_cast(n); + return it; + } + + FMT_CONSTEXPR value_type operator*() const { return {}; } +}; + template FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, const basic_format_specs& specs) -> OutputIt { @@ -1557,10 +2180,17 @@ FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, auto size = s.size(); if (specs.precision >= 0 && to_unsigned(specs.precision) < size) size = code_point_index(s, to_unsigned(specs.precision)); - auto width = - specs.width != 0 ? compute_width(basic_string_view(data, size)) : 0; + bool is_debug = specs.type == presentation_type::debug; + size_t width = 0; + if (specs.width != 0) { + if (is_debug) + width = write_escaped_string(counting_iterator{}, s).count(); + else + width = compute_width(basic_string_view(data, size)); + } return write_padded(out, specs, size, width, [=](reserve_iterator it) { + if (is_debug) return write_escaped_string(it, s); return copy_str(data, data + size, it); }); } @@ -1578,14 +2208,37 @@ FMT_CONSTEXPR auto write(OutputIt out, const Char* s, -> OutputIt { return check_cstring_type_spec(specs.type) ? write(out, basic_string_view(s), specs, {}) - : write_ptr(out, to_uintptr(s), &specs); + : write_ptr(out, bit_cast(s), &specs); +} + +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + auto abs_value = static_cast>(value); + bool negative = is_negative(value); + // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. + if (negative) abs_value = ~abs_value + 1; + int num_digits = count_digits(abs_value); + auto size = (negative ? 1 : 0) + static_cast(num_digits); + auto it = reserve(out, size); + if (auto ptr = to_pointer(it, size)) { + if (negative) *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; + } + if (negative) *it++ = static_cast('-'); + it = format_decimal(it, abs_value, num_digits).end; + return base_iterator(out, it); } template -auto write_nonfinite(OutputIt out, bool isinf, basic_format_specs specs, - const float_specs& fspecs) -> OutputIt { +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, + basic_format_specs specs, + const float_specs& fspecs) -> OutputIt { auto str = - isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); + isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf"); constexpr size_t str_size = 3; auto sign = fspecs.sign; auto size = str_size + (sign ? 1 : 0); @@ -1594,7 +2247,7 @@ auto write_nonfinite(OutputIt out, bool isinf, basic_format_specs specs, specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); if (is_zero_fill) specs.fill[0] = static_cast(' '); return write_padded(out, specs, size, [=](reserve_iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); return copy_str(str, str + str_size, it); }); } @@ -1606,17 +2259,17 @@ struct big_decimal_fp { int exponent; }; -inline auto get_significand_size(const big_decimal_fp& fp) -> int { - return fp.significand_size; +constexpr auto get_significand_size(const big_decimal_fp& f) -> int { + return f.significand_size; } template -inline auto get_significand_size(const dragonbox::decimal_fp& fp) -> int { - return count_digits(fp.significand); +inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { + return count_digits(f.significand); } template -inline auto write_significand(OutputIt out, const char* significand, - int& significand_size) -> OutputIt { +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { return copy_str(significand, significand + significand_size, out); } template @@ -1624,6 +2277,19 @@ inline auto write_significand(OutputIt out, UInt significand, int significand_size) -> OutputIt { return format_decimal(out, significand, significand_size).end; } +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.separator()) { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} template ::value)> @@ -1631,14 +2297,20 @@ inline auto write_significand(Char* out, UInt significand, int significand_size, int integral_size, Char decimal_point) -> Char* { if (!decimal_point) return format_decimal(out, significand, significand_size).end; - auto end = format_decimal(out + 1, significand, significand_size).end; - if (integral_size == 1) { - out[0] = out[1]; - } else { - std::uninitialized_copy_n(out + 1, integral_size, - make_checked(out, to_unsigned(integral_size))); + out += significand_size + 1; + Char* end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) { + out -= 2; + copy2(out, digits2(static_cast(significand % 100))); + significand /= 100; + } + if (floating_size % 2 != 0) { + *--out = static_cast('0' + significand % 10); + significand /= 10; } - out[integral_size] = decimal_point; + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); return end; } @@ -1655,9 +2327,9 @@ inline auto write_significand(OutputIt out, UInt significand, } template -inline auto write_significand(OutputIt out, const char* significand, - int significand_size, int integral_size, - Char decimal_point) -> OutputIt { +FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { out = detail::copy_str_noinline(significand, significand + integral_size, out); if (!decimal_point) return out; @@ -1666,18 +2338,41 @@ inline auto write_significand(OutputIt out, const char* significand, significand + significand_size, out); } -template -auto write_float(OutputIt out, const DecimalFP& fp, - const basic_format_specs& specs, float_specs fspecs, - Char decimal_point) -> OutputIt { - auto significand = fp.significand; - int significand_size = get_significand_size(fp); - static const Char zero = static_cast('0'); +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int integral_size, + Char decimal_point, + const Grouping& grouping) -> OutputIt { + if (!grouping.separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(buffer_appender(buffer), significand, + significand_size, integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_str_noinline(buffer.data() + integral_size, + buffer.end(), out); +} + +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, + const basic_format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + auto significand = f.significand; + int significand_size = get_significand_size(f); + const Char zero = static_cast('0'); auto sign = fspecs.sign; size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); using iterator = reserve_iterator; - int output_exp = fp.exponent + significand_size - 1; + Char decimal_point = + fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + + int output_exp = f.exponent + significand_size - 1; auto use_exp_format = [=]() { if (fspecs.format == float_format::exp) return true; if (fspecs.format != float_format::general) return false; @@ -1703,7 +2398,7 @@ auto write_float(OutputIt out, const DecimalFP& fp, size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); char exp_char = fspecs.upper ? 'E' : 'e'; auto write = [=](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); // Insert a decimal point after the first digit and add an exponent. it = write_significand(it, significand, significand_size, 1, decimal_point); @@ -1715,23 +2410,23 @@ auto write_float(OutputIt out, const DecimalFP& fp, : base_iterator(out, write(reserve(out, size))); } - int exp = fp.exponent + significand_size; - if (fp.exponent >= 0) { + int exp = f.exponent + significand_size; + if (f.exponent >= 0) { // 1234e5 -> 123400000[.0+] - size += to_unsigned(fp.exponent); + size += to_unsigned(f.exponent); int num_zeros = fspecs.precision - exp; -#ifdef FMT_FUZZ - if (num_zeros > 5000) - throw std::runtime_error("fuzz mode - avoiding excessive cpu use"); -#endif + abort_fuzzing_if(num_zeros > 5000); if (fspecs.showpoint) { + ++size; if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 1; - if (num_zeros > 0) size += to_unsigned(num_zeros) + 1; + if (num_zeros > 0) size += to_unsigned(num_zeros); } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); - it = write_significand(it, significand, significand_size); - it = detail::fill_n(it, fp.exponent, zero); + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, + f.exponent, grouping); if (!fspecs.showpoint) return it; *it++ = decimal_point; return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; @@ -1740,10 +2435,12 @@ auto write_float(OutputIt out, const DecimalFP& fp, // 1234e-2 -> 12.34[0+] int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(significand_size)); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); it = write_significand(it, significand, significand_size, exp, - decimal_point); + decimal_point, grouping); return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; }); } @@ -1756,7 +2453,7 @@ auto write_float(OutputIt out, const DecimalFP& fp, bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = static_cast(data::signs[sign]); + if (sign) *it++ = detail::sign(sign); *it++ = zero; if (!pointy) return it; *it++ = decimal_point; @@ -1765,26 +2462,747 @@ auto write_float(OutputIt out, const DecimalFP& fp, }); } +template class fallback_digit_grouping { + public: + constexpr fallback_digit_grouping(locale_ref, bool) {} + + constexpr Char separator() const { return Char(); } + + constexpr int count_separators(int) const { return 0; } + + template + constexpr Out apply(Out out, basic_string_view) const { + return out; + } +}; + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, + const basic_format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, f, specs, fspecs, + loc); + } else { + return do_write_float(out, f, specs, fspecs, loc); + } +} + +template constexpr bool isnan(T value) { + return !(value >= value); // std::isnan doesn't support __float128. +} + +template +struct has_isfinite : std::false_type {}; + +template +struct has_isfinite> + : std::true_type {}; + +template ::value&& + has_isfinite::value)> +FMT_CONSTEXPR20 bool isfinite(T value) { + constexpr T inf = T(std::numeric_limits::infinity()); + if (is_constant_evaluated()) + return !detail::isnan(value) && value != inf && value != -inf; + return std::isfinite(value); +} +template ::value)> +FMT_CONSTEXPR bool isfinite(T value) { + T inf = T(std::numeric_limits::infinity()); + // std::isfinite doesn't support __float128. + return !detail::isnan(value) && value != inf && value != -inf; +} + +template ::value)> +FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { + if (is_constant_evaluated()) { +#ifdef __cpp_if_constexpr + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits >> (num_bits() - 1)) != 0; + } +#endif + } + return std::signbit(static_cast(value)); +} + +enum class round_direction { unknown, up, down }; + +// Given the divisor (normally a power of 10), the remainder = v % divisor for +// some number v and the error, returns whether v should be rounded up, down, or +// whether the rounding direction can't be determined due to error. +// error should be less than divisor / 2. +FMT_CONSTEXPR inline round_direction get_round_direction(uint64_t divisor, + uint64_t remainder, + uint64_t error) { + FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. + FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. + FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. + // Round down if (remainder + error) * 2 <= divisor. + if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) + return round_direction::down; + // Round up if (remainder - error) * 2 >= divisor. + if (remainder >= error && + remainder - error >= divisor - (remainder - error)) { + return round_direction::up; + } + return round_direction::unknown; +} + +namespace digits { +enum result { + more, // Generate more digits. + done, // Done generating digits. + error // Digit generation cancelled due to an error. +}; +} + +struct gen_digits_handler { + char* buf; + int size; + int precision; + int exp10; + bool fixed; + + FMT_CONSTEXPR digits::result on_digit(char digit, uint64_t divisor, + uint64_t remainder, uint64_t error, + bool integral) { + FMT_ASSERT(remainder < divisor, ""); + buf[size++] = digit; + if (!integral && error >= remainder) return digits::error; + if (size < precision) return digits::more; + if (!integral) { + // Check if error * 2 < divisor with overflow prevention. + // The check is not needed for the integral part because error = 1 + // and divisor > (1 << 32) there. + if (error >= divisor || error >= divisor - error) return digits::error; + } else { + FMT_ASSERT(error == 1 && divisor > 2, ""); + } + auto dir = get_round_direction(divisor, remainder, error); + if (dir != round_direction::up) + return dir == round_direction::down ? digits::done : digits::error; + ++buf[size - 1]; + for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') { + buf[0] = '1'; + if (fixed) + buf[size++] = '0'; + else + ++exp10; + } + return digits::done; + } +}; + +inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { + // Adjust fixed precision by exponent because it is relative to decimal + // point. + if (exp10 > 0 && precision > max_value() - exp10) + FMT_THROW(format_error("number is too big")); + precision += exp10; +} + +// Generates output using the Grisu digit-gen algorithm. +// error: the size of the region (lower, upper) outside of which numbers +// definitely do not round to value (Delta in Grisu3). +FMT_INLINE FMT_CONSTEXPR20 auto grisu_gen_digits(fp value, uint64_t error, + int& exp, + gen_digits_handler& handler) + -> digits::result { + const fp one(1ULL << -value.e, value.e); + // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be + // zero because it contains a product of two 64-bit numbers with MSB set (due + // to normalization) - 1, shifted right by at most 60 bits. + auto integral = static_cast(value.f >> -one.e); + FMT_ASSERT(integral != 0, ""); + FMT_ASSERT(integral == value.f >> -one.e, ""); + // The fractional part of scaled value (p2 in Grisu) c = value % one. + uint64_t fractional = value.f & (one.f - 1); + exp = count_digits(integral); // kappa in Grisu. + // Non-fixed formats require at least one digit and no precision adjustment. + if (handler.fixed) { + adjust_precision(handler.precision, exp + handler.exp10); + // Check if precision is satisfied just by leading zeros, e.g. + // format("{:.2f}", 0.001) gives "0.00" without generating any digits. + if (handler.precision <= 0) { + if (handler.precision < 0) return digits::done; + // Divide by 10 to prevent overflow. + uint64_t divisor = data::power_of_10_64[exp - 1] << -one.e; + auto dir = get_round_direction(divisor, value.f / 10, error * 10); + if (dir == round_direction::unknown) return digits::error; + handler.buf[handler.size++] = dir == round_direction::up ? '1' : '0'; + return digits::done; + } + } + // Generate digits for the integral part. This can produce up to 10 digits. + do { + uint32_t digit = 0; + auto divmod_integral = [&](uint32_t divisor) { + digit = integral / divisor; + integral %= divisor; + }; + // This optimization by Milo Yip reduces the number of integer divisions by + // one per iteration. + switch (exp) { + case 10: + divmod_integral(1000000000); + break; + case 9: + divmod_integral(100000000); + break; + case 8: + divmod_integral(10000000); + break; + case 7: + divmod_integral(1000000); + break; + case 6: + divmod_integral(100000); + break; + case 5: + divmod_integral(10000); + break; + case 4: + divmod_integral(1000); + break; + case 3: + divmod_integral(100); + break; + case 2: + divmod_integral(10); + break; + case 1: + digit = integral; + integral = 0; + break; + default: + FMT_ASSERT(false, "invalid number of digits"); + } + --exp; + auto remainder = (static_cast(integral) << -one.e) + fractional; + auto result = handler.on_digit(static_cast('0' + digit), + data::power_of_10_64[exp] << -one.e, + remainder, error, true); + if (result != digits::more) return result; + } while (exp > 0); + // Generate digits for the fractional part. + for (;;) { + fractional *= 10; + error *= 10; + char digit = static_cast('0' + (fractional >> -one.e)); + fractional &= one.f - 1; + --exp; + auto result = handler.on_digit(digit, one.f, fractional, error, false); + if (result != digits::more) return result; + } +} + +class bigint { + private: + // A bigint is stored as an array of bigits (big digits), with bigit at index + // 0 being the least significant one. + using bigit = uint32_t; + using double_bigit = uint64_t; + enum { bigits_capacity = 32 }; + basic_memory_buffer bigits_; + int exp_; + + FMT_CONSTEXPR20 bigit operator[](int index) const { + return bigits_[to_unsigned(index)]; + } + FMT_CONSTEXPR20 bigit& operator[](int index) { + return bigits_[to_unsigned(index)]; + } + + static constexpr const int bigit_bits = num_bits(); + + friend struct formatter; + + FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { + auto result = static_cast((*this)[index]) - other - borrow; + (*this)[index] = static_cast(result); + borrow = static_cast(result >> (bigit_bits * 2 - 1)); + } + + FMT_CONSTEXPR20 void remove_leading_zeros() { + int num_bigits = static_cast(bigits_.size()) - 1; + while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; + bigits_.resize(to_unsigned(num_bigits + 1)); + } + + // Computes *this -= other assuming aligned bigints and *this >= other. + FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { + FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); + FMT_ASSERT(compare(*this, other) >= 0, ""); + bigit borrow = 0; + int i = other.exp_ - exp_; + for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) + subtract_bigits(i, other.bigits_[j], borrow); + while (borrow > 0) subtract_bigits(i, 0, borrow); + remove_leading_zeros(); + } + + FMT_CONSTEXPR20 void multiply(uint32_t value) { + const double_bigit wide_value = value; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + double_bigit result = bigits_[i] * wide_value + carry; + bigits_[i] = static_cast(result); + carry = static_cast(result >> bigit_bits); + } + if (carry != 0) bigits_.push_back(carry); + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR20 void multiply(UInt value) { + using half_uint = + conditional_t::value, uint64_t, uint32_t>; + const int shift = num_bits() - bigit_bits; + const UInt lower = static_cast(value); + const UInt upper = value >> num_bits(); + UInt carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + UInt result = lower * bigits_[i] + static_cast(carry); + carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + + (carry >> bigit_bits); + bigits_[i] = static_cast(result); + } + while (carry != 0) { + bigits_.push_back(static_cast(carry)); + carry >>= bigit_bits; + } + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR20 void assign(UInt n) { + size_t num_bigits = 0; + do { + bigits_[num_bigits++] = static_cast(n); + n >>= bigit_bits; + } while (n != 0); + bigits_.resize(num_bigits); + exp_ = 0; + } + + public: + FMT_CONSTEXPR20 bigint() : exp_(0) {} + explicit bigint(uint64_t n) { assign(n); } + + bigint(const bigint&) = delete; + void operator=(const bigint&) = delete; + + FMT_CONSTEXPR20 void assign(const bigint& other) { + auto size = other.bigits_.size(); + bigits_.resize(size); + auto data = other.bigits_.data(); + std::copy(data, data + size, make_checked(bigits_.data(), size)); + exp_ = other.exp_; + } + + template FMT_CONSTEXPR20 void operator=(Int n) { + FMT_ASSERT(n > 0, ""); + assign(uint64_or_128_t(n)); + } + + FMT_CONSTEXPR20 int num_bigits() const { + return static_cast(bigits_.size()) + exp_; + } + + FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) { + FMT_ASSERT(shift >= 0, ""); + exp_ += shift / bigit_bits; + shift %= bigit_bits; + if (shift == 0) return *this; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + bigit c = bigits_[i] >> (bigit_bits - shift); + bigits_[i] = (bigits_[i] << shift) + carry; + carry = c; + } + if (carry != 0) bigits_.push_back(carry); + return *this; + } + + template FMT_CONSTEXPR20 bigint& operator*=(Int value) { + FMT_ASSERT(value > 0, ""); + multiply(uint32_or_64_or_128_t(value)); + return *this; + } + + friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) { + int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); + if (num_lhs_bigits != num_rhs_bigits) + return num_lhs_bigits > num_rhs_bigits ? 1 : -1; + int i = static_cast(lhs.bigits_.size()) - 1; + int j = static_cast(rhs.bigits_.size()) - 1; + int end = i - j; + if (end < 0) end = 0; + for (; i >= end; --i, --j) { + bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; + if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; + } + if (i != j) return i > j ? 1 : -1; + return 0; + } + + // Returns compare(lhs1 + lhs2, rhs). + friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2, + const bigint& rhs) { + auto minimum = [](int a, int b) { return a < b ? a : b; }; + auto maximum = [](int a, int b) { return a > b ? a : b; }; + int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits()); + int num_rhs_bigits = rhs.num_bigits(); + if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; + if (max_lhs_bigits > num_rhs_bigits) return 1; + auto get_bigit = [](const bigint& n, int i) -> bigit { + return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; + }; + double_bigit borrow = 0; + int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_); + for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { + double_bigit sum = + static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); + bigit rhs_bigit = get_bigit(rhs, i); + if (sum > rhs_bigit + borrow) return 1; + borrow = rhs_bigit + borrow - sum; + if (borrow > 1) return -1; + borrow <<= bigit_bits; + } + return borrow != 0 ? -1 : 0; + } + + // Assigns pow(10, exp) to this bigint. + FMT_CONSTEXPR20 void assign_pow10(int exp) { + FMT_ASSERT(exp >= 0, ""); + if (exp == 0) return *this = 1; + // Find the top bit. + int bitmask = 1; + while (exp >= bitmask) bitmask <<= 1; + bitmask >>= 1; + // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by + // repeated squaring and multiplication. + *this = 5; + bitmask >>= 1; + while (bitmask != 0) { + square(); + if ((exp & bitmask) != 0) *this *= 5; + bitmask >>= 1; + } + *this <<= exp; // Multiply by pow(2, exp) by shifting. + } + + FMT_CONSTEXPR20 void square() { + int num_bigits = static_cast(bigits_.size()); + int num_result_bigits = 2 * num_bigits; + basic_memory_buffer n(std::move(bigits_)); + bigits_.resize(to_unsigned(num_result_bigits)); + auto sum = uint128_t(); + for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { + // Compute bigit at position bigit_index of the result by adding + // cross-product terms n[i] * n[j] such that i + j == bigit_index. + for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { + // Most terms are multiplied twice which can be optimized in the future. + sum += static_cast(n[i]) * n[j]; + } + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); // Compute the carry. + } + // Do the same for the top half. + for (int bigit_index = num_bigits; bigit_index < num_result_bigits; + ++bigit_index) { + for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) + sum += static_cast(n[i++]) * n[j--]; + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); + } + remove_leading_zeros(); + exp_ *= 2; + } + + // If this bigint has a bigger exponent than other, adds trailing zero to make + // exponents equal. This simplifies some operations such as subtraction. + FMT_CONSTEXPR20 void align(const bigint& other) { + int exp_difference = exp_ - other.exp_; + if (exp_difference <= 0) return; + int num_bigits = static_cast(bigits_.size()); + bigits_.resize(to_unsigned(num_bigits + exp_difference)); + for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) + bigits_[j] = bigits_[i]; + std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); + exp_ -= exp_difference; + } + + // Divides this bignum by divisor, assigning the remainder to this and + // returning the quotient. + FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) { + FMT_ASSERT(this != &divisor, ""); + if (compare(*this, divisor) < 0) return 0; + FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); + align(divisor); + int quotient = 0; + do { + subtract_aligned(divisor); + ++quotient; + } while (compare(*this, divisor) >= 0); + return quotient; + } +}; + +// format_dragon flags. +enum dragon { + predecessor_closer = 1, + fixup = 2, // Run fixup to correct exp10 which can be off by one. + fixed = 4, +}; + +// Formats a floating-point number using a variation of the Fixed-Precision +// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: +// https://fmt.dev/papers/p372-steele.pdf. +FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, + unsigned flags, int num_digits, + buffer& buf, int& exp10) { + bigint numerator; // 2 * R in (FPP)^2. + bigint denominator; // 2 * S in (FPP)^2. + // lower and upper are differences between value and corresponding boundaries. + bigint lower; // (M^- in (FPP)^2). + bigint upper_store; // upper's value if different from lower. + bigint* upper = nullptr; // (M^+ in (FPP)^2). + // Shift numerator and denominator by an extra bit or two (if lower boundary + // is closer) to make lower and upper integers. This eliminates multiplication + // by 2 during later computations. + bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; + int shift = is_predecessor_closer ? 2 : 1; + if (value.e >= 0) { + numerator = value.f; + numerator <<= value.e + shift; + lower = 1; + lower <<= value.e; + if (is_predecessor_closer) { + upper_store = 1; + upper_store <<= value.e + 1; + upper = &upper_store; + } + denominator.assign_pow10(exp10); + denominator <<= shift; + } else if (exp10 < 0) { + numerator.assign_pow10(-exp10); + lower.assign(numerator); + if (is_predecessor_closer) { + upper_store.assign(numerator); + upper_store <<= 1; + upper = &upper_store; + } + numerator *= value.f; + numerator <<= shift; + denominator = 1; + denominator <<= shift - value.e; + } else { + numerator = value.f; + numerator <<= shift; + denominator.assign_pow10(exp10); + denominator <<= shift - value.e; + lower = 1; + if (is_predecessor_closer) { + upper_store = 1ULL << 1; + upper = &upper_store; + } + } + int even = static_cast((value.f & 1) == 0); + if (!upper) upper = &lower; + if ((flags & dragon::fixup) != 0) { + if (add_compare(numerator, *upper, denominator) + even <= 0) { + --exp10; + numerator *= 10; + if (num_digits < 0) { + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1); + } + // Invariant: value == (numerator / denominator) * pow(10, exp10). + if (num_digits < 0) { + // Generate the shortest representation. + num_digits = 0; + char* data = buf.data(); + for (;;) { + int digit = numerator.divmod_assign(denominator); + bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. + // numerator + upper >[=] pow10: + bool high = add_compare(numerator, *upper, denominator) + even > 0; + data[num_digits++] = static_cast('0' + digit); + if (low || high) { + if (!low) { + ++data[num_digits - 1]; + } else if (high) { + int result = add_compare(numerator, numerator, denominator); + // Round half to even. + if (result > 0 || (result == 0 && (digit % 2) != 0)) + ++data[num_digits - 1]; + } + buf.try_resize(to_unsigned(num_digits)); + exp10 -= num_digits - 1; + return; + } + numerator *= 10; + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + // Generate the given number of digits. + exp10 -= num_digits - 1; + if (num_digits == 0) { + denominator *= 10; + auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + buf.push_back(digit); + return; + } + buf.try_resize(to_unsigned(num_digits)); + for (int i = 0; i < num_digits - 1; ++i) { + int digit = numerator.divmod_assign(denominator); + buf[i] = static_cast('0' + digit); + numerator *= 10; + } + int digit = numerator.divmod_assign(denominator); + auto result = add_compare(numerator, numerator, denominator); + if (result > 0 || (result == 0 && (digit % 2) != 0)) { + if (digit == 9) { + const auto overflow = '0' + 10; + buf[num_digits - 1] = overflow; + // Propagate the carry. + for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] == overflow) { + buf[0] = '1'; + ++exp10; + } + return; + } + ++digit; + } + buf[num_digits - 1] = static_cast('0' + digit); +} + +template +FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, + buffer& buf) -> int { + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); + FMT_ASSERT(value >= 0, "value is negative"); + auto converted_value = convert_float(value); + + const bool fixed = specs.format == float_format::fixed; + if (value <= 0) { // <= instead of == to silence a warning. + if (precision <= 0 || !fixed) { + buf.push_back('0'); + return 0; + } + buf.try_resize(to_unsigned(precision)); + fill_n(buf.data(), precision, '0'); + return -precision; + } + + int exp = 0; + bool use_dragon = true; + unsigned dragon_flags = 0; + if (!is_fast_float()) { + const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) + using info = dragonbox::float_info; + const auto f = basic_fp(converted_value); + // Compute exp, an approximate power of 10, such that + // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). + // This is based on log10(value) == log2(value) / log2(10) and approximation + // of log2(value) by e + num_fraction_bits idea from double-conversion. + exp = static_cast( + std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10)); + dragon_flags = dragon::fixup; + } else if (!is_constant_evaluated() && precision < 0) { + // Use Dragonbox for the shortest format. + if (specs.binary32) { + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } + auto dec = dragonbox::to_decimal(static_cast(value)); + write(buffer_appender(buf), dec.significand); + return dec.exponent; + } else { + // Use Grisu + Dragon4 for the given precision: + // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. + const int min_exp = -60; // alpha in Grisu. + int cached_exp10 = 0; // K in Grisu. + fp normalized = normalize(fp(converted_value)); + const auto cached_pow = get_cached_power( + min_exp - (normalized.e + fp::num_significand_bits), cached_exp10); + normalized = normalized * cached_pow; + gen_digits_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; + if (grisu_gen_digits(normalized, 1, exp, handler) != digits::error && + !is_constant_evaluated()) { + exp += handler.exp10; + buf.try_resize(to_unsigned(handler.size)); + use_dragon = false; + } else { + exp += handler.size - cached_exp10 - 1; + precision = handler.precision; + } + } + if (use_dragon) { + auto f = basic_fp(); + bool is_predecessor_closer = specs.binary32 + ? f.assign(static_cast(value)) + : f.assign(converted_value); + if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; + if (fixed) dragon_flags |= dragon::fixed; + // Limit precision to the maximum possible number of significant digits in + // an IEEE754 double because we don't need to generate zeros. + const int max_double_digits = 767; + if (precision > max_double_digits) precision = max_double_digits; + format_dragon(f, dragon_flags, precision, buf, exp); + } + if (!fixed && !specs.showpoint) { + // Remove trailing zeros. + auto num_digits = buf.size(); + while (num_digits > 0 && buf[num_digits - 1] == '0') { + --num_digits; + ++exp; + } + buf.try_resize(num_digits); + } + return exp; +} + template ::value)> -auto write(OutputIt out, T value, basic_format_specs specs, - locale_ref loc = {}) -> OutputIt { + FMT_ENABLE_IF(is_floating_point::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value, + basic_format_specs specs, locale_ref loc = {}) + -> OutputIt { if (const_check(!is_supported_floating_point(value))) return out; float_specs fspecs = parse_float_type_spec(specs); fspecs.sign = specs.sign; - if (std::signbit(value)) { // value < 0 is false for NaN so use signbit. + if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. fspecs.sign = sign::minus; value = -value; } else if (fspecs.sign == sign::minus) { fspecs.sign = sign::none; } - if (!std::isfinite(value)) - return write_nonfinite(out, std::isinf(value), specs, fspecs); + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isnan(value), specs, fspecs); if (specs.align == align::numeric && fspecs.sign) { auto it = reserve(out, 1); - *it++ = static_cast(data::signs[fspecs.sign]); + *it++ = detail::sign(fspecs.sign); out = base_iterator(out, it); fspecs.sign = sign::none; if (specs.width != 0) --specs.width; @@ -1792,55 +3210,55 @@ auto write(OutputIt out, T value, basic_format_specs specs, memory_buffer buffer; if (fspecs.format == float_format::hex) { - if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]); - snprintf_float(promote_float(value), specs.precision, fspecs, buffer); + if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); + snprintf_float(convert_float(value), specs.precision, fspecs, buffer); return write_bytes(out, {buffer.data(), buffer.size()}, specs); } - int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6; + int precision = specs.precision >= 0 || specs.type == presentation_type::none + ? specs.precision + : 6; if (fspecs.format == float_format::exp) { if (precision == max_value()) - FMT_THROW(format_error("number is too big")); + throw_format_error("number is too big"); else ++precision; + } else if (fspecs.format != float_format::fixed && precision == 0) { + precision = 1; } if (const_check(std::is_same())) fspecs.binary32 = true; - fspecs.use_grisu = is_fast_float(); - int exp = format_float(promote_float(value), precision, fspecs, buffer); + int exp = format_float(convert_float(value), precision, fspecs, buffer); fspecs.precision = precision; - Char point = - fspecs.locale ? decimal_point(loc) : static_cast('.'); - auto fp = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; - return write_float(out, fp, specs, fspecs, point); + auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; + return write_float(out, f, specs, fspecs, loc); } template ::value)> -auto write(OutputIt out, T value) -> OutputIt { +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { + if (is_constant_evaluated()) + return write(out, value, basic_format_specs()); if (const_check(!is_supported_floating_point(value))) return out; - using floaty = conditional_t::value, double, T>; - using uint = typename dragonbox::float_info::carrier_uint; - auto bits = bit_cast(value); - auto fspecs = float_specs(); - auto sign_bit = bits & (uint(1) << (num_bits() - 1)); - if (sign_bit != 0) { + if (detail::signbit(value)) { fspecs.sign = sign::minus; value = -value; } - static const auto specs = basic_format_specs(); + constexpr auto specs = basic_format_specs(); + using floaty = conditional_t::value, double, T>; + using uint = typename dragonbox::float_info::carrier_uint; uint mask = exponent_mask(); - if ((bits & mask) == mask) - return write_nonfinite(out, std::isinf(value), specs, fspecs); + if ((bit_cast(value) & mask) == mask) + return write_nonfinite(out, std::isnan(value), specs, fspecs); auto dec = dragonbox::to_decimal(static_cast(value)); - return write_float(out, dec, specs, fspecs, static_cast('.')); + return write_float(out, dec, specs, fspecs, {}); } template ::value && + FMT_ENABLE_IF(is_floating_point::value && !is_fast_float::value)> inline auto write(OutputIt out, T value) -> OutputIt { return write(out, value, basic_format_specs()); @@ -1867,29 +3285,7 @@ constexpr auto write(OutputIt out, const T& value) -> OutputIt { return write(out, to_string_view(value)); } -template ::value && - !std::is_same::value && - !std::is_same::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - auto abs_value = static_cast>(value); - bool negative = is_negative(value); - // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. - if (negative) abs_value = ~abs_value + 1; - int num_digits = count_digits(abs_value); - auto size = (negative ? 1 : 0) + static_cast(num_digits); - auto it = reserve(out, size); - if (auto ptr = to_pointer(it, size)) { - if (negative) *ptr++ = static_cast('-'); - format_decimal(ptr, abs_value, num_digits); - return out; - } - if (negative) *it++ = static_cast('-'); - it = format_decimal(it, abs_value, num_digits).end; - return base_iterator(out, it); -} - -// FMT_ENABLE_IF() condition separated to workaround MSVC bug +// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. template < typename Char, typename OutputIt, typename T, bool check = @@ -1898,8 +3294,7 @@ template < type::custom_type, FMT_ENABLE_IF(check)> FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - return write( - out, static_cast::type>(value)); + return write(out, static_cast>(value)); } template & specs = {}, locale_ref = {}) -> OutputIt { - return specs.type && specs.type != 's' + return specs.type != presentation_type::none && + specs.type != presentation_type::string ? write(out, value ? 1 : 0, specs, {}) : write_bytes(out, value ? "true" : "false", specs); } @@ -1923,10 +3319,9 @@ template FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) -> OutputIt { if (!value) { - FMT_THROW(format_error("string pointer is null")); + throw_format_error("string pointer is null"); } else { - auto length = std::char_traits::length(value); - out = write(out, basic_string_view(value, length)); + out = write(out, basic_string_view(value)); } return out; } @@ -1937,21 +3332,31 @@ auto write(OutputIt out, const T* value, const basic_format_specs& specs = {}, locale_ref = {}) -> OutputIt { check_pointer_type_spec(specs.type, error_handler()); - return write_ptr(out, to_uintptr(value), &specs); + return write_ptr(out, bit_cast(value), &specs); } -template -FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> - typename std::enable_if< - mapped_type_constant>::value == - type::custom_type, - OutputIt>::type { - using context_type = basic_format_context; +// A write overload that handles implicit conversions. +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< + std::is_class::value && !is_string::value && + !is_floating_point::value && !std::is_same::value && + !std::is_same().map(value))>::value, + OutputIt> { + return write(out, arg_mapper().map(value)); +} + +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) + -> enable_if_t::value == type::custom_type, + OutputIt> { using formatter_type = - conditional_t::value, - typename context_type::template formatter_type, + conditional_t::value, + typename Context::template formatter_type, fallback_formatter>; - context_type ctx(out, {}, {}); + auto ctx = Context(out, {}, {}); return formatter_type().format(value, ctx); } @@ -2128,43 +3533,17 @@ FMT_CONSTEXPR void handle_dynamic_spec(int& value, } } -#define FMT_STRING_IMPL(s, base, explicit) \ - [] { \ - /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ - /* Use a macro-like name to avoid shadowing warnings. */ \ - struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ - using char_type = fmt::remove_cvref_t; \ - FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ - operator fmt::basic_string_view() const { \ - return fmt::detail_exported::compile_string_to_view(s); \ - } \ - }; \ - return FMT_COMPILE_STRING(); \ - }() - -/** - \rst - Constructs a compile-time format string from a string literal *s*. - - **Example**:: - - // A compile-time error because 'd' is an invalid specifier for strings. - std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); - \endrst - */ -#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, ) - #if FMT_USE_USER_DEFINED_LITERALS template struct udl_formatter { basic_string_view str; template auto operator()(T&&... args) const -> std::basic_string { - return vformat(str, fmt::make_args_checked(str, args...)); + return vformat(str, fmt::make_format_args>(args...)); } }; -# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +# if FMT_USE_NONTYPE_TEMPLATE_ARGS template Str> struct statically_named_arg : view { @@ -2213,10 +3592,10 @@ auto vformat(const Locale& loc, basic_string_view format_str, using format_func = void (*)(detail::buffer&, int, const char*); FMT_API void format_error_code(buffer& out, int error_code, - string_view message) FMT_NOEXCEPT; + string_view message) noexcept; FMT_API void report_error(format_func func, int error_code, - const char* message) FMT_NOEXCEPT; + const char* message) noexcept; FMT_END_DETAIL_NAMESPACE FMT_API auto vsystem_error(int error_code, string_view format_str, @@ -2262,12 +3641,11 @@ auto system_error(int error_code, format_string fmt, T&&... args) \endrst */ FMT_API void format_system_error(detail::buffer& out, int error_code, - const char* message) FMT_NOEXCEPT; + const char* message) noexcept; // Reports a system error without throwing an exception. // Can be used to report errors from destructors. -FMT_API void report_system_error(int error_code, - const char* message) FMT_NOEXCEPT; +FMT_API void report_system_error(int error_code, const char* message) noexcept; /** Fast integer formatter. */ class format_int { @@ -2349,27 +3727,6 @@ formatter(ctx.out(), val, specs_, ctx.locale()); } -#define FMT_FORMAT_AS(Type, Base) \ - template \ - struct formatter : formatter { \ - template \ - auto format(Type const& val, FormatContext& ctx) const \ - -> decltype(ctx.out()) { \ - return formatter::format(static_cast(val), ctx); \ - } \ - } - -FMT_FORMAT_AS(signed char, int); -FMT_FORMAT_AS(unsigned char, unsigned); -FMT_FORMAT_AS(short, int); -FMT_FORMAT_AS(unsigned short, unsigned); -FMT_FORMAT_AS(long, long long); -FMT_FORMAT_AS(unsigned long, unsigned long long); -FMT_FORMAT_AS(Char*, const Char*); -FMT_FORMAT_AS(std::basic_string, basic_string_view); -FMT_FORMAT_AS(std::nullptr_t, const void*); -FMT_FORMAT_AS(detail::std_string_view, basic_string_view); - template struct formatter : formatter { template @@ -2459,6 +3816,28 @@ template auto ptr(const std::shared_ptr& p) -> const void* { return p.get(); } +/** + \rst + Converts ``e`` to the underlying type. + + **Example**:: + + enum class color { red, green, blue }; + auto s = fmt::format("{}", fmt::underlying(color::red)); + \endrst + */ +template +constexpr auto underlying(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} + +namespace enums { +template ::value)> +constexpr auto format_as(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} +} // namespace enums + class bytes { private: string_view data_; @@ -2493,6 +3872,52 @@ template <> struct formatter { } }; +// group_digits_view is not derived from view because it copies the argument. +template struct group_digits_view { T value; }; + +/** + \rst + Returns a view that formats an integer value using ',' as a locale-independent + thousands separator. + + **Example**:: + + fmt::print("{}", fmt::group_digits(12345)); + // Output: "12,345" + \endrst + */ +template auto group_digits(T value) -> group_digits_view { + return {value}; +} + +template struct formatter> : formatter { + private: + detail::dynamic_format_specs specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + using handler_type = detail::dynamic_specs_handler; + detail::specs_checker handler(handler_type(specs_, ctx), + detail::type::int_type); + auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); + detail::check_string_type_spec(specs_.type, ctx.error_handler()); + return it; + } + + template + auto format(group_digits_view t, FormatContext& ctx) + -> decltype(ctx.out()) { + detail::handle_dynamic_spec(specs_.width, + specs_.width_ref, ctx); + detail::handle_dynamic_spec( + specs_.precision, specs_.precision_ref, ctx); + return detail::write_int_localized( + ctx.out(), static_cast>(t.value), 0, specs_, + detail::digit_grouping({"\3", ','})); + } +}; + template struct join_view : detail::view { It begin; @@ -2503,13 +3928,15 @@ struct join_view : detail::view { : begin(b), end(e), sep(s) {} }; -template -using arg_join FMT_DEPRECATED_ALIAS = join_view; - template struct formatter, Char> { private: - using value_type = typename std::iterator_traits::value_type; + using value_type = +#ifdef __cpp_lib_ranges + std::iter_value_t; +#else + typename std::iterator_traits::value_type; +#endif using context = buffer_context; using mapper = detail::arg_mapper; @@ -2538,16 +3965,18 @@ struct formatter, Char> { } template - auto format(const join_view& value, FormatContext& ctx) - -> decltype(ctx.out()) { + auto format(const join_view& value, + FormatContext& ctx) const -> decltype(ctx.out()) { auto it = value.begin; auto out = ctx.out(); if (it != value.end) { - out = value_formatter_.format(map(*it++), ctx); + out = value_formatter_.format(map(*it), ctx); + ++it; while (it != value.end) { out = detail::copy_str(value.sep.begin(), value.sep.end(), out); ctx.advance_to(out); - out = value_formatter_.format(map(*it++), ctx); + out = value_formatter_.format(map(*it), ctx); + ++it; } } return out; @@ -2555,8 +3984,8 @@ struct formatter, Char> { }; /** - Returns an object that formats the iterator range `[begin, end)` with - elements separated by `sep`. + Returns a view that formats the iterator range `[begin, end)` with elements + separated by `sep`. */ template auto join(It begin, Sentinel end, string_view sep) -> join_view { @@ -2565,7 +3994,7 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view { /** \rst - Returns an object that formats `range` with elements separated by `sep`. + Returns a view that formats `range` with elements separated by `sep`. **Example**:: @@ -2604,7 +4033,7 @@ inline auto to_string(const T& value) -> std::string { } template ::value)> -inline auto to_string(T value) -> std::string { +FMT_NODISCARD inline auto to_string(T value) -> std::string { // The buffer should be large enough to store the number including the sign // or "false" for bool. constexpr int max_size = detail::digits10() + 2; @@ -2614,7 +4043,7 @@ inline auto to_string(T value) -> std::string { } template -auto to_string(const basic_memory_buffer& buf) +FMT_NODISCARD auto to_string(const basic_memory_buffer& buf) -> std::basic_string { auto size = buf.size(); detail::assume(size < std::basic_string().max_size()); @@ -2654,9 +4083,10 @@ void vformat_to( basic_format_parse_context parse_context; buffer_context context; - format_handler(buffer_appender out, basic_string_view str, - basic_format_args> args, locale_ref loc) - : parse_context(str), context(out, args, loc) {} + format_handler(buffer_appender p_out, basic_string_view str, + basic_format_args> p_args, + locale_ref p_loc) + : parse_context(str), context(p_out, p_args, p_loc) {} void on_text(const Char* begin, const Char* end) { auto text = basic_string_view(begin, to_unsigned(end - begin)); @@ -2713,20 +4143,6 @@ extern template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result; extern template FMT_API auto decimal_point_impl(locale_ref) -> char; extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; -extern template auto format_float(double value, int precision, - float_specs specs, buffer& buf) - -> int; -extern template auto format_float(long double value, int precision, - float_specs specs, - buffer& buf) -> int; -void snprintf_float(float, int, float_specs, buffer&) = delete; -extern template auto snprintf_float(double value, int precision, - float_specs specs, - buffer& buf) -> int; -extern template auto snprintf_float(long double value, - int precision, - float_specs specs, - buffer& buf) -> int; #endif // FMT_HEADER_ONLY FMT_END_DETAIL_NAMESPACE @@ -2743,33 +4159,16 @@ inline namespace literals { fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); \endrst */ -# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -template -constexpr auto operator""_a() - -> detail::udl_arg, - sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> { - return {}; +# if FMT_USE_NONTYPE_TEMPLATE_ARGS +template constexpr auto operator""_a() { + using char_t = remove_cvref_t; + return detail::udl_arg(); } # else constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg { return {s}; } # endif - -/** - \rst - User-defined literal equivalent of :func:`fmt::format`. - - **Example**:: - - using namespace fmt::literals; - std::string message = "The answer is {}"_format(42); - \endrst - */ -constexpr auto operator"" _format(const char* s, size_t n) - -> detail::udl_formatter { - return {{s, n}}; -} } // namespace literals #endif // FMT_USE_USER_DEFINED_LITERALS @@ -2786,14 +4185,6 @@ inline auto format(const Locale& loc, format_string fmt, T&&... args) return vformat(loc, string_view(fmt), fmt::make_format_args(args...)); } -template -FMT_DEPRECATED auto format_to(basic_memory_buffer& buf, - format_string fmt, T&&... args) - -> appender { - detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...)); - return appender(buf); -} - template ::value&& detail::is_locale::value)> @@ -2816,10 +4207,6 @@ FMT_INLINE auto format_to(OutputIt out, const Locale& loc, FMT_MODULE_EXPORT_END FMT_END_NAMESPACE -#ifdef FMT_DEPRECATED_INCLUDE_XCHAR -# include "xchar.h" -#endif - #ifdef FMT_HEADER_ONLY # define FMT_FUNC inline # include "format-inl.h" diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/os.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/os.h index f6c0f3298..d82be1125 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/os.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/os.h @@ -9,10 +9,8 @@ #define FMT_OS_H_ #include -#include // locale_t #include #include -#include // strtod_l #include // std::system_error #if defined __APPLE__ || defined(__FreeBSD__) @@ -21,17 +19,20 @@ #include "format.h" +#ifndef FMT_USE_FCNTL // UWP doesn't provide _pipe. -#if FMT_HAS_INCLUDE("winapifamily.h") -# include -#endif -#if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ - defined(__linux__)) && \ - (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) -# include // for O_RDONLY -# define FMT_USE_FCNTL 1 -#else -# define FMT_USE_FCNTL 0 +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ + defined(__linux__)) && \ + (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# include // for O_RDONLY +# define FMT_USE_FCNTL 1 +# else +# define FMT_USE_FCNTL 0 +# endif #endif #ifndef FMT_POSIX @@ -138,7 +139,7 @@ template struct formatter { }; #ifdef _WIN32 -FMT_API const std::error_category& system_category() FMT_NOEXCEPT; +FMT_API const std::error_category& system_category() noexcept; FMT_BEGIN_DETAIL_NAMESPACE // A converter from UTF-16 to UTF-8. @@ -162,7 +163,7 @@ class utf16_to_utf8 { }; FMT_API void format_windows_error(buffer& out, int error_code, - const char* message) FMT_NOEXCEPT; + const char* message) noexcept; FMT_END_DETAIL_NAMESPACE FMT_API std::system_error vwindows_error(int error_code, string_view format_str, @@ -204,10 +205,9 @@ std::system_error windows_error(int error_code, string_view message, // 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; +FMT_API void report_windows_error(int error_code, const char* message) noexcept; #else -inline const std::error_category& system_category() FMT_NOEXCEPT { +inline const std::error_category& system_category() noexcept { return std::system_category(); } #endif // _WIN32 @@ -234,13 +234,13 @@ class buffered_file { void operator=(const buffered_file&) = delete; // Constructs a buffered_file object which doesn't represent any file. - buffered_file() FMT_NOEXCEPT : file_(nullptr) {} + buffered_file() noexcept : file_(nullptr) {} // Destroys the object closing the file it represents if any. - FMT_API ~buffered_file() FMT_NOEXCEPT; + FMT_API ~buffered_file() noexcept; public: - buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) { + buffered_file(buffered_file&& other) noexcept : file_(other.file_) { other.file_ = nullptr; } @@ -258,11 +258,9 @@ class buffered_file { FMT_API void close(); // Returns the pointer to a FILE object representing this file. - FILE* get() const FMT_NOEXCEPT { return file_; } + FILE* get() const 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; + FMT_API int descriptor() const; void vprint(string_view format_str, format_args args) { fmt::vprint(file_, format_str, args); @@ -276,12 +274,12 @@ class buffered_file { #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 +// Methods that are not declared with 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 { +class FMT_API file { private: int fd_; // File descriptor. @@ -300,16 +298,16 @@ class file { }; // Constructs a file object which doesn't represent any file. - file() FMT_NOEXCEPT : fd_(-1) {} + file() noexcept : fd_(-1) {} // Opens a file and constructs a file object representing this file. - FMT_API file(cstring_view path, int oflag); + 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; } + file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } // Move assignment is not noexcept because close may throw. file& operator=(file&& other) { @@ -320,43 +318,43 @@ class file { } // Destroys the object closing the file it represents if any. - FMT_API ~file() FMT_NOEXCEPT; + ~file() noexcept; // Returns the file descriptor. - int descriptor() const FMT_NOEXCEPT { return fd_; } + int descriptor() const noexcept { return fd_; } // Closes the file. - FMT_API void close(); + void close(); // Returns the file size. The size has signed type for consistency with // stat::st_size. - FMT_API long long size() const; + 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); + 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); + 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); + 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); + 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; + void dup2(int fd, std::error_code& ec) 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); + 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); + buffered_file fdopen(const char* mode); }; // Returns the memory page size. @@ -390,23 +388,26 @@ struct ostream_params { : ostream_params(params...) { this->buffer_size = bs.value; } + +// Intel has a bug that results in failure to deduce a constructor +// for empty parameter packs. +# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 + ostream_params(int new_oflag) : oflag(new_oflag) {} + ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} +# endif }; FMT_END_DETAIL_NAMESPACE -constexpr detail::buffer_size buffer_size; +// Added {} below to work around default constructor error known to +// occur in Xcode versions 7.2.1 and 8.2.1. +constexpr detail::buffer_size buffer_size{}; /** A fast output stream which is not thread-safe. */ class FMT_API ostream final : private detail::buffer { 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) @@ -426,6 +427,12 @@ class FMT_API ostream final : private detail::buffer { delete[] data(); } + void flush() { + if (size() == 0) return; + file_.write(data(), size()); + clear(); + } + template friend ostream output_file(cstring_view path, T... params); @@ -450,7 +457,7 @@ class FMT_API ostream final : private detail::buffer { * ````: Flags passed to `open `_ - (``file::WRONLY | file::CREATE`` by default) + (``file::WRONLY | file::CREATE | file::TRUNC`` by default) * ``buffer_size=``: Output buffer size **Example**:: @@ -465,50 +472,6 @@ inline ostream output_file(cstring_view path, T... 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 diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/ostream.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/ostream.h index d66248a60..c3cdd4a61 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/ostream.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/ostream.h @@ -8,79 +8,33 @@ #ifndef FMT_OSTREAM_H_ #define FMT_OSTREAM_H_ +#include #include +#if defined(_WIN32) && defined(__GLIBCXX__) +# include +# include +#elif defined(_WIN32) && defined(_LIBCPP_VERSION) +# include <__std_stream> +#endif #include "format.h" FMT_BEGIN_NAMESPACE -template class basic_printf_parse_context; template class basic_printf_context; namespace detail { -template class formatbuf : public std::basic_streambuf { - private: - using int_type = typename std::basic_streambuf::int_type; - using traits_type = typename std::basic_streambuf::traits_type; - - buffer& buffer_; - - public: - formatbuf(buffer& 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(ch)); - return ch; - } - - std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { - buffer_.append(s, s + count); - return count; - } -}; - -struct converter { - template ::value)> converter(T); -}; - -template struct test_stream : std::basic_ostream { - private: - void_t<> operator<<(converter); -}; - -// Hide insertion operators for built-in types. -template -void_t<> operator<<(std::basic_ostream&, Char); -template -void_t<> operator<<(std::basic_ostream&, char); -template -void_t<> operator<<(std::basic_ostream&, char); -template -void_t<> operator<<(std::basic_ostream&, signed char); -template -void_t<> operator<<(std::basic_ostream&, unsigned char); - -// Checks if T has a user-defined operator<< (e.g. not a member of -// std::ostream). -template class is_streamable { +// Checks if T has a user-defined operator<<. +template +class is_streamable { private: template - static bool_constant&>() - << std::declval()), - void_t<>>::value> - test(int); + static auto test(int) + -> bool_constant&>() + << std::declval()) != 0>; - template static std::false_type test(...); + template static auto test(...) -> std::false_type; using result = decltype(test(0)); @@ -90,7 +44,68 @@ template class is_streamable { static const bool value = result::value; }; +// Formatting of built-in types and arrays is intentionally disabled because +// it's handled by standard (non-ostream) formatters. +template +struct is_streamable< + T, Char, + enable_if_t< + std::is_arithmetic::value || std::is_array::value || + std::is_pointer::value || std::is_same::value || + std::is_convertible>::value || + std::is_same>::value || + (std::is_convertible::value && !std::is_enum::value)>> + : std::false_type {}; + +// Generate a unique explicit instantion in every translation unit using a tag +// type in an anonymous namespace. +namespace { +struct file_access_tag {}; +} // namespace +template +class file_access { + friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } +}; + +#if FMT_MSC_VERSION +template class file_access; +auto get_file(std::filebuf&) -> FILE*; +#elif defined(_WIN32) && defined(_LIBCPP_VERSION) +template class file_access, + &std::__stdoutbuf::__file_>; +auto get_file(std::__stdoutbuf&) -> FILE*; +#endif + +inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) { +#if FMT_MSC_VERSION + if (auto* buf = dynamic_cast(os.rdbuf())) + if (FILE* f = get_file(*buf)) return write_console(f, data); +#elif defined(_WIN32) && defined(__GLIBCXX__) + auto* rdbuf = os.rdbuf(); + FILE* c_file; + if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) + c_file = fbuf->file(); + else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) + c_file = fbuf->file(); + else + return false; + if (c_file) return write_console(c_file, data); +#elif defined(_WIN32) && defined(_LIBCPP_VERSION) + if (auto* buf = dynamic_cast*>(os.rdbuf())) + if (FILE* f = get_file(*buf)) return write_console(f, data); +#else + ignore_unused(os, data); +#endif + return false; +} +inline bool write_ostream_unicode(std::wostream&, + fmt::basic_string_view) { + return false; +} + // Write the content of buf to os. +// It is a separate function rather than a part of vprint to simplify testing. template void write_buffer(std::basic_ostream& os, buffer& buf) { const Char* buf_data = buf.data(); @@ -108,55 +123,86 @@ void write_buffer(std::basic_ostream& os, buffer& buf) { template void format_value(buffer& buf, const T& value, locale_ref loc = locale_ref()) { - formatbuf format_buf(buf); - std::basic_ostream output(&format_buf); + auto&& format_buf = formatbuf>(buf); + auto&& output = std::basic_ostream(&format_buf); #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) if (loc) output.imbue(loc.get()); #endif output << value; output.exceptions(std::ios_base::failbit | std::ios_base::badbit); - buf.try_resize(buf.size()); } +template struct streamed_view { const T& value; }; + +} // namespace detail + // Formats an object of type T that has an overloaded ostream operator<<. -template -struct fallback_formatter::value>> - : private formatter, Char> { - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) - -> decltype(ctx.begin()) { - return formatter, Char>::parse(ctx); - } - template >::value)> - auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } +template +struct basic_ostream_formatter : formatter, Char> { + void set_debug_format() = delete; - template - auto format(const T& value, basic_format_context& ctx) + template + auto format(const T& value, basic_format_context& ctx) const -> OutputIt { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); format_value(buffer, value, ctx.locale()); - basic_string_view str(buffer.data(), buffer.size()); - return formatter, Char>::format(str, ctx); + return formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); } +}; + +using ostream_formatter = basic_ostream_formatter; + +template +struct formatter, Char> + : basic_ostream_formatter { template - auto format(const T& value, basic_printf_context& ctx) - -> OutputIt { - basic_memory_buffer buffer; - format_value(buffer, value, ctx.locale()); - return std::copy(buffer.begin(), buffer.end(), ctx.out()); + auto format(detail::streamed_view view, + basic_format_context& ctx) const -> OutputIt { + return basic_ostream_formatter::format(view.value, ctx); } }; + +/** + \rst + Returns a view that formats `value` via an ostream ``operator<<``. + + **Example**:: + + fmt::print("Current thread id: {}\n", + fmt::streamed(std::this_thread::get_id())); + \endrst + */ +template +auto streamed(const T& value) -> detail::streamed_view { + return {value}; +} + +namespace detail { + +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct fallback_formatter::value>> + : basic_ostream_formatter { + using basic_ostream_formatter::format; +}; + +inline void vprint_directly(std::ostream& os, string_view format_str, + format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, format_str, args); + detail::write_buffer(os, buffer); +} + } // namespace detail -FMT_MODULE_EXPORT -template -void vprint(std::basic_ostream& os, basic_string_view format_str, +FMT_MODULE_EXPORT template +void vprint(std::basic_ostream& os, + basic_string_view> format_str, basic_format_args>> args) { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); detail::vformat_to(buffer, format_str, args); + if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; detail::write_buffer(os, buffer); } @@ -169,13 +215,23 @@ void vprint(std::basic_ostream& os, basic_string_view format_str, fmt::print(cerr, "Don't {}!", "panic"); \endrst */ +FMT_MODULE_EXPORT template +void print(std::ostream& os, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (detail::is_utf8()) + vprint(os, fmt, vargs); + else + detail::vprint_directly(os, fmt, vargs); +} + FMT_MODULE_EXPORT -template ::value, char_t>> -void print(std::basic_ostream& os, const S& format_str, Args&&... args) { - vprint(os, to_string_view(format_str), - fmt::make_args_checked(format_str, args...)); +template +void print(std::wostream& os, + basic_format_string...> fmt, + Args&&... args) { + vprint(os, fmt, fmt::make_format_args>(args...)); } + FMT_END_NAMESPACE #endif // FMT_OSTREAM_H_ diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/printf.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/printf.h index 3a3cd1528..70a592dc2 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/printf.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/printf.h @@ -10,7 +10,6 @@ #include // std::max #include // std::numeric_limits -#include #include "format.h" @@ -233,7 +232,7 @@ class printf_arg_formatter : public arg_formatter { OutputIt write_null_pointer(bool is_string = false) { auto s = this->specs; - s.type = 0; + s.type = presentation_type::none; return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); } @@ -249,8 +248,10 @@ class printf_arg_formatter : public arg_formatter { // std::is_same instead. if (std::is_same::value) { format_specs fmt_specs = this->specs; - if (fmt_specs.type && fmt_specs.type != 'c') + if (fmt_specs.type != presentation_type::none && + fmt_specs.type != presentation_type::chr) { return (*this)(static_cast(value)); + } fmt_specs.sign = sign::none; fmt_specs.alt = false; fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types. @@ -271,13 +272,13 @@ class printf_arg_formatter : public arg_formatter { /** 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'); + return write_null_pointer(this->specs.type != presentation_type::pointer); } /** 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'); + return write_null_pointer(this->specs.type != presentation_type::pointer); } OutputIt operator()(basic_string_view value) { @@ -490,13 +491,13 @@ void vprintf(buffer& buf, basic_string_view format, // Parse type. if (it == end) FMT_THROW(format_error("invalid format string")); - specs.type = static_cast(*it++); + char type = static_cast(*it++); if (arg.is_integral()) { // Normalize type. - switch (specs.type) { + switch (type) { case 'i': case 'u': - specs.type = 'd'; + type = 'd'; break; case 'c': visit_format_arg( @@ -505,6 +506,9 @@ void vprintf(buffer& buf, basic_string_view format, break; } } + specs.type = parse_presentation_type(type); + if (specs.type == presentation_type::none) + parse_ctx.on_error("invalid type specifier"); start = it; @@ -556,7 +560,7 @@ inline auto vsprintf( basic_format_args>> args) -> std::basic_string { basic_memory_buffer buffer; - vprintf(buffer, to_string_view(fmt), args); + vprintf(buffer, detail::to_string_view(fmt), args); return to_string(buffer); } @@ -573,7 +577,8 @@ template ::value, char_t>> inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { using context = basic_printf_context_t; - return vsprintf(to_string_view(fmt), fmt::make_format_args(args...)); + return vsprintf(detail::to_string_view(fmt), + fmt::make_format_args(args...)); } template > @@ -582,7 +587,7 @@ inline auto vfprintf( basic_format_args>> args) -> int { basic_memory_buffer buffer; - vprintf(buffer, to_string_view(fmt), args); + vprintf(buffer, detail::to_string_view(fmt), args); size_t size = buffer.size(); return std::fwrite(buffer.data(), sizeof(Char), size, f) < size ? -1 @@ -601,7 +606,7 @@ inline auto vfprintf( template > inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { using context = basic_printf_context_t; - return vfprintf(f, to_string_view(fmt), + return vfprintf(f, detail::to_string_view(fmt), fmt::make_format_args(args...)); } @@ -610,7 +615,7 @@ inline auto vprintf( const S& fmt, basic_format_args>> args) -> int { - return vfprintf(stdout, to_string_view(fmt), args); + return vfprintf(stdout, detail::to_string_view(fmt), args); } /** @@ -625,27 +630,10 @@ inline auto vprintf( template ::value)> inline auto printf(const S& fmt, const T&... args) -> int { return vprintf( - to_string_view(fmt), + detail::to_string_view(fmt), fmt::make_format_args>>(args...)); } -template > -FMT_DEPRECATED auto vfprintf( - std::basic_ostream& os, const S& fmt, - basic_format_args>> args) - -> int { - basic_memory_buffer buffer; - vprintf(buffer, to_string_view(fmt), args); - os.write(buffer.data(), static_cast(buffer.size())); - return static_cast(buffer.size()); -} -template > -FMT_DEPRECATED auto fprintf(std::basic_ostream& os, const S& fmt, - const T&... args) -> int { - return vfprintf(os, to_string_view(fmt), - fmt::make_format_args>(args...)); -} - FMT_MODULE_EXPORT_END FMT_END_NAMESPACE diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/ranges.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/ranges.h index f0390df21..dea7d60dd 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/ranges.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/ranges.h @@ -13,37 +13,13 @@ #define FMT_RANGES_H_ #include +#include #include #include "format.h" FMT_BEGIN_NAMESPACE -template struct formatting_range { -#ifdef FMT_DEPRECATED_BRACED_RANGES - Char prefix = '{'; - Char postfix = '}'; -#else - Char prefix = '['; - Char postfix = ']'; -#endif - - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } -}; - -template struct formatting_tuple { - Char prefix = '('; - Char postfix = ')'; - - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } -}; - namespace detail { template @@ -71,7 +47,7 @@ OutputIterator copy(wchar_t ch, OutputIterator out) { return out; } -/// Return true value if T has std::string interface, like std::string_view. +// Returns true if T has a std::string-like interface, like std::string_view. template class is_std_string_like { template static auto check(U* p) @@ -79,18 +55,46 @@ template class is_std_string_like { template static void check(...); public: - static FMT_CONSTEXPR_DECL const bool value = - is_string::value || !std::is_void(nullptr))>::value; + static constexpr const bool value = + is_string::value || + std::is_convertible>::value || + !std::is_void(nullptr))>::value; }; template struct is_std_string_like> : std::true_type {}; +template class is_map { + template static auto check(U*) -> typename U::mapped_type; + template static void check(...); + + public: +#ifdef FMT_FORMAT_MAP_AS_LIST + static constexpr const bool value = false; +#else + static constexpr const bool value = + !std::is_void(nullptr))>::value; +#endif +}; + +template class is_set { + template static auto check(U*) -> typename U::key_type; + template static void check(...); + + public: +#ifdef FMT_FORMAT_SET_AS_LIST + static constexpr const bool value = false; +#else + static constexpr const bool value = + !std::is_void(nullptr))>::value && !is_map::value; +#endif +}; + template struct conditional_helper {}; template struct is_range_ : std::false_type {}; -#if !FMT_MSC_VER || FMT_MSC_VER > 1800 +#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 # define FMT_DECLTYPE_RETURN(val) \ ->decltype(val) { return val; } \ @@ -143,16 +147,16 @@ struct has_mutable_begin_end : std::false_type {}; template struct has_const_begin_end< - T, void_t&>())), - decltype(detail::range_begin( - std::declval&>()))>> + T, + void_t< + decltype(detail::range_begin(std::declval&>())), + decltype(detail::range_end(std::declval&>()))>> : std::true_type {}; template struct has_mutable_begin_end< T, void_t())), - decltype(detail::range_begin(std::declval())), + decltype(detail::range_end(std::declval())), enable_if_t::value>>> : std::true_type {}; @@ -160,46 +164,22 @@ template struct is_range_ : std::integral_constant::value || has_mutable_begin_end::value)> {}; - -template struct range_to_view; -template -struct range_to_view::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 -struct range_to_view::value && - has_mutable_begin_end::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. +// tuple_size and tuple_element check. template class is_tuple_like_ { template static auto check(U* p) -> decltype(std::tuple_size::value, int()); template static void check(...); public: - static FMT_CONSTEXPR_DECL const bool value = + static constexpr const bool value = !std::is_void(nullptr))>::value; }; // Check for integer_sequence -#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 +#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 template using integer_sequence = std::integer_sequence; template using index_sequence = std::index_sequence; @@ -222,8 +202,33 @@ template using make_index_sequence = make_integer_sequence; #endif +template +using tuple_index_sequence = make_index_sequence::value>; + +template ::value> +class is_tuple_formattable_ { + public: + static constexpr const bool value = false; +}; +template class is_tuple_formattable_ { + template + static std::true_type check2(index_sequence, + integer_sequence); + static std::false_type check2(...); + template + static decltype(check2( + index_sequence{}, + integer_sequence< + bool, (is_formattable::type, + C>::value)...>{})) check(index_sequence); + + public: + static constexpr const bool value = + decltype(check(tuple_index_sequence{}))::value; +}; + template -void for_each(index_sequence, Tuple&& tup, F&& f) FMT_NOEXCEPT { +void for_each(index_sequence, Tuple&& tup, F&& f) noexcept { using std::get; // using free function get(T) now. const int _[] = {0, ((void)f(get(tup)), 0)...}; @@ -241,9 +246,36 @@ template void for_each(Tuple&& tup, F&& f) { for_each(indexes, std::forward(tup), std::forward(f)); } +#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 +// Older MSVC doesn't get the reference type correctly for arrays. +template struct range_reference_type_impl { + using type = decltype(*detail::range_begin(std::declval())); +}; + +template struct range_reference_type_impl { + using type = T&; +}; + +template +using range_reference_type = typename range_reference_type_impl::type; +#else template -using value_type = - remove_cvref_t()))>; +using range_reference_type = + decltype(*detail::range_begin(std::declval())); +#endif + +// We don't use the Range's value_type for anything, but we do need the Range's +// reference type, with cv-ref stripped. +template +using uncvref_type = remove_cvref_t>; + +template +using uncvref_first_type = + remove_cvref_t>().first)>; + +template +using uncvref_second_type = remove_cvref_t< + decltype(std::declval>().second)>; template OutputIt write_delimiter(OutputIt out) { *out++ = ','; @@ -251,23 +283,22 @@ template OutputIt write_delimiter(OutputIt out) { return out; } -template < - typename Char, typename OutputIt, typename Arg, - FMT_ENABLE_IF(is_std_string_like::type>::value)> -OutputIt write_range_entry(OutputIt out, const Arg& v) { - *out++ = '"'; - out = write(out, v); - *out++ = '"'; - return out; +template +auto write_range_entry(OutputIt out, basic_string_view str) -> OutputIt { + return write_escaped_string(out, str); +} + +template >::value)> +inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt { + auto sv = std_string_view(str); + return write_range_entry(out, basic_string_view(sv)); } template ::value)> OutputIt write_range_entry(OutputIt out, const Arg v) { - *out++ = '\''; - *out++ = v; - *out++ = '\''; - return out; + return write_escaped_char(out, v); } template < @@ -281,88 +312,287 @@ OutputIt write_range_entry(OutputIt out, const Arg& v) { } // namespace detail template struct is_tuple_like { - static FMT_CONSTEXPR_DECL const bool value = + static constexpr const bool value = detail::is_tuple_like_::value && !detail::is_range_::value; }; +template struct is_tuple_formattable { + static constexpr const bool value = + detail::is_tuple_formattable_::value; +}; + template -struct formatter::value>> { +struct formatter::value && + fmt::is_tuple_formattable::value>> { private: - // C++11 generic lambda for format() + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + + // C++11 generic lambda for format(). template struct format_each { template void operator()(const T& v) { - if (i > 0) out = detail::write_delimiter(out); + if (i > 0) out = detail::copy_str(separator, out); out = detail::write_range_entry(out, v); ++i; } - formatting_tuple& formatting; - size_t& i; - typename std::add_lvalue_reference< - decltype(std::declval().out())>::type out; + int i; + typename FormatContext::iterator& out; + basic_string_view separator; }; public: - formatting_tuple formatting; + FMT_CONSTEXPR formatter() {} + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return formatting.parse(ctx); + return ctx.begin(); } template - auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { + auto format(const TupleT& values, FormatContext& ctx) const + -> decltype(ctx.out()) { auto out = ctx.out(); - size_t i = 0; - - detail::copy(formatting.prefix, out); - detail::for_each(values, format_each{formatting, i, out}); - detail::copy(formatting.postfix, out); - - return ctx.out(); + out = detail::copy_str(opening_bracket_, out); + detail::for_each(values, format_each{0, out, separator_}); + out = detail::copy_str(closing_bracket_, out); + return out; } }; template struct is_range { - static FMT_CONSTEXPR_DECL const bool value = + static constexpr const bool value = detail::is_range_::value && !detail::is_std_string_like::value && !std::is_convertible>::value && - !std::is_constructible, T>::value; + !std::is_convertible>::value; +}; + +namespace detail { +template struct range_mapper { + using mapper = arg_mapper; + + template , Context>::value)> + static auto map(T&& value) -> T&& { + return static_cast(value); + } + template , Context>::value)> + static auto map(T&& value) + -> decltype(mapper().map(static_cast(value))) { + return mapper().map(static_cast(value)); + } }; +template +using range_formatter_type = conditional_t< + is_formattable::value, + formatter>{}.map( + std::declval()))>, + Char>, + fallback_formatter>; + +template +using maybe_const_range = + conditional_t::value, const R, R>; + +// Workaround a bug in MSVC 2015 and earlier. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 +template +struct is_formattable_delayed + : disjunction< + is_formattable>, Char>, + has_fallback_formatter>, Char>> {}; +#endif + +} // namespace detail + +template +struct range_formatter; + template -struct formatter< +struct range_formatter< T, Char, - enable_if_t< - fmt::is_range::value -// Workaround a bug in MSVC 2017 and earlier. -#if !FMT_MSC_VER || FMT_MSC_VER >= 1927 - && (has_formatter, format_context>::value || - detail::has_fallback_formatter, Char>::value) -#endif - >> { - formatting_range formatting; + enable_if_t>, + disjunction, + detail::has_fallback_formatter>>::value>> { + private: + detail::range_formatter_type underlying_; + bool custom_specs_ = false; + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + + template + FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, int) + -> decltype(u.set_debug_format()) { + u.set_debug_format(); + } + + template + FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} + + FMT_CONSTEXPR void maybe_set_debug_format() { + maybe_set_debug_format(underlying_, 0); + } + + public: + FMT_CONSTEXPR range_formatter() {} + + FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type& { + return underlying_; + } + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return formatting.parse(ctx); + auto it = ctx.begin(); + auto end = ctx.end(); + if (it == end || *it == '}') { + maybe_set_debug_format(); + return it; + } + + if (*it == 'n') { + set_brackets({}, {}); + ++it; + } + + if (*it == '}') { + maybe_set_debug_format(); + return it; + } + + if (*it != ':') + FMT_THROW(format_error("no other top-level range formatters supported")); + + custom_specs_ = true; + ++it; + ctx.advance_to(it); + return underlying_.parse(ctx); } - template - 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::view(values); - auto it = view.begin(); - auto end = view.end(); + template + auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { + detail::range_mapper> mapper; + auto out = ctx.out(); + out = detail::copy_str(opening_bracket_, out); + int i = 0; + auto it = detail::range_begin(range); + auto end = detail::range_end(range); for (; it != end; ++it) { - if (i > 0) out = detail::write_delimiter(out); - out = detail::write_range_entry(out, *it); + if (i > 0) out = detail::copy_str(separator_, out); + ; + ctx.advance_to(out); + out = underlying_.format(mapper.map(*it), ctx); ++i; } - return detail::copy(formatting.postfix, out); + out = detail::copy_str(closing_bracket_, out); + return out; } }; +enum class range_format { disabled, map, set, sequence, string, debug_string }; + +namespace detail { +template struct range_format_kind_ { + static constexpr auto value = std::is_same, T>::value + ? range_format::disabled + : is_map::value ? range_format::map + : is_set::value ? range_format::set + : range_format::sequence; +}; + +template +struct range_default_formatter; + +template +using range_format_constant = std::integral_constant; + +template +struct range_default_formatter< + K, R, Char, + enable_if_t<(K == range_format::sequence || K == range_format::map || + K == range_format::set)>> { + using range_type = detail::maybe_const_range; + range_formatter, Char> underlying_; + + FMT_CONSTEXPR range_default_formatter() { init(range_format_constant()); } + + FMT_CONSTEXPR void init(range_format_constant) { + underlying_.set_brackets(detail::string_literal{}, + detail::string_literal{}); + } + + FMT_CONSTEXPR void init(range_format_constant) { + underlying_.set_brackets(detail::string_literal{}, + detail::string_literal{}); + underlying_.underlying().set_brackets({}, {}); + underlying_.underlying().set_separator( + detail::string_literal{}); + } + + FMT_CONSTEXPR void init(range_format_constant) {} + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return underlying_.parse(ctx); + } + + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { + return underlying_.format(range, ctx); + } +}; +} // namespace detail + +template +struct range_format_kind + : conditional_t< + is_range::value, detail::range_format_kind_, + std::integral_constant> {}; + +template +struct formatter< + R, Char, + enable_if_t::value != + range_format::disabled> +// Workaround a bug in MSVC 2015 and earlier. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 + , + detail::is_formattable_delayed +#endif + >::value>> + : detail::range_default_formatter::value, R, + Char> { +}; + template struct tuple_join_view : detail::view { const std::tuple& tuple; basic_string_view sep; @@ -374,46 +604,70 @@ template struct tuple_join_view : detail::view { template using tuple_arg_join = tuple_join_view; +// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers +// support in tuple_join. It is disabled by default because of issues with +// the dynamic width and precision. +#ifndef FMT_TUPLE_JOIN_SPECIFIERS +# define FMT_TUPLE_JOIN_SPECIFIERS 0 +#endif + template struct formatter, Char> { template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); + return do_parse(ctx, std::integral_constant()); } template - auto format(const tuple_join_view& value, FormatContext& ctx) -> - typename FormatContext::iterator { - return format(value, ctx, detail::make_index_sequence{}); + auto format(const tuple_join_view& value, + FormatContext& ctx) const -> typename FormatContext::iterator { + return do_format(value, ctx, + std::integral_constant()); } private: - template - auto format(const tuple_join_view& value, FormatContext& ctx, - detail::index_sequence) -> - typename FormatContext::iterator { - using std::get; - return format_args(value, ctx, get(value.tuple)...); + std::tuple::type, Char>...> formatters_; + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + auto end = ctx.begin(); +#if FMT_TUPLE_JOIN_SPECIFIERS + end = std::get(formatters_).parse(ctx); + if (N > 1) { + auto end1 = do_parse(ctx, std::integral_constant()); + if (end != end1) + FMT_THROW(format_error("incompatible format specs for tuple elements")); + } +#endif + return end; } template - auto format_args(const tuple_join_view&, FormatContext& ctx) -> + auto do_format(const tuple_join_view&, FormatContext& ctx, + std::integral_constant) const -> 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 - auto format_args(const tuple_join_view& value, FormatContext& ctx, - const Arg& arg, const Args&... args) -> + template + auto do_format(const tuple_join_view& value, FormatContext& ctx, + std::integral_constant) const -> typename FormatContext::iterator { - using base = formatter::type, Char>; - auto out = base().format(arg, ctx); - if (sizeof...(Args) > 0) { + auto out = std::get(formatters_) + .format(std::get(value.tuple), ctx); + if (N > 1) { out = std::copy(value.sep.begin(), value.sep.end(), out); ctx.advance_to(out); - return format_args(value, ctx, args...); + return do_format(value, ctx, std::integral_constant()); } return out; } diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/std.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/std.h new file mode 100644 index 000000000..41d2b2838 --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/std.h @@ -0,0 +1,171 @@ +// Formatting library for C++ - formatters for standard library types +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_STD_H_ +#define FMT_STD_H_ + +#include +#include +#include + +#include "ostream.h" + +#if FMT_HAS_INCLUDE() +# include +#endif +// Checking FMT_CPLUSPLUS for warning suppression in MSVC. +#if FMT_CPLUSPLUS >= 201703L +# if FMT_HAS_INCLUDE() +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +#endif + +#ifdef __cpp_lib_filesystem +FMT_BEGIN_NAMESPACE + +namespace detail { + +template +void write_escaped_path(basic_memory_buffer& quoted, + const std::filesystem::path& p) { + write_escaped_string(std::back_inserter(quoted), p.string()); +} +# ifdef _WIN32 +template <> +inline void write_escaped_path(basic_memory_buffer& quoted, + const std::filesystem::path& p) { + auto s = p.u8string(); + write_escaped_string( + std::back_inserter(quoted), + string_view(reinterpret_cast(s.c_str()), s.size())); +} +# endif +template <> +inline void write_escaped_path( + basic_memory_buffer& quoted, + const std::filesystem::path& p) { + write_escaped_string( + std::back_inserter(quoted), p.native()); +} + +} // namespace detail + +template +struct formatter + : formatter> { + template + auto format(const std::filesystem::path& p, FormatContext& ctx) const -> + typename FormatContext::iterator { + basic_memory_buffer quoted; + detail::write_escaped_path(quoted, p); + return formatter>::format( + basic_string_view(quoted.data(), quoted.size()), ctx); + } +}; +FMT_END_NAMESPACE +#endif + +FMT_BEGIN_NAMESPACE +template +struct formatter : basic_ostream_formatter {}; +FMT_END_NAMESPACE + +#ifdef __cpp_lib_variant +FMT_BEGIN_NAMESPACE +template struct formatter { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const std::monostate&, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = detail::write(out, "monostate"); + return out; + } +}; + +namespace detail { + +template +using variant_index_sequence = + std::make_index_sequence::value>; + +// variant_size and variant_alternative check. +template +struct is_variant_like_ : std::false_type {}; +template +struct is_variant_like_::value)>> + : std::true_type {}; + +// formattable element check +template class is_variant_formattable_ { + template + static std::conjunction< + is_formattable, C>...> + check(std::index_sequence); + + public: + static constexpr const bool value = + decltype(check(variant_index_sequence{}))::value; +}; + +template +auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { + if constexpr (is_string::value) + return write_escaped_string(out, detail::to_string_view(v)); + else if constexpr (std::is_same_v) + return write_escaped_char(out, v); + else + return write(out, v); +} + +} // namespace detail + +template struct is_variant_like { + static constexpr const bool value = detail::is_variant_like_::value; +}; + +template struct is_variant_formattable { + static constexpr const bool value = + detail::is_variant_formattable_::value; +}; + +template +struct formatter< + Variant, Char, + std::enable_if_t, is_variant_formattable>>> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const Variant& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + out = detail::write(out, "variant("); + std::visit( + [&](const auto& v) { + out = detail::write_variant_alternative(out, v); + }, + value); + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif + +#endif // FMT_STD_H_ diff --git a/Lumos/External/spdlog/include/spdlog/fmt/bundled/xchar.h b/Lumos/External/spdlog/include/spdlog/fmt/bundled/xchar.h index a0dd032f1..3b5bc15ca 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/bundled/xchar.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/bundled/xchar.h @@ -5,11 +5,10 @@ // // For the license information refer to format.h. -#ifndef FMT_WCHAR_H_ -#define FMT_WCHAR_H_ +#ifndef FMT_XCHAR_H_ +#define FMT_XCHAR_H_ #include -#include #include "format.h" @@ -30,9 +29,11 @@ using wmemory_buffer = basic_memory_buffer; #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 // Workaround broken conversion on older gcc. template using wformat_string = wstring_view; +inline auto runtime(wstring_view s) -> wstring_view { return s; } #else template using wformat_string = basic_format_string...>; +inline auto runtime(wstring_view s) -> basic_runtime { return {{s}}; } #endif template <> struct is_char : std::true_type {}; @@ -47,12 +48,7 @@ constexpr format_arg_store make_wformat_args( } inline namespace literals { -constexpr auto operator"" _format(const wchar_t* s, size_t n) - -> detail::udl_formatter { - return {{s, n}}; -} - -#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS constexpr detail::udl_arg operator"" _a(const wchar_t* s, size_t) { return {s}; } @@ -87,13 +83,19 @@ auto vformat(basic_string_view format_str, return to_string(buffer); } +template +auto format(wformat_string fmt, T&&... args) -> std::wstring { + return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); +} + // Pass char_t as a default template parameter instead of using // std::basic_string> to reduce the symbol size. template , - FMT_ENABLE_IF(!std::is_same::value)> + FMT_ENABLE_IF(!std::is_same::value && + !std::is_same::value)> auto format(const S& format_str, Args&&... args) -> std::basic_string { - const auto& vargs = fmt::make_args_checked(format_str, args...); - return vformat(to_string_view(format_str), vargs); + return vformat(detail::to_string_view(format_str), + fmt::make_format_args>(args...)); } template , @@ -103,7 +105,7 @@ inline auto vformat( const Locale& loc, const S& format_str, basic_format_args>> args) -> std::basic_string { - return detail::vformat(loc, to_string_view(format_str), args); + return detail::vformat(loc, detail::to_string_view(format_str), args); } template ::value)> inline auto format(const Locale& loc, const S& format_str, Args&&... args) -> std::basic_string { - return detail::vformat(loc, to_string_view(format_str), - fmt::make_args_checked(format_str, args...)); + return detail::vformat(loc, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); } template , @@ -123,7 +125,7 @@ auto vformat_to(OutputIt out, const S& format_str, basic_format_args>> args) -> OutputIt { auto&& buf = detail::get_buffer(out); - detail::vformat_to(buf, to_string_view(format_str), args); + detail::vformat_to(buf, detail::to_string_view(format_str), args); return detail::get_iterator(buf); } @@ -132,18 +134,8 @@ template ::value&& detail::is_exotic_char::value)> inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt { - const auto& vargs = fmt::make_args_checked(fmt, args...); - return vformat_to(out, to_string_view(fmt), vargs); -} - -template ::value)> -FMT_DEPRECATED auto format_to(basic_memory_buffer& buf, - const S& format_str, Args&&... args) -> - typename buffer_context::iterator { - const auto& vargs = fmt::make_args_checked(format_str, args...); - detail::vformat_to(buf, to_string_view(format_str), vargs, {}); - return detail::buffer_appender(buf); + return vformat_to(out, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); } template >> args) -> OutputIt { auto&& buf = detail::get_buffer(out); - vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc)); + vformat_to(buf, detail::to_string_view(format_str), args, + detail::locale_ref(loc)); return detail::get_iterator(buf); } @@ -167,8 +160,8 @@ template < inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, Args&&... args) -> typename std::enable_if::type { - const auto& vargs = fmt::make_args_checked(format_str, args...); - return vformat_to(out, loc, to_string_view(format_str), vargs); + return vformat_to(out, loc, to_string_view(format_str), + fmt::make_format_args>(args...)); } template ::value)> inline auto format_to_n(OutputIt out, size_t n, const S& fmt, const Args&... args) -> format_to_n_result { - const auto& vargs = fmt::make_args_checked(fmt, args...); - return vformat_to_n(out, n, to_string_view(fmt), vargs); + return vformat_to_n(out, n, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); } template , FMT_ENABLE_IF(detail::is_exotic_char::value)> inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { detail::counting_buffer buf; - const auto& vargs = fmt::make_args_checked(fmt, args...); - detail::vformat_to(buf, to_string_view(fmt), vargs); + detail::vformat_to(buf, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); return buf.count(); } @@ -217,11 +210,11 @@ inline void vprint(wstring_view fmt, wformat_args args) { template void print(std::FILE* f, wformat_string fmt, T&&... args) { - return vprint(f, wstring_view(fmt), make_wformat_args(args...)); + return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); } template void print(wformat_string fmt, T&&... args) { - return vprint(wstring_view(fmt), make_wformat_args(args...)); + return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); } /** @@ -233,4 +226,4 @@ template inline auto to_wstring(const T& value) -> std::wstring { FMT_MODULE_EXPORT_END FMT_END_NAMESPACE -#endif // FMT_WCHAR_H_ +#endif // FMT_XCHAR_H_ diff --git a/Lumos/External/spdlog/include/spdlog/fmt/chrono.h b/Lumos/External/spdlog/include/spdlog/fmt/chrono.h index a0544bcaa..83fad2ff9 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/chrono.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/chrono.h @@ -8,13 +8,15 @@ // 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 +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include +# else +# include # endif -# include -#else -# include #endif diff --git a/Lumos/External/spdlog/include/spdlog/fmt/compile.h b/Lumos/External/spdlog/include/spdlog/fmt/compile.h index 6f3459350..906e9f57a 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/compile.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/compile.h @@ -5,16 +5,18 @@ #pragma once // -// include bundled or external copy of fmtlib's ostream support +// include bundled or external copy of fmtlib's compile-time support // -#if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include +# else +# include # endif -# include -#else -# include #endif diff --git a/Lumos/External/spdlog/include/spdlog/fmt/fmt.h b/Lumos/External/spdlog/include/spdlog/fmt/fmt.h index 7aaeed814..90fcae0f0 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/fmt.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/fmt.h @@ -10,7 +10,9 @@ // By default spdlog include its own copy. // -#if !defined(SPDLOG_FMT_EXTERNAL) +#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format +# include +#elif !defined(SPDLOG_FMT_EXTERNAL) # if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) # define FMT_HEADER_ONLY # endif @@ -19,8 +21,12 @@ # endif // enable the 'n' flag in for backward compatibility with fmt 6.x # define FMT_DEPRECATED_N_SPECIFIER +// enable ostream formatting for backward compatibility with fmt 8.x +# define FMT_DEPRECATED_OSTREAM + # include # include + #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib # include # include diff --git a/Lumos/External/spdlog/include/spdlog/fmt/ostr.h b/Lumos/External/spdlog/include/spdlog/fmt/ostr.h index 9d8efe38c..758803417 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/ostr.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/ostr.h @@ -8,13 +8,15 @@ // 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 +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include +# else +# include # endif -# include -#else -# include #endif diff --git a/Lumos/External/spdlog/include/spdlog/fmt/ranges.h b/Lumos/External/spdlog/include/spdlog/fmt/ranges.h new file mode 100644 index 000000000..9103a5f6a --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/fmt/ranges.h @@ -0,0 +1,22 @@ +// +// 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 ranges support +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/Lumos/External/spdlog/include/spdlog/fmt/std.h b/Lumos/External/spdlog/include/spdlog/fmt/std.h new file mode 100644 index 000000000..0490cab0b --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/fmt/std.h @@ -0,0 +1,23 @@ +// +// 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 std support (for formatting e.g. std::filesystem::path, std::thread::id, std::monostate, +// std::variant, ...) +// + +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif +# endif +# include +# else +# include +# endif +#endif diff --git a/Lumos/External/spdlog/include/spdlog/fmt/xchar.h b/Lumos/External/spdlog/include/spdlog/fmt/xchar.h index 616d8f5ba..9a766e5a0 100644 --- a/Lumos/External/spdlog/include/spdlog/fmt/xchar.h +++ b/Lumos/External/spdlog/include/spdlog/fmt/xchar.h @@ -5,16 +5,18 @@ #pragma once // -// include bundled or external copy of fmtlib's ostream support +// include bundled or external copy of fmtlib's xchar support // -#if !defined(SPDLOG_FMT_EXTERNAL) -# ifdef SPDLOG_HEADER_ONLY -# ifndef FMT_HEADER_ONLY -# define FMT_HEADER_ONLY +#if !defined(SPDLOG_USE_STD_FORMAT) +# if !defined(SPDLOG_FMT_EXTERNAL) +# ifdef SPDLOG_HEADER_ONLY +# ifndef FMT_HEADER_ONLY +# define FMT_HEADER_ONLY +# endif # endif +# include +# else +# include # endif -# include -#else -# include #endif diff --git a/Lumos/External/spdlog/include/spdlog/fwd.h b/Lumos/External/spdlog/include/spdlog/fwd.h index cc05ddd41..d25882572 100644 --- a/Lumos/External/spdlog/include/spdlog/fwd.h +++ b/Lumos/External/spdlog/include/spdlog/fwd.h @@ -11,4 +11,8 @@ namespace sinks { class sink; } +namespace level { +enum level_enum : int; +} + } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/logger-inl.h b/Lumos/External/spdlog/include/spdlog/logger-inl.h index fd841657d..227cec439 100644 --- a/Lumos/External/spdlog/include/spdlog/logger-inl.h +++ b/Lumos/External/spdlog/include/spdlog/logger-inl.h @@ -185,7 +185,7 @@ SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg) { sink->log(msg); } - SPDLOG_LOGGER_CATCH() + SPDLOG_LOGGER_CATCH(msg.source) } } @@ -203,14 +203,14 @@ SPDLOG_INLINE void logger::flush_() { sink->flush(); } - SPDLOG_LOGGER_CATCH() + SPDLOG_LOGGER_CATCH(source_loc()) } } SPDLOG_INLINE void logger::dump_backtrace_() { using details::log_msg; - if (tracer_.enabled()) + if (tracer_.enabled() && !tracer_.empty()) { sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); @@ -248,9 +248,9 @@ SPDLOG_INLINE void logger::err_handler_(const std::string &msg) 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()); + 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()); + std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, name().c_str(), msg.c_str()); #endif } } diff --git a/Lumos/External/spdlog/include/spdlog/logger.h b/Lumos/External/spdlog/include/spdlog/logger.h index a69148b4d..1810cb2ac 100644 --- a/Lumos/External/spdlog/include/spdlog/logger.h +++ b/Lumos/External/spdlog/include/spdlog/logger.h @@ -28,10 +28,17 @@ #include #ifndef SPDLOG_NO_EXCEPTIONS -# define SPDLOG_LOGGER_CATCH() \ +# define SPDLOG_LOGGER_CATCH(location) \ catch (const std::exception &ex) \ { \ - err_handler_(ex.what()); \ + if (location.filename) \ + { \ + err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), location.filename, location.line)); \ + } \ + else \ + { \ + err_handler_(ex.what()); \ + } \ } \ catch (...) \ { \ @@ -39,7 +46,7 @@ throw; \ } #else -# define SPDLOG_LOGGER_CATCH() +# define SPDLOG_LOGGER_CATCH(location) #endif namespace spdlog { @@ -77,14 +84,14 @@ class SPDLOG_API logger logger &operator=(logger other) SPDLOG_NOEXCEPT; void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; - template - void log(source_loc loc, level::level_enum lvl, const FormatString &fmt, Args &&...args) + template + void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) { - log_(loc, lvl, fmt, std::forward(args)...); + log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); } - template - void log(level::level_enum lvl, const FormatString &fmt, Args &&...args) + template + void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { log(source_loc{}, lvl, fmt, std::forward(args)...); } @@ -95,11 +102,11 @@ class SPDLOG_API logger log(source_loc{}, lvl, msg); } - // T can be statically converted to string_view - template::value, int>::type = 0> + // T cannot be statically converted to format string (including string_view/wstring_view) + template::value, int>::type = 0> void log(source_loc loc, level::level_enum lvl, const T &msg) { - log(loc, lvl, string_view_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) @@ -133,50 +140,126 @@ class SPDLOG_API logger log(source_loc{}, lvl, msg); } - // T cannot be statically converted to string_view or wstring_view - template::value && - !is_convertible_to_wstring_view::value, - int>::type = 0> - void log(source_loc loc, level::level_enum lvl, const T &msg) + template + void trace(format_string_t fmt, Args &&...args) { - log(loc, lvl, "{}", msg); + log(level::trace, fmt, std::forward(args)...); } - template - void trace(const FormatString &fmt, Args &&...args) + template + void debug(format_string_t fmt, Args &&...args) + { + log(level::debug, fmt, std::forward(args)...); + } + + template + void info(format_string_t fmt, Args &&...args) + { + log(level::info, fmt, std::forward(args)...); + } + + template + void warn(format_string_t fmt, Args &&...args) + { + log(level::warn, fmt, std::forward(args)...); + } + + template + void error(format_string_t fmt, Args &&...args) + { + log(level::err, fmt, std::forward(args)...); + } + + template + void critical(format_string_t fmt, Args &&...args) + { + log(level::critical, fmt, std::forward(args)...); + } + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + template + void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) + { + log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); + } + + template + void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) + { + log(source_loc{}, lvl, fmt, std::forward(args)...); + } + + void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) + { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) + { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.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); + } + + void log(level::level_enum lvl, wstring_view_t msg) + { + log(source_loc{}, lvl, msg); + } + + template + void trace(wformat_string_t fmt, Args &&...args) { log(level::trace, fmt, std::forward(args)...); } - template - void debug(const FormatString &fmt, Args &&...args) + template + void debug(wformat_string_t fmt, Args &&...args) { log(level::debug, fmt, std::forward(args)...); } - template - void info(const FormatString &fmt, Args &&...args) + template + void info(wformat_string_t fmt, Args &&...args) { log(level::info, fmt, std::forward(args)...); } - template - void warn(const FormatString &fmt, Args &&...args) + template + void warn(wformat_string_t fmt, Args &&...args) { log(level::warn, fmt, std::forward(args)...); } - template - void error(const FormatString &fmt, Args &&...args) + template + void error(wformat_string_t fmt, Args &&...args) { log(level::err, fmt, std::forward(args)...); } - template - void critical(const FormatString &fmt, Args &&...args) + template + void critical(wformat_string_t fmt, Args &&...args) { log(level::critical, fmt, std::forward(args)...); } +#endif template void trace(const T &msg) @@ -236,6 +319,10 @@ class SPDLOG_API logger // each sink will get a separate instance of the formatter object. void set_formatter(std::unique_ptr f); + // set formatting for the sinks in this logger. + // equivalent to + // set_formatter(make_unique(pattern, time_type)) + // Note: each sink will get a new instance of a formatter object, replacing the old one. void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); // backtrace support. @@ -269,9 +356,8 @@ class SPDLOG_API logger details::backtracer tracer_; // common implementation for after templated public api has been resolved - template, - typename std::enable_if::value, Char>::type * = nullptr> - void log_(source_loc loc, level::level_enum lvl, const FormatString &fmt, Args &&...args) + template + 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(); @@ -282,16 +368,21 @@ class SPDLOG_API logger SPDLOG_TRY { memory_buf_t buf; - fmt::detail::vformat_to(buf, fmt::to_string_view(fmt), fmt::make_format_args(args...)); +#ifdef SPDLOG_USE_STD_FORMAT + fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...)); +#else + fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...)); +#endif + 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() + SPDLOG_LOGGER_CATCH(loc) } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT template - void log_(source_loc loc, level::level_enum lvl, const wstring_view_t &fmt, Args &&...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(); @@ -302,36 +393,16 @@ class SPDLOG_API logger SPDLOG_TRY { // format to wmemory_buffer and convert to utf8 - fmt::wmemory_buffer wbuf; - fmt::format_to(std::back_inserter(wbuf), fmt, std::forward(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() - } + wmemory_buf_t wbuf; + fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, fmt_lib::make_format_args(args...)); - // T can be statically converted to wstring_view, and no formatting needed. - template::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::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() + SPDLOG_LOGGER_CATCH(loc) } - #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT // log the given message (if the given log level is high enough), diff --git a/Lumos/External/spdlog/include/spdlog/pattern_formatter-inl.h b/Lumos/External/spdlog/include/spdlog/pattern_formatter-inl.h index ec727032b..01afbe6f0 100644 --- a/Lumos/External/spdlog/include/spdlog/pattern_formatter-inl.h +++ b/Lumos/External/spdlog/include/spdlog/pattern_formatter-inl.h @@ -766,6 +766,7 @@ class source_location_formatter final : public flag_formatter { if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); return; } @@ -800,6 +801,7 @@ class source_filename_formatter final : public flag_formatter { if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); return; } size_t text_size = padinfo_.enabled() ? std::char_traits::length(msg.source.filename) : 0; @@ -846,6 +848,7 @@ class short_filename_formatter final : public flag_formatter { if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); return; } auto filename = basename(msg.source.filename); @@ -867,6 +870,7 @@ class source_linenum_formatter final : public flag_formatter { if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); return; } @@ -889,6 +893,7 @@ class source_funcname_formatter final : public flag_formatter { if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); return; } size_t text_size = padinfo_.enabled() ? std::char_traits::length(msg.source.funcname) : 0; @@ -1019,6 +1024,7 @@ SPDLOG_INLINE pattern_formatter::pattern_formatter( : pattern_(std::move(pattern)) , eol_(std::move(eol)) , pattern_time_type_(time_type) + , need_localtime_(false) , last_log_secs_(0) , custom_handlers_(std::move(custom_user_flags)) { @@ -1031,6 +1037,7 @@ SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, : pattern_("%+") , eol_(std::move(eol)) , pattern_time_type_(time_type) + , need_localtime_(true) , last_log_secs_(0) { std::memset(&cached_tm_, 0, sizeof(cached_tm_)); @@ -1044,16 +1051,25 @@ SPDLOG_INLINE std::unique_ptr pattern_formatter::clone() const { cloned_custom_formatters[it.first] = it.second->clone(); } - return details::make_unique(pattern_, pattern_time_type_, eol_, std::move(cloned_custom_formatters)); + auto cloned = details::make_unique(pattern_, pattern_time_type_, eol_, std::move(cloned_custom_formatters)); + cloned->need_localtime(need_localtime_); +#if defined(__GNUC__) && __GNUC__ < 5 + return std::move(cloned); +#else + return cloned; +#endif } SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) { - auto secs = std::chrono::duration_cast(msg.time.time_since_epoch()); - if (secs != last_log_secs_) + if (need_localtime_) { - cached_tm_ = get_time_(msg); - last_log_secs_ = secs; + const auto secs = std::chrono::duration_cast(msg.time.time_since_epoch()); + if (secs != last_log_secs_) + { + cached_tm_ = get_time_(msg); + last_log_secs_ = secs; + } } for (auto &f : formatters_) @@ -1067,9 +1083,15 @@ SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory SPDLOG_INLINE void pattern_formatter::set_pattern(std::string pattern) { pattern_ = std::move(pattern); + need_localtime_ = false; compile_pattern_(pattern_); } +SPDLOG_INLINE void pattern_formatter::need_localtime(bool need) +{ + need_localtime_ = need; +} + SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) { if (pattern_time_type_ == pattern_time_type::local) @@ -1097,6 +1119,7 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i { case ('+'): // default formatter formatters_.push_back(details::make_unique(padding)); + need_localtime_ = true; break; case 'n': // logger name @@ -1121,60 +1144,74 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i case ('a'): // weekday formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('A'): // short weekday formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('b'): case ('h'): // month formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('B'): // short month formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('c'): // datetime formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('C'): // year 2 digits formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('Y'): // year 4 digits formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('D'): case ('x'): // datetime MM/DD/YY formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('m'): // month 1-12 formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('d'): // day of month 1-31 formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('H'): // hours 24 formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('I'): // hours 12 formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('M'): // minutes formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('S'): // seconds formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('e'): // milliseconds @@ -1195,23 +1232,28 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i case ('p'): // am/pm formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('r'): // 12 hour clock 02:55:02 pm formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('R'): // 24-hour HH:MM time formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('T'): case ('X'): // ISO 8601 time format (HH:MM:SS) formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('z'): // timezone formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; break; case ('P'): // pid @@ -1342,7 +1384,6 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri { truncate = false; } - return details::padding_info{std::min(width, max_width), side, truncate}; } diff --git a/Lumos/External/spdlog/include/spdlog/pattern_formatter.h b/Lumos/External/spdlog/include/spdlog/pattern_formatter.h index e9ccfaa75..4c87b21ef 100644 --- a/Lumos/External/spdlog/include/spdlog/pattern_formatter.h +++ b/Lumos/External/spdlog/include/spdlog/pattern_formatter.h @@ -68,7 +68,7 @@ class SPDLOG_API custom_flag_formatter : public details::flag_formatter public: virtual std::unique_ptr clone() const = 0; - void set_padding_info(details::padding_info padding) + void set_padding_info(const details::padding_info &padding) { flag_formatter::padinfo_ = padding; } @@ -98,11 +98,13 @@ class SPDLOG_API pattern_formatter final : public formatter return *this; } void set_pattern(std::string pattern); + void need_localtime(bool need = true); private: std::string pattern_; std::string eol_; pattern_time_type pattern_time_type_; + bool need_localtime_; std::tm cached_tm_; std::chrono::seconds last_log_secs_; std::vector> formatters_; diff --git a/Lumos/External/spdlog/include/spdlog/sinks/android_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/android_sink.h index 42935a7cb..0087e9533 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/android_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/android_sink.h @@ -16,6 +16,7 @@ # include # include # include +# include # if !defined(SPDLOG_ANDROID_RETRIES) # define SPDLOG_ANDROID_RETRIES 2 @@ -25,9 +26,10 @@ namespace spdlog { namespace sinks { /* - * Android sink (logging using __android_log_write) + * Android sink + * (logging using __android_log_write or __android_log_buf_write depending on the specified BufferID) */ -template +template class android_sink final : public base_sink { public: @@ -53,24 +55,43 @@ class android_sink final : public base_sink 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 ret = android_log(priority, tag_.c_str(), msg_output); + if (ret == -EPERM) + { + return; // !__android_log_is_loggable + } 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); + ret = android_log(priority, tag_.c_str(), msg_output); retry_count++; } if (ret < 0) { - throw_spdlog_ex("__android_log_write() failed", ret); + throw_spdlog_ex("logging to Android failed", ret); } } void flush_() override {} private: + // There might be liblog versions used, that do not support __android_log_buf_write. So we only compile and link against + // __android_log_buf_write, if user explicitly provides a non-default log buffer. Otherwise, when using the default log buffer, always + // log via __android_log_write. + template + typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) + { + return __android_log_write(prio, tag, text); + } + + template + typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log(int prio, const char *tag, const char *text) + { + return __android_log_buf_write(ID, prio, tag, text); + } + static android_LogPriority convert_to_android_(spdlog::level::level_enum level) { switch (level) @@ -98,6 +119,12 @@ class android_sink final : public base_sink using android_sink_mt = android_sink; using android_sink_st = android_sink; + +template +using android_sink_buf_mt = android_sink; +template +using android_sink_buf_st = android_sink; + } // namespace sinks // Create and register android syslog logger @@ -116,4 +143,4 @@ inline std::shared_ptr android_logger_st(const std::string &logger_name, } // namespace spdlog -#endif // __ANDROID__ \ No newline at end of file +#endif // __ANDROID__ diff --git a/Lumos/External/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h b/Lumos/External/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h index d8db423ce..c924fc5bd 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h @@ -21,20 +21,20 @@ SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, co { 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); + colors_.at(level::trace) = to_string_(white); + colors_.at(level::debug) = to_string_(cyan); + colors_.at(level::info) = to_string_(green); + colors_.at(level::warn) = to_string_(yellow_bold); + colors_.at(level::err) = to_string_(red_bold); + colors_.at(level::critical) = to_string_(bold_on_red); + colors_.at(level::off) = to_string_(reset); } template SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, string_view_t color) { std::lock_guard lock(mutex_); - colors_[color_level] = to_string_(color); + colors_.at(static_cast(color_level)) = to_string_(color); } template @@ -52,7 +52,7 @@ SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg // before color range print_range_(formatted, 0, msg.color_range_start); // in color range - print_ccode_(colors_[msg.level]); + print_ccode_(colors_.at(static_cast(msg.level))); print_range_(formatted, msg.color_range_start, msg.color_range_end); print_ccode_(reset); // after color range diff --git a/Lumos/External/spdlog/include/spdlog/sinks/base_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/base_sink.h index a0624e941..2e795f592 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/base_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/base_sink.h @@ -16,7 +16,7 @@ namespace spdlog { namespace sinks { template -class base_sink : public sink +class SPDLOG_API base_sink : public sink { public: base_sink(); @@ -37,7 +37,7 @@ class base_sink : public sink protected: // sink formatter std::unique_ptr formatter_; - mutable Mutex mutex_; + Mutex mutex_; virtual void sink_it_(const details::log_msg &msg) = 0; virtual void flush_() = 0; diff --git a/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink-inl.h b/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink-inl.h index e903dd939..8d23f96df 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink-inl.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink-inl.h @@ -14,7 +14,8 @@ namespace spdlog { namespace sinks { template -SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate) +SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers &event_handlers) + : file_helper_{event_handlers} { file_helper_.open(filename, truncate); } diff --git a/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink.h index 047bc8ce5..aacc993bf 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/basic_file_sink.h @@ -20,7 +20,7 @@ template class basic_file_sink final : public base_sink { public: - explicit basic_file_sink(const filename_t &filename, bool truncate = false); + explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}); const filename_t &filename() const; protected: @@ -40,15 +40,17 @@ using basic_file_sink_st = basic_file_sink; // factory functions // template -inline std::shared_ptr basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false) +inline std::shared_ptr basic_logger_mt( + const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate); + return Factory::template create(logger_name, filename, truncate, event_handlers); } template -inline std::shared_ptr basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false) +inline std::shared_ptr basic_logger_st( + const std::string &logger_name, const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate); + return Factory::template create(logger_name, filename, truncate, event_handlers); } } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/callback_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/callback_sink.h new file mode 100644 index 000000000..bcd31383b --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/sinks/callback_sink.h @@ -0,0 +1,61 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include + +namespace spdlog { + +// callbacks type +typedef std::function custom_log_callback; + +namespace sinks { +/* + * Trivial callback sink, gets a callback function and calls it on each log + */ +template +class callback_sink final : public base_sink +{ +public: + explicit callback_sink(const custom_log_callback &callback) + : callback_{callback} + {} + +protected: + void sink_it_(const details::log_msg &msg) override + { + callback_(msg); + } + void flush_() override{}; + +private: + custom_log_callback callback_; +}; + +using callback_sink_mt = callback_sink; +using callback_sink_st = callback_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback) +{ + return Factory::template create(logger_name, callback); +} + +template +inline std::shared_ptr callback_logger_st(const std::string &logger_name, const custom_log_callback &callback) +{ + return Factory::template create(logger_name, callback); +} + +} // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/daily_file_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/daily_file_sink.h index d6a09f6bd..0770380c0 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/daily_file_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/daily_file_sink.h @@ -13,9 +13,10 @@ #include #include +#include +#include #include #include -#include #include #include @@ -32,8 +33,8 @@ struct daily_filename_calculator { 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); + return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), basename, now_tm.tm_year + 1900, + now_tm.tm_mon + 1, now_tm.tm_mday, ext); } }; @@ -46,15 +47,15 @@ struct daily_filename_calculator */ struct daily_filename_format_calculator { - static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + static filename_t calc_filename(const filename_t &file_path, 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); +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + std::wstringstream stream; #else - return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm); + std::stringstream stream; #endif + stream << std::put_time(&now_tm, file_path.c_str()); + return stream.str(); } }; @@ -68,10 +69,12 @@ class daily_file_sink final : public base_sink { 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) + daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) : base_filename_(std::move(base_filename)) , rotation_h_(rotation_hour) , rotation_m_(rotation_minute) + , file_helper_{event_handlers} , truncate_(truncate) , max_files_(max_files) , filenames_q_() @@ -213,30 +216,32 @@ using daily_file_format_sink_st = daily_file_sink -inline std::shared_ptr 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) +inline std::shared_ptr 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, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, hour, minute, truncate, max_files); + return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); } template -inline std::shared_ptr 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) +inline std::shared_ptr 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, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, hour, minute, truncate, max_files); + return Factory::template create( + logger_name, filename, hour, minute, truncate, max_files, event_handlers); } template -inline std::shared_ptr 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) +inline std::shared_ptr 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, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, hour, minute, truncate, max_files); + return Factory::template create(logger_name, filename, hour, minute, truncate, max_files, event_handlers); } template -inline std::shared_ptr 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) +inline std::shared_ptr 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, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, hour, minute, truncate, max_files); + return Factory::template create( + logger_name, filename, hour, minute, truncate, max_files, event_handlers); } } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/dist_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/dist_sink.h index 8fccb4ee5..7ec3a2ecf 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/dist_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/dist_sink.h @@ -31,16 +31,16 @@ class dist_sink : public base_sink dist_sink(const dist_sink &) = delete; dist_sink &operator=(const dist_sink &) = delete; - void add_sink(std::shared_ptr sink) + void add_sink(std::shared_ptr sub_sink) { std::lock_guard lock(base_sink::mutex_); - sinks_.push_back(sink); + sinks_.push_back(sub_sink); } - void remove_sink(std::shared_ptr sink) + void remove_sink(std::shared_ptr sub_sink) { std::lock_guard lock(base_sink::mutex_); - sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); + sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end()); } void set_sinks(std::vector> sinks) @@ -57,20 +57,20 @@ class dist_sink : public base_sink protected: void sink_it_(const details::log_msg &msg) override { - for (auto &sink : sinks_) + for (auto &sub_sink : sinks_) { - if (sink->should_log(msg.level)) + if (sub_sink->should_log(msg.level)) { - sink->log(msg); + sub_sink->log(msg); } } } void flush_() override { - for (auto &sink : sinks_) + for (auto &sub_sink : sinks_) { - sink->flush(); + sub_sink->flush(); } } @@ -82,9 +82,9 @@ class dist_sink : public base_sink void set_formatter_(std::unique_ptr sink_formatter) override { base_sink::formatter_ = std::move(sink_formatter); - for (auto &sink : sinks_) + for (auto &sub_sink : sinks_) { - sink->set_formatter(base_sink::formatter_->clone()); + sub_sink->set_formatter(base_sink::formatter_->clone()); } } std::vector> sinks_; diff --git a/Lumos/External/spdlog/include/spdlog/sinks/dup_filter_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/dup_filter_sink.h index 282163ae4..3c96549c5 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/dup_filter_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/dup_filter_sink.h @@ -20,7 +20,7 @@ // #include // // int main() { -// auto dup_filter = std::make_shared(std::chrono::seconds(5)); +// auto dup_filter = std::make_shared(std::chrono::seconds(5), level::info); // dup_filter->add_sink(std::make_shared()); // spdlog::logger l("logger", dup_filter); // l.info("Hello"); @@ -41,8 +41,9 @@ class dup_filter_sink : public dist_sink { public: template - explicit dup_filter_sink(std::chrono::duration max_skip_duration) + explicit dup_filter_sink(std::chrono::duration max_skip_duration, level::level_enum notification_level = level::info) : max_skip_duration_{max_skip_duration} + , log_level_{notification_level} {} protected: @@ -50,6 +51,7 @@ class dup_filter_sink : public dist_sink log_clock::time_point last_msg_time_; std::string last_msg_payload_; size_t skip_counter_ = 0; + level::level_enum log_level_; void sink_it_(const details::log_msg &msg) override { @@ -67,7 +69,7 @@ class dup_filter_sink : public dist_sink auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast(skip_counter_)); if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) { - details::log_msg skipped_msg{msg.logger_name, level::info, string_view_t{buf, static_cast(msg_size)}}; + details::log_msg skipped_msg{msg.source, msg.logger_name, log_level_, string_view_t{buf, static_cast(msg_size)}}; dist_sink::sink_it_(skipped_msg); } } diff --git a/Lumos/External/spdlog/include/spdlog/sinks/hourly_file_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/hourly_file_sink.h index e75ab4db0..33dd89483 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/hourly_file_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/hourly_file_sink.h @@ -31,7 +31,7 @@ struct hourly_filename_calculator { filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}{:02d}{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, + return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, now_tm.tm_hour, ext); } }; @@ -46,8 +46,10 @@ class hourly_file_sink final : public base_sink { public: // create hourly file sink which rotates on given time - hourly_file_sink(filename_t base_filename, bool truncate = false, uint16_t max_files = 0) + hourly_file_sink( + filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) : base_filename_(std::move(base_filename)) + , file_helper_{event_handlers} , truncate_(truncate) , max_files_(max_files) , filenames_q_() @@ -55,6 +57,7 @@ class hourly_file_sink final : public base_sink auto now = log_clock::now(); auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); file_helper_.open(filename, truncate_); + remove_init_file_ = file_helper_.size() == 0; rotation_tp_ = next_rotation_tp_(); if (max_files_ > 0) @@ -76,10 +79,16 @@ class hourly_file_sink final : public base_sink bool should_rotate = time >= rotation_tp_; if (should_rotate) { + if (remove_init_file_) + { + file_helper_.close(); + details::os::remove(file_helper_.filename()); + } auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); file_helper_.open(filename, truncate_); rotation_tp_ = next_rotation_tp_(); } + remove_init_file_ = false; memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); file_helper_.write(formatted); @@ -168,6 +177,7 @@ class hourly_file_sink final : public base_sink bool truncate_; uint16_t max_files_; details::circular_q filenames_q_; + bool remove_init_file_; }; using hourly_file_sink_mt = hourly_file_sink; @@ -179,16 +189,16 @@ using hourly_file_sink_st = hourly_file_sink; // factory functions // template -inline std::shared_ptr hourly_logger_mt( - const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0) +inline std::shared_ptr hourly_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files); + return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); } template -inline std::shared_ptr hourly_logger_st( - const std::string &logger_name, const filename_t &filename, bool truncate = false, uint16_t max_files = 0) +inline std::shared_ptr hourly_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, + uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, truncate, max_files); + return Factory::template create(logger_name, filename, truncate, max_files, event_handlers); } } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/kafka_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/kafka_sink.h new file mode 100644 index 000000000..ce740efc0 --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/sinks/kafka_sink.h @@ -0,0 +1,133 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for kafka +// Building and using requires librdkafka library. +// For building librdkafka library check the url below +// https://github.com/confluentinc/librdkafka +// + +#include +#include "spdlog/details/log_msg.h" +#include "spdlog/sinks/base_sink.h" +#include "spdlog/details/synchronous_factory.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/async.h" +#include + +// kafka header +#include + +namespace spdlog { +namespace sinks { + +struct kafka_sink_config +{ + std::string server_addr; + std::string produce_topic; + int32_t flush_timeout_ms = 1000; + + kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000) + : server_addr{std::move(addr)} + , produce_topic{std::move(topic)} + , flush_timeout_ms(flush_timeout_ms) + {} +}; + +template +class kafka_sink : public base_sink +{ +public: + kafka_sink(kafka_sink_config config) + : config_{std::move(config)} + { + try + { + std::string errstr; + conf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)); + RdKafka::Conf::ConfResult confRes = conf_->set("bootstrap.servers", config_.server_addr, errstr); + if (confRes != RdKafka::Conf::CONF_OK) + { + throw_spdlog_ex(fmt_lib::format("conf set bootstrap.servers failed err:{}", errstr)); + } + + tconf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)); + if (tconf_ == nullptr) + { + throw_spdlog_ex(fmt_lib::format("create topic config failed")); + } + + producer_.reset(RdKafka::Producer::create(conf_.get(), errstr)); + if (producer_ == nullptr) + { + throw_spdlog_ex(fmt_lib::format("create producer failed err:{}", errstr)); + } + topic_.reset(RdKafka::Topic::create(producer_.get(), config_.produce_topic, tconf_.get(), errstr)); + if (topic_ == nullptr) + { + throw_spdlog_ex(fmt_lib::format("create topic failed err:{}", errstr)); + } + } + catch (const std::exception &e) + { + throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what())); + } + } + + ~kafka_sink() + { + producer_->flush(config_.flush_timeout_ms); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, (void *)msg.payload.data(), msg.payload.size(), NULL, NULL); + } + + void flush_() override + { + producer_->flush(config_.flush_timeout_ms); + } + +private: + kafka_sink_config config_; + std::unique_ptr producer_ = nullptr; + std::unique_ptr conf_ = nullptr; + std::unique_ptr tconf_ = nullptr; + std::unique_ptr topic_ = nullptr; +}; + +using kafka_sink_mt = kafka_sink; +using kafka_sink_st = kafka_sink; + +} // namespace sinks + +template +inline std::shared_ptr kafka_logger_mt(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_st(const std::string &logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_async_mt(std::string logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_async_st(std::string logger_name, spdlog::sinks::kafka_sink_config config) +{ + return Factory::template create(logger_name, config); +} + +} // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/mongo_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/mongo_sink.h index 048b457cf..6a8927f54 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/mongo_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/mongo_sink.h @@ -30,16 +30,26 @@ class mongo_sink : public base_sink { public: mongo_sink(const std::string &db_name, const std::string &collection_name, const std::string &uri = "mongodb://localhost:27017") + try : mongo_sink(std::make_shared(), db_name, collection_name, uri) + {} + catch (const std::exception &e) + { + throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); + } + + mongo_sink(std::shared_ptr instance, const std::string &db_name, const std::string &collection_name, + const std::string &uri = "mongodb://localhost:27017") + : instance_(std::move(instance)) + , db_name_(db_name) + , coll_name_(collection_name) { try { - client_ = std::make_unique(mongocxx::uri{uri}); - db_name_ = db_name; - coll_name_ = collection_name; + client_ = spdlog::details::make_unique(mongocxx::uri{uri}); } - catch (const std::exception) + catch (const std::exception &e) { - throw spdlog_ex("Error opening database"); + throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); } } @@ -57,8 +67,8 @@ class mongo_sink : public base_sink if (client_ != nullptr) { auto doc = document{} << "timestamp" << bsoncxx::types::b_date(msg.time) << "level" << level::to_string_view(msg.level).data() - << "message" << std::string(msg.payload.begin(), msg.payload.end()) << "logger_name" - << std::string(msg.logger_name.begin(), msg.logger_name.end()) << "thread_id" + << "level_num" << msg.level << "message" << std::string(msg.payload.begin(), msg.payload.end()) + << "logger_name" << std::string(msg.logger_name.begin(), msg.logger_name.end()) << "thread_id" << static_cast(msg.thread_id) << finalize; client_->database(db_name_).collection(coll_name_).insert_one(doc.view()); } @@ -67,12 +77,11 @@ class mongo_sink : public base_sink void flush_() override {} private: - static mongocxx::instance instance_; + std::shared_ptr instance_; std::string db_name_; std::string coll_name_; std::unique_ptr client_ = nullptr; }; -mongocxx::instance mongo_sink::instance_{}; #include "spdlog/details/null_mutex.h" #include diff --git a/Lumos/External/spdlog/include/spdlog/sinks/msvc_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/msvc_sink.h index 2ac4a9659..bf68ae880 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/msvc_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/msvc_sink.h @@ -1,4 +1,4 @@ -// Copyright(c) 2016 Alexander Dalshov. +// Copyright(c) 2016 Alexander Dalshov & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) #pragma once @@ -6,13 +6,21 @@ #if defined(_WIN32) # include +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +# include +# endif # include # include # include // Avoid including windows.h (https://stackoverflow.com/a/30741042) +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString); +# else extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); +# endif +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); namespace spdlog { namespace sinks { @@ -24,16 +32,31 @@ class msvc_sink : public base_sink { public: msvc_sink() = default; + msvc_sink(bool check_debugger_present) + : check_debugger_present_{check_debugger_present} {}; protected: void sink_it_(const details::log_msg &msg) override { + if (check_debugger_present_ && !IsDebuggerPresent()) + { + return; + } memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); - OutputDebugStringA(fmt::to_string(formatted).c_str()); + formatted.push_back('\0'); // add a null terminator for OutputDebugString +# if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) + wmemory_buf_t wformatted; + details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); + OutputDebugStringW(wformatted.data()); +# else + OutputDebugStringA(formatted.data()); +# endif } void flush_() override {} + + bool check_debugger_present_ = true; }; using msvc_sink_mt = msvc_sink; diff --git a/Lumos/External/spdlog/include/spdlog/sinks/qt_sinks.h b/Lumos/External/spdlog/include/spdlog/sinks/qt_sinks.h index 5a9a83da7..f801ac344 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/qt_sinks.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/qt_sinks.h @@ -4,197 +4,289 @@ #pragma once // -// Custom sink for QPlainTextEdit or QTextEdit and its children(QTextBrowser... +// Custom sink for QPlainTextEdit or QTextEdit and its childs(QTextBrowser... // etc) Building and using requires Qt library. // +// Warning: the qt_sink won't be notified if the target widget is destroyed. +// If the widget's lifetime can be shorter than the logger's one, you should provide some permanent QObject, +// and then use a standard signal/slot. +// #include "spdlog/common.h" #include "spdlog/details/log_msg.h" #include "spdlog/details/synchronous_factory.h" #include "spdlog/sinks/base_sink.h" +#include -#include -#include #include +#include -namespace _spdlog_p { -namespace _sinks_p { // -// Private class for QTextEdit and its derivatives +// qt_sink class // -class qtextedit_sink_p : public QObject +namespace spdlog { +namespace sinks { +template +class qt_sink : public base_sink { - Q_OBJECT public: - qtextedit_sink_p(QTextEdit *textedit = nullptr) + qt_sink(QObject *qt_object, std::string meta_method) + : qt_object_(qt_object) + , meta_method_(std::move(meta_method)) { - if (textedit != nullptr) + if (!qt_object_) { - textedit_ = textedit; - connect(this, &qtextedit_sink_p::append_text, textedit_, &QTextEdit::append); + throw_spdlog_ex("qt_sink: qt_object is null"); } } - ~qtextedit_sink_p() {} + ~qt_sink() + { + flush_(); + } - void append(const spdlog::string_view_t &str) +protected: + void sink_it_(const details::log_msg &msg) override { - emit append_text(QString::fromUtf8(str.data(), static_cast(str.size() - 2))); + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + QMetaObject::invokeMethod(qt_object_, meta_method_.c_str(), Qt::AutoConnection, + Q_ARG(QString, QString::fromUtf8(str.data(), static_cast(str.size())).trimmed())); } -signals: - void append_text(const QString &); + void flush_() override {} private: - QTextEdit *textedit_ = nullptr; + QObject *qt_object_ = nullptr; + std::string meta_method_; }; -// -// Private class for QPlainTextEdit -// -class qplaintextedit_sink_p : public QObject +// QT color sink to QTextEdit. +// Color location is determined by the sink log pattern like in the rest of spdlog sinks. +// Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). +// max_lines is the maximum number of lines that the sink will hold before removing the oldest lines. +// Note: Only ascii (latin1) is supported by this sink. +template +class qt_color_sink : public base_sink { - Q_OBJECT public: - qplaintextedit_sink_p(QPlainTextEdit *textedit = nullptr) + qt_color_sink(QTextEdit *qt_text_edit, int max_lines) + : qt_text_edit_(qt_text_edit) + , max_lines_(max_lines) { - if (textedit != nullptr) + if (!qt_text_edit_) { - textedit_ = textedit; - connect(this, &qplaintextedit_sink_p::append_text, textedit_, &QPlainTextEdit::appendPlainText); + throw_spdlog_ex("qt_color_text_sink: text_edit is null"); } - } - ~qplaintextedit_sink_p() {} + default_color_ = qt_text_edit_->currentCharFormat(); + // set colors + QTextCharFormat format; + // trace + format.setForeground(Qt::gray); + colors_.at(level::trace) = format; + // debug + format.setForeground(Qt::cyan); + colors_.at(level::debug) = format; + // info + format.setForeground(Qt::green); + colors_.at(level::info) = format; + // warn + format.setForeground(Qt::yellow); + colors_.at(level::warn) = format; + // err + format.setForeground(Qt::red); + colors_.at(level::err) = format; + // critical + format.setForeground(Qt::white); + format.setBackground(Qt::red); + colors_.at(level::critical) = format; + } - void append(const spdlog::string_view_t &str) + ~qt_color_sink() { - emit append_text(QString::fromUtf8(str.data(), static_cast(str.size() - 2))); + flush_(); } -signals: - void append_text(const QString &); + void set_default_color(QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + default_color_ = format; + } -private: - QPlainTextEdit *textedit_ = nullptr; -}; -} // namespace _sinks_p -} // namespace _spdlog_p + void set_level_color(level::level_enum color_level, QTextCharFormat format) + { + // std::lock_guard lock(base_sink::mutex_); + colors_.at(static_cast(color_level)) = format; + } -// -// qtextedit_sink class -// -namespace spdlog { -namespace sinks { -template -class qtextedit_sink : public base_sink -{ -public: - qtextedit_sink(QTextEdit *textedit = nullptr) + QTextCharFormat &get_level_color(level::level_enum color_level) { - if (textedit != nullptr) - { - textedit_p = std::make_shared<_spdlog_p::_sinks_p::qtextedit_sink_p>(textedit); - } - else - { - throw spdlog_ex("Error opening QTextEdit"); - } + std::lock_guard lock(base_sink::mutex_); + return colors_.at(static_cast(color_level)); } - ~qtextedit_sink() + QTextCharFormat &get_default_color() { - flush_(); + std::lock_guard lock(base_sink::mutex_); + return default_color_; } protected: + struct invoke_params + { + invoke_params(int max_lines, QTextEdit *q_text_edit, QString payload, QTextCharFormat default_color, QTextCharFormat level_color, + int color_range_start, int color_range_end) + : max_lines(max_lines) + , q_text_edit(q_text_edit) + , payload(std::move(payload)) + , default_color(default_color) + , level_color(level_color) + , color_range_start(color_range_start) + , color_range_end(color_range_end) + {} + int max_lines; + QTextEdit *q_text_edit; + QString payload; + QTextCharFormat default_color; + QTextCharFormat level_color; + int color_range_start; + int color_range_end; + }; + void sink_it_(const details::log_msg &msg) override { memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); - string_view_t str_v = string_view_t(formatted.data(), formatted.size()); - textedit_p->append(str_v); + + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + // apply the color to the color range in the formatted message. + auto payload = QString::fromLatin1(str.data(), static_cast(str.size())); + + invoke_params params{max_lines_, // max lines + qt_text_edit_, // text edit to append to + std::move(payload), // text to append + default_color_, // default color + colors_.at(msg.level), // color to apply + static_cast(msg.color_range_start), // color range start + static_cast(msg.color_range_end)}; // color range end + + QMetaObject::invokeMethod( + qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection); } void flush_() override {} -private: - std::shared_ptr<_spdlog_p::_sinks_p::qtextedit_sink_p> textedit_p = nullptr; -}; + // Add colored text to the text edit widget. This method is invoked in the GUI thread. + // It is a static method to ensure that it is handled correctly even if the sink is destroyed prematurely + // before it is invoked. -// -// qplaintextedit_sink class -// -template -class qplaintextedit_sink : public base_sink -{ -public: - qplaintextedit_sink(QPlainTextEdit *textedit = nullptr) + static void invoke_method_(invoke_params params) { - if (textedit != nullptr) + auto *document = params.q_text_edit->document(); + QTextCursor cursor(document); + + // remove first blocks if number of blocks exceeds max_lines + while (document->blockCount() > params.max_lines) { - textedit_p = std::make_shared<_spdlog_p::_sinks_p::qplaintextedit_sink_p>(textedit); + cursor.select(QTextCursor::BlockUnderCursor); + cursor.removeSelectedText(); + cursor.deleteChar(); // delete the newline after the block } - else + + cursor.movePosition(QTextCursor::End); + cursor.setCharFormat(params.default_color); + + // if color range not specified or not not valid, just append the text with default color + if (params.color_range_end <= params.color_range_start) { - throw spdlog_ex("Error opening QPlainTextEdit"); + cursor.insertText(params.payload); + return; } - } - ~qplaintextedit_sink() - { - flush_(); - } + // insert the text before the color range + cursor.insertText(params.payload.left(params.color_range_start)); -protected: - void sink_it_(const details::log_msg &msg) override - { - memory_buf_t formatted; - base_sink::formatter_->format(msg, formatted); - string_view_t str_v = string_view_t(formatted.data(), formatted.size()); - textedit_p->append(str_v); - } + // insert the colorized text + cursor.setCharFormat(params.level_color); + cursor.insertText(params.payload.mid(params.color_range_start, params.color_range_end - params.color_range_start)); - void flush_() override {} + // insert the text after the color range with default format + cursor.setCharFormat(params.default_color); + cursor.insertText(params.payload.mid(params.color_range_end)); + } -private: - std::shared_ptr<_spdlog_p::_sinks_p::qplaintextedit_sink_p> textedit_p = nullptr; + QTextEdit *qt_text_edit_; + int max_lines_; + QTextCharFormat default_color_; + std::array colors_; }; #include "spdlog/details/null_mutex.h" #include -using qtextedit_sink_mt = qtextedit_sink; -using qtextedit_sink_st = qtextedit_sink; - -using qplaintextedit_sink_mt = qplaintextedit_sink; -using qplaintextedit_sink_st = qplaintextedit_sink; +using qt_sink_mt = qt_sink; +using qt_sink_st = qt_sink; +using qt_color_sink_mt = qt_color_sink; +using qt_color_sink_st = qt_color_sink; } // namespace sinks // // Factory functions // + +// log to QTextEdit template -inline std::shared_ptr qtextedit_logger_mt(const std::string &logger_name, QTextEdit *qtextedit = nullptr) +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") { - return Factory::template create(logger_name, qtextedit); + return Factory::template create(logger_name, qt_object, meta_method); } template -inline std::shared_ptr qtextedit_logger_st(const std::string &logger_name, QTextEdit *qtextedit = nullptr) +inline std::shared_ptr qt_logger_st(const std::string &logger_name, QTextEdit *qt_object, const std::string &meta_method = "append") { - return Factory::template create(logger_name, qtextedit); + return Factory::template create(logger_name, qt_object, meta_method); } +// log to QPlainTextEdit template -inline std::shared_ptr qplaintextedit_logger_mt(const std::string &logger_name, QPlainTextEdit *qplaintextedit = nullptr) +inline std::shared_ptr qt_logger_mt( + const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") { - return Factory::template create(logger_name, qplaintextedit); + return Factory::template create(logger_name, qt_object, meta_method); } template -inline std::shared_ptr qplaintextedit_logger_st(const std::string &logger_name, QPlainTextEdit *qplaintextedit = nullptr) +inline std::shared_ptr qt_logger_st( + const std::string &logger_name, QPlainTextEdit *qt_object, const std::string &meta_method = "appendPlainText") { - return Factory::template create(logger_name, qplaintextedit); + return Factory::template create(logger_name, qt_object, meta_method); } +// log to QObject +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, QObject *qt_object, const std::string &meta_method) +{ + return Factory::template create(logger_name, qt_object, meta_method); +} + +// log to QTextEdit with colorize output +template +inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) +{ + return Factory::template create(logger_name, qt_text_edit, max_lines); +} + +template +inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, QTextEdit *qt_text_edit, int max_lines) +{ + return Factory::template create(logger_name, qt_text_edit, max_lines); +} + } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/ringbuffer_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/ringbuffer_sink.h index 1ee3f6916..3ca47c6f7 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/ringbuffer_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/ringbuffer_sink.h @@ -50,7 +50,7 @@ class ringbuffer_sink final : public base_sink { memory_buf_t formatted; base_sink::formatter_->format(q_.at(i), formatted); - ret.push_back(fmt::to_string(formatted)); + ret.push_back(SPDLOG_BUF_TO_STRING(formatted)); } return ret; } diff --git a/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h b/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h index f31f53190..cf8b9d5c6 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink-inl.h @@ -25,16 +25,27 @@ namespace sinks { template SPDLOG_INLINE rotating_file_sink::rotating_file_sink( - filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open) + filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open, const file_event_handlers &event_handlers) : base_filename_(std::move(base_filename)) , max_size_(max_size) , max_files_(max_files) + , file_helper_{event_handlers} { + if (max_size == 0) + { + throw_spdlog_ex("rotating sink constructor: max_size arg cannot be zero"); + } + + if (max_files > 200000) + { + throw_spdlog_ex("rotating sink constructor: max_files arg cannot exceed 200000"); + } file_helper_.open(calc_filename(base_filename_, 0)); current_size_ = file_helper_.size(); // expensive. called only once if (rotate_on_open && current_size_ > 0) { rotate_(); + current_size_ = 0; } } @@ -50,7 +61,7 @@ SPDLOG_INLINE filename_t rotating_file_sink::calc_filename(const filename filename_t basename, ext; std::tie(basename, ext) = details::file_helper::split_by_extension(filename); - return fmt::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); + return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); } template @@ -65,13 +76,22 @@ SPDLOG_INLINE void rotating_file_sink::sink_it_(const details::log_msg &m { memory_buf_t formatted; base_sink::formatter_->format(msg, formatted); - current_size_ += formatted.size(); - if (current_size_ > max_size_) + auto new_size = current_size_ + formatted.size(); + + // rotate if the new estimated file size exceeds max size. + // rotate only if the real size > 0 to better deal with full disk (see issue #2261). + // we only check the real size when new_size > max_size_ because it is relatively expensive. + if (new_size > max_size_) { - rotate_(); - current_size_ = formatted.size(); + file_helper_.flush(); + if (file_helper_.size() > 0) + { + rotate_(); + new_size = formatted.size(); + } } file_helper_.write(formatted); + current_size_ = new_size; } template @@ -90,6 +110,7 @@ SPDLOG_INLINE void rotating_file_sink::rotate_() { using details::os::filename_to_str; using details::os::path_exists; + file_helper_.close(); for (auto i = max_files_; i > 0; --i) { diff --git a/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink.h index 842527ef7..ce0d7b1ef 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/rotating_file_sink.h @@ -22,7 +22,8 @@ template class rotating_file_sink final : public base_sink { public: - rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false); + rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open = false, + const file_event_handlers &event_handlers = {}); static filename_t calc_filename(const filename_t &filename, std::size_t index); filename_t filename(); @@ -59,17 +60,19 @@ using rotating_file_sink_st = rotating_file_sink; // template -inline std::shared_ptr rotating_logger_mt( - const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false) +inline std::shared_ptr rotating_logger_mt(const std::string &logger_name, const filename_t &filename, size_t max_file_size, + size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open); + return Factory::template create( + logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); } template -inline std::shared_ptr rotating_logger_st( - const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false) +inline std::shared_ptr rotating_logger_st(const std::string &logger_name, const filename_t &filename, size_t max_file_size, + size_t max_files, bool rotate_on_open = false, const file_event_handlers &event_handlers = {}) { - return Factory::template create(logger_name, filename, max_file_size, max_files, rotate_on_open); + return Factory::template create( + logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); } } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/stdout_sinks-inl.h b/Lumos/External/spdlog/include/spdlog/sinks/stdout_sinks-inl.h index c14066b9b..c1754370f 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/stdout_sinks-inl.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/stdout_sinks-inl.h @@ -16,7 +16,7 @@ // so instead we use ::FileWrite # include -# ifndef _USING_V110_SDK71_ // fileapi.h doesnt exist in winxp +# ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp # include // WriteFile (..) # endif @@ -37,7 +37,7 @@ SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) #ifdef _WIN32 // get windows handle from the FILE* object - handle_ = (HANDLE)::_get_osfhandle(::_fileno(file_)); + handle_ = reinterpret_cast(::_get_osfhandle(::_fileno(file_))); // don't throw to support cases where no console is attached, // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE). @@ -60,7 +60,6 @@ SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &m std::lock_guard lock(mutex_); memory_buf_t formatted; formatter_->format(msg, formatted); - ::fflush(file_); // flush in case there is somthing in this file_ already auto size = static_cast(formatted.size()); DWORD bytes_written = 0; bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; @@ -73,8 +72,8 @@ SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &m memory_buf_t formatted; formatter_->format(msg, formatted); ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); +#endif // WIN32 ::fflush(file_); // flush every line to terminal -#endif // WIN32 } template diff --git a/Lumos/External/spdlog/include/spdlog/sinks/systemd_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/systemd_sink.h index e3d513a0d..b00a95f29 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/systemd_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/systemd_sink.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include @@ -18,16 +19,15 @@ namespace sinks { /** * Sink that write to systemd journal using the `sd_journal_send()` library call. - * - * Locking is not needed, as `sd_journal_send()` itself is thread-safe. */ template class systemd_sink : public base_sink { public: - // - systemd_sink() - : syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, + systemd_sink(std::string ident = "", bool enable_formatting = false) + : ident_{std::move(ident)} + , enable_formatting_{enable_formatting} + , syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, /* spdlog::level::debug */ LOG_DEBUG, /* spdlog::level::info */ LOG_INFO, /* spdlog::level::warn */ LOG_WARNING, @@ -42,31 +42,52 @@ class systemd_sink : public base_sink systemd_sink &operator=(const systemd_sink &) = delete; protected: + const std::string ident_; + bool enable_formatting_ = false; using levels_array = std::array; levels_array syslog_levels_; void sink_it_(const details::log_msg &msg) override { int err; + string_view_t payload; + memory_buf_t formatted; + if (enable_formatting_) + { + base_sink::formatter_->format(msg, formatted); + payload = string_view_t(formatted.data(), formatted.size()); + } + else + { + payload = msg.payload; + } - size_t length = msg.payload.size(); + size_t length = payload.size(); // limit to max int if (length > static_cast(std::numeric_limits::max())) { length = static_cast(std::numeric_limits::max()); } + const string_view_t syslog_identifier = ident_.empty() ? msg.logger_name : ident_; + // Do not send source location if not available if (msg.source.empty()) { // Note: function call inside '()' to avoid macro expansion - err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), - "SYSLOG_IDENTIFIER=%.*s", static_cast(msg.logger_name.size()), msg.logger_name.data(), nullptr); + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", details::os::thread_id(), +#endif + "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), nullptr); } else { - err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), - "SYSLOG_IDENTIFIER=%.*s", static_cast(msg.logger_name.size()), msg.logger_name.data(), "CODE_FILE=%s", + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", details::os::thread_id(), +#endif + "SYSLOG_IDENTIFIER=%.*s", static_cast(syslog_identifier.size()), syslog_identifier.data(), "CODE_FILE=%s", msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr); } @@ -90,14 +111,16 @@ using systemd_sink_st = systemd_sink; // Create and register a syslog logger template -inline std::shared_ptr systemd_logger_mt(const std::string &logger_name) +inline std::shared_ptr systemd_logger_mt( + const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) { - return Factory::template create(logger_name); + return Factory::template create(logger_name, ident, enable_formatting); } template -inline std::shared_ptr systemd_logger_st(const std::string &logger_name) +inline std::shared_ptr systemd_logger_st( + const std::string &logger_name, const std::string &ident = "", bool enable_formatting = false) { - return Factory::template create(logger_name); + return Factory::template create(logger_name, ident, enable_formatting); } } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/udp_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/udp_sink.h new file mode 100644 index 000000000..ccbce2be3 --- /dev/null +++ b/Lumos/External/spdlog/include/spdlog/sinks/udp_sink.h @@ -0,0 +1,74 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif + +#include +#include +#include +#include + +// Simple udp client sink +// Sends formatted log via udp + +namespace spdlog { +namespace sinks { + +struct udp_sink_config +{ + std::string server_host; + uint16_t server_port; + + udp_sink_config(std::string host, uint16_t port) + : server_host{std::move(host)} + , server_port{port} + {} +}; + +template +class udp_sink : public spdlog::sinks::base_sink +{ +public: + // host can be hostname or ip address + explicit udp_sink(udp_sink_config sink_config) + : client_{sink_config.server_host, sink_config.server_port} + {} + + ~udp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override + { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + details::udp_client client_; +}; + +using udp_sink_mt = udp_sink; +using udp_sink_st = udp_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr udp_logger_mt(const std::string &logger_name, sinks::udp_sink_config skin_config) +{ + return Factory::template create(logger_name, skin_config); +} + +} // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/sinks/win_eventlog_sink.h b/Lumos/External/spdlog/include/spdlog/sinks/win_eventlog_sink.h index 5e70599a1..d23d00a8b 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/win_eventlog_sink.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/win_eventlog_sink.h @@ -47,6 +47,24 @@ namespace win_eventlog { namespace internal { +struct local_alloc_t +{ + HLOCAL hlocal_; + + SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT : hlocal_(nullptr) {} + + local_alloc_t(local_alloc_t const &) = delete; + local_alloc_t &operator=(local_alloc_t const &) = delete; + + ~local_alloc_t() SPDLOG_NOEXCEPT + { + if (hlocal_) + { + LocalFree(hlocal_); + } + } +}; + /** Windows error */ struct win32_error : public spdlog_ex { @@ -55,22 +73,17 @@ struct win32_error : public spdlog_ex { std::string system_message; - LPSTR format_message_result{}; + local_alloc_t format_message_result{}; auto format_message_succeeded = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, - error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr); - - if (format_message_succeeded && format_message_result) - { - system_message = fmt::format(" ({})", format_message_result); - } + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result.hlocal_, 0, nullptr); - if (format_message_result) + if (format_message_succeeded && format_message_result.hlocal_) { - LocalFree((HLOCAL)format_message_result); + system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_); } - return fmt::format("{}: {}{}", user_message, error_code, system_message); + return fmt_lib::format("{}: {}{}", user_message, error_code, system_message); } explicit win32_error(std::string const &func_name, DWORD error = GetLastError()) @@ -197,7 +210,7 @@ class win_eventlog_sink : public base_sink HANDLE hEventLog_{NULL}; internal::sid_t current_user_sid_; std::string source_; - WORD event_id_; + DWORD event_id_; HANDLE event_log_handle() { @@ -228,12 +241,12 @@ class win_eventlog_sink : public base_sink details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); LPCWSTR lp_wstr = buf.data(); - succeeded = ::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, - current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr); + succeeded = static_cast(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); #else LPCSTR lp_str = formatted.data(); - succeeded = ::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_, - current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr); + succeeded = static_cast(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); #endif if (!succeeded) @@ -245,7 +258,7 @@ class win_eventlog_sink : public base_sink void flush_() override {} public: - win_eventlog_sink(std::string const &source, WORD event_id = 1000 /* according to mscoree.dll */) + win_eventlog_sink(std::string const &source, DWORD event_id = 1000 /* according to mscoree.dll */) : source_(source) , event_id_(event_id) { diff --git a/Lumos/External/spdlog/include/spdlog/sinks/wincolor_sink-inl.h b/Lumos/External/spdlog/include/spdlog/sinks/wincolor_sink-inl.h index be3d80a20..8311929e4 100644 --- a/Lumos/External/spdlog/include/spdlog/sinks/wincolor_sink-inl.h +++ b/Lumos/External/spdlog/include/spdlog/sinks/wincolor_sink-inl.h @@ -45,7 +45,7 @@ template void SPDLOG_INLINE wincolor_sink::set_color(level::level_enum level, std::uint16_t color) { std::lock_guard lock(mutex_); - colors_[level] = color; + colors_[static_cast(level)] = color; } template @@ -66,7 +66,7 @@ void SPDLOG_INLINE wincolor_sink::log(const details::log_msg &msg) // before color range print_range_(formatted, 0, msg.color_range_start); // in color range - auto orig_attribs = static_cast(set_foreground_color_(colors_[msg.level])); + auto orig_attribs = static_cast(set_foreground_color_(colors_[static_cast(msg.level)])); print_range_(formatted, msg.color_range_start, msg.color_range_end); // reset to orig colors ::SetConsoleTextAttribute(static_cast(out_handle_), orig_attribs); diff --git a/Lumos/External/spdlog/include/spdlog/spdlog-inl.h b/Lumos/External/spdlog/include/spdlog/spdlog-inl.h index 2b875fae9..22ea22bb4 100644 --- a/Lumos/External/spdlog/include/spdlog/spdlog-inl.h +++ b/Lumos/External/spdlog/include/spdlog/spdlog-inl.h @@ -67,11 +67,6 @@ SPDLOG_INLINE void flush_on(level::level_enum log_level) details::registry::instance().flush_on(log_level); } -SPDLOG_INLINE void flush_every(std::chrono::seconds interval) -{ - details::registry::instance().flush_every(interval); -} - SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) { details::registry::instance().set_error_handler(handler); @@ -122,4 +117,9 @@ SPDLOG_INLINE void set_default_logger(std::shared_ptr default_lo details::registry::instance().set_default_logger(std::move(default_logger)); } +SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr logger) +{ + details::registry::instance().apply_logger_env_levels(std::move(logger)); +} + } // namespace spdlog diff --git a/Lumos/External/spdlog/include/spdlog/spdlog.h b/Lumos/External/spdlog/include/spdlog/spdlog.h index 41c6bbb81..fbfe5fb86 100644 --- a/Lumos/External/spdlog/include/spdlog/spdlog.h +++ b/Lumos/External/spdlog/include/spdlog/spdlog.h @@ -81,7 +81,11 @@ SPDLOG_API void flush_on(level::level_enum log_level); // Start/Restart a periodic flusher thread // Warning: Use only if all your loggers are thread safe! -SPDLOG_API void flush_every(std::chrono::seconds interval); +template +inline void flush_every(std::chrono::duration interval) +{ + details::registry::instance().flush_every(interval); +} // Set global error handler SPDLOG_API void set_error_handler(void (*handler)(const std::string &msg)); @@ -127,50 +131,59 @@ SPDLOG_API spdlog::logger *default_logger_raw(); SPDLOG_API void set_default_logger(std::shared_ptr default_logger); -template -inline void log(source_loc source, level::level_enum lvl, const FormatString &fmt, Args &&...args) +// Initialize logger level based on environment configs. +// +// Useful for applying SPDLOG_LEVEL to manually created loggers. +// +// Example: +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::apply_logger_env_levels(mylogger); +SPDLOG_API void apply_logger_env_levels(std::shared_ptr logger); + +template +inline void log(source_loc source, level::level_enum lvl, format_string_t fmt, Args &&...args) { default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); } -template -inline void log(level::level_enum lvl, const FormatString &fmt, Args &&...args) +template +inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); } -template -inline void trace(const FormatString &fmt, Args &&...args) +template +inline void trace(format_string_t fmt, Args &&...args) { default_logger_raw()->trace(fmt, std::forward(args)...); } -template -inline void debug(const FormatString &fmt, Args &&...args) +template +inline void debug(format_string_t fmt, Args &&...args) { default_logger_raw()->debug(fmt, std::forward(args)...); } -template -inline void info(const FormatString &fmt, Args &&...args) +template +inline void info(format_string_t fmt, Args &&...args) { default_logger_raw()->info(fmt, std::forward(args)...); } -template -inline void warn(const FormatString &fmt, Args &&...args) +template +inline void warn(format_string_t fmt, Args &&...args) { default_logger_raw()->warn(fmt, std::forward(args)...); } -template -inline void error(const FormatString &fmt, Args &&...args) +template +inline void error(format_string_t fmt, Args &&...args) { default_logger_raw()->error(fmt, std::forward(args)...); } -template -inline void critical(const FormatString &fmt, Args &&...args) +template +inline void critical(format_string_t fmt, Args &&...args) { default_logger_raw()->critical(fmt, std::forward(args)...); } @@ -187,6 +200,56 @@ inline void log(level::level_enum lvl, const T &msg) default_logger_raw()->log(lvl, msg); } +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +template +inline void log(source_loc source, level::level_enum lvl, wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); +} + +template +inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); +} + +template +inline void trace(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->trace(fmt, std::forward(args)...); +} + +template +inline void debug(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->debug(fmt, std::forward(args)...); +} + +template +inline void info(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->info(fmt, std::forward(args)...); +} + +template +inline void warn(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->warn(fmt, std::forward(args)...); +} + +template +inline void error(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->error(fmt, std::forward(args)...); +} + +template +inline void critical(wformat_string_t fmt, Args &&...args) +{ + default_logger_raw()->critical(fmt, std::forward(args)...); +} +#endif + template inline void trace(const T &msg) { @@ -238,7 +301,12 @@ inline void critical(const T &msg) // SPDLOG_LEVEL_OFF // -#define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) +#ifndef SPDLOG_NO_SOURCE_LOC +# define SPDLOG_LOGGER_CALL(logger, level, ...) \ + (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) +#else +# define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{}, level, __VA_ARGS__) +#endif #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE # define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) diff --git a/Lumos/External/spdlog/include/spdlog/stopwatch.h b/Lumos/External/spdlog/include/spdlog/stopwatch.h index bb976b19c..bea7b8a74 100644 --- a/Lumos/External/spdlog/include/spdlog/stopwatch.h +++ b/Lumos/External/spdlog/include/spdlog/stopwatch.h @@ -4,6 +4,7 @@ #pragma once #include +#include // Stopwatch support for spdlog (using std::chrono::steady_clock). // Displays elapsed seconds since construction as double. @@ -42,20 +43,27 @@ class stopwatch void reset() { - start_tp_ = clock ::now(); + start_tp_ = clock::now(); } }; } // namespace spdlog // Support for fmt formatting (e.g. "{:012.9}" or just "{}") -namespace fmt { +namespace +#ifdef SPDLOG_USE_STD_FORMAT + std +#else + fmt +#endif +{ + template<> struct formatter : formatter { template - auto format(const spdlog::stopwatch &sw, FormatContext &ctx) -> decltype(ctx.out()) + auto format(const spdlog::stopwatch &sw, FormatContext &ctx) const -> decltype(ctx.out()) { return formatter::format(sw.elapsed().count(), ctx); } }; -} // namespace fmt +} // namespace std diff --git a/Lumos/External/spdlog/include/spdlog/tweakme.h b/Lumos/External/spdlog/include/spdlog/tweakme.h index 24361f303..5bcb5ff42 100644 --- a/Lumos/External/spdlog/include/spdlog/tweakme.h +++ b/Lumos/External/spdlog/include/spdlog/tweakme.h @@ -19,6 +19,13 @@ // #define SPDLOG_CLOCK_COARSE /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment if source location logging is not needed. +// This will prevent spdlog from using __FILE__, __LINE__ and SPDLOG_FUNCTION +// +// #define SPDLOG_NO_SOURCE_LOC +/////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// // Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). // This will prevent spdlog from querying the thread id on each log call. @@ -74,6 +81,12 @@ // #define SPDLOG_FMT_EXTERNAL /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to use C++20 std::format instead of fmt. +// +// #define SPDLOG_USE_STD_FORMAT +/////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// // Uncomment to enable wchar_t support (convert to utf8) // @@ -89,8 +102,7 @@ /////////////////////////////////////////////////////////////////////////////// // Uncomment to customize level names (e.g. "MY TRACE") // -// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", -// "MY ERROR", "MY CRITICAL", "OFF" } +// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", "MY ERROR", "MY CRITICAL", "OFF" } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -120,5 +132,9 @@ // __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc. // Defaults to __FUNCTION__ (should work on all compilers) if not defined. // -// #define SPDLOG_FUNCTION __PRETTY_FUNCTION__ +// #ifdef __PRETTY_FUNCTION__ +// # define SPDLOG_FUNCTION __PRETTY_FUNCTION__ +// #else +// # define SPDLOG_FUNCTION __FUNCTION__ +// #endif /////////////////////////////////////////////////////////////////////////////// diff --git a/Lumos/External/spdlog/include/spdlog/version.h b/Lumos/External/spdlog/include/spdlog/version.h index e759a61e7..633cddc78 100644 --- a/Lumos/External/spdlog/include/spdlog/version.h +++ b/Lumos/External/spdlog/include/spdlog/version.h @@ -4,7 +4,7 @@ #pragma once #define SPDLOG_VER_MAJOR 1 -#define SPDLOG_VER_MINOR 9 +#define SPDLOG_VER_MINOR 12 #define SPDLOG_VER_PATCH 0 #define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) diff --git a/Lumos/External/spdlog/logos/jetbrains-variant-4.svg b/Lumos/External/spdlog/logos/jetbrains-variant-4.svg new file mode 100644 index 000000000..e02b55951 --- /dev/null +++ b/Lumos/External/spdlog/logos/jetbrains-variant-4.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Lumos/External/spdlog/scripts/ci_setup_clang.sh b/Lumos/External/spdlog/scripts/ci_setup_clang.sh new file mode 100644 index 000000000..140f9f9d0 --- /dev/null +++ b/Lumos/External/spdlog/scripts/ci_setup_clang.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -ex + +VERSION=$1 + +apt-get update +apt-get install -y libc++-${VERSION}-dev libc++abi-${VERSION}-dev + +if [[ "${VERSION}" -ge 12 ]]; then + apt-get install -y --no-install-recommends libunwind-${VERSION}-dev +fi diff --git a/Lumos/External/spdlog/scripts/extract_version.py b/Lumos/External/spdlog/scripts/extract_version.py new file mode 100644 index 000000000..79b5728a8 --- /dev/null +++ b/Lumos/External/spdlog/scripts/extract_version.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 + +import os +import re + +base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +config_h = os.path.join(base_path, 'include', 'spdlog', 'version.h') +data = {'MAJOR': 0, 'MINOR': 0, 'PATCH': 0} +reg = re.compile(r'^\s*#define\s+SPDLOG_VER_([A-Z]+)\s+([0-9]+).*$') + +with open(config_h, 'r') as fp: + for l in fp: + m = reg.match(l) + if m: + data[m.group(1)] = int(m.group(2)) + +print(f"{data['MAJOR']}.{data['MINOR']}.{data['PATCH']}") diff --git a/Lumos/External/spdlog/scripts/format.sh b/Lumos/External/spdlog/scripts/format.sh new file mode 100644 index 000000000..bd5868ebc --- /dev/null +++ b/Lumos/External/spdlog/scripts/format.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +cd "$(dirname "$0")"/.. +pwd +echo -n "Running dos2unix " +find . -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "dos2unix '{}' 2>/dev/null; echo -n '.'" +echo +echo -n "Running clang-format " +find . -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "clang-format -i {}; echo -n '.'" +echo +echo -n "Running cmake-format " +find . -name "CMakeLists.txt" -o -name "*\.cmake"|grep -v bundled|xargs -I {} sh -c "cmake-format --line-width 120 --tab-size 4 --max-subgroups-hwrap 4 -i {}; echo -n '.'" +echo + + + diff --git a/Lumos/External/spdlog/src/async.cpp b/Lumos/External/spdlog/src/async.cpp index b7443dfc3..5ea8d8f40 100644 --- a/Lumos/External/spdlog/src/async.cpp +++ b/Lumos/External/spdlog/src/async.cpp @@ -9,5 +9,3 @@ #include #include #include - -template class SPDLOG_API spdlog::details::mpmc_blocking_queue; diff --git a/Lumos/External/spdlog/src/bundled_fmtlib_format.cpp b/Lumos/External/spdlog/src/bundled_fmtlib_format.cpp new file mode 100644 index 000000000..933918260 --- /dev/null +++ b/Lumos/External/spdlog/src/bundled_fmtlib_format.cpp @@ -0,0 +1,52 @@ +// Slightly modified version of fmt lib's format.cc (version 1.9.1) source file. +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. + +#ifndef SPDLOG_COMPILED_LIB +# error Please define SPDLOG_COMPILED_LIB to compile this file. +#endif + +#if !defined(SPDLOG_FMT_EXTERNAL) && !defined(SPDLOG_USE_STD_FORMAT) + +#include + +FMT_BEGIN_NAMESPACE +namespace detail { + +template FMT_API auto dragonbox::to_decimal(float x) noexcept + -> dragonbox::decimal_fp; +template FMT_API auto dragonbox::to_decimal(double x) noexcept + -> dragonbox::decimal_fp; + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template FMT_API locale_ref::locale_ref(const std::locale& loc); +template FMT_API auto locale_ref::get() const -> std::locale; +#endif + +// Explicit instantiations for char. + +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +template FMT_API auto decimal_point_impl(locale_ref) -> char; + +template FMT_API void buffer::append(const char*, const char*); + +// DEPRECATED! +// There is no correspondent extern template in format.h because of +// incompatibility between clang and gcc (#2377). +template FMT_API void vformat_to(buffer&, string_view, + basic_format_args, + locale_ref); + +// Explicit instantiations for wchar_t. + +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; + +template FMT_API void buffer::append(const wchar_t*, const wchar_t*); + +} // namespace detail +FMT_END_NAMESPACE + +#endif // !SPDLOG_FMT_EXTERNAL diff --git a/Lumos/External/spdlog/src/fmt.cpp b/Lumos/External/spdlog/src/fmt.cpp deleted file mode 100644 index b3cd3cf13..000000000 --- a/Lumos/External/spdlog/src/fmt.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// Slightly modified version of fmt lib's format.cc source file. -// Copyright (c) 2012 - 2016, Victor Zverovich -// All rights reserved. - -#ifndef SPDLOG_COMPILED_LIB -# error Please define SPDLOG_COMPILED_LIB to compile this file. -#endif - -#if !defined(SPDLOG_FMT_EXTERNAL) -# include - -FMT_BEGIN_NAMESPACE -namespace detail { - -template -int format_float(char *buf, std::size_t size, const char *format, int precision, T value) -{ -# ifdef FMT_FUZZ - if (precision > 100000) - throw std::runtime_error("fuzz mode - avoid large allocation inside snprintf"); -# endif - // Suppress the warning about nonliteral format string. - int (*snprintf_ptr)(char *, size_t, const char *, ...) = FMT_SNPRINTF; - return precision < 0 ? snprintf_ptr(buf, size, format, value) : snprintf_ptr(buf, size, format, precision, value); -} - -template FMT_API dragonbox::decimal_fp dragonbox::to_decimal(float x) FMT_NOEXCEPT; -template FMT_API dragonbox::decimal_fp dragonbox::to_decimal(double x) FMT_NOEXCEPT; -} // namespace detail - -// Workaround a bug in MSVC2013 that prevents instantiation of format_float. -int (*instantiate_format_float)(double, int, detail::float_specs, detail::buffer &) = detail::format_float; - -# ifndef FMT_STATIC_THOUSANDS_SEPARATOR -template FMT_API detail::locale_ref::locale_ref(const std::locale &loc); -template FMT_API std::locale detail::locale_ref::get() const; -# endif - -// Explicit instantiations for char. - -template FMT_API auto detail::thousands_sep_impl(locale_ref) -> thousands_sep_result; -template FMT_API char detail::decimal_point_impl(locale_ref); - -template FMT_API void detail::buffer::append(const char *, const char *); - -// DEPRECATED! -// There is no correspondent extern template in format.h because of -// incompatibility between clang and gcc (#2377). -template FMT_API void detail::vformat_to( - detail::buffer &, string_view, basic_format_args, detail::locale_ref); - -template FMT_API int detail::snprintf_float(double, int, detail::float_specs, detail::buffer &); -template FMT_API int detail::snprintf_float(long double, int, detail::float_specs, detail::buffer &); -template FMT_API int detail::format_float(double, int, detail::float_specs, detail::buffer &); -template FMT_API int detail::format_float(long double, int, detail::float_specs, detail::buffer &); - -// Explicit instantiations for wchar_t. - -template FMT_API auto detail::thousands_sep_impl(locale_ref) -> thousands_sep_result; -template FMT_API wchar_t detail::decimal_point_impl(locale_ref); - -template FMT_API void detail::buffer::append(const wchar_t *, const wchar_t *); - -template struct detail::basic_data; - -FMT_END_NAMESPACE - -#endif // !SPDLOG_FMT_EXTERNAL diff --git a/Lumos/External/spdlog/tests/CMakeLists.txt b/Lumos/External/spdlog/tests/CMakeLists.txt new file mode 100644 index 000000000..176578ade --- /dev/null +++ b/Lumos/External/spdlog/tests/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION 3.10) +project(spdlog_utests CXX) + +if(NOT TARGET spdlog) + # Stand-alone build + find_package(spdlog REQUIRED) +endif() + +include(../cmake/utils.cmake) + +find_package(PkgConfig) +if(PkgConfig_FOUND) + pkg_check_modules(systemd libsystemd) +endif() + +find_package(Catch2 3 QUIET) +if(Catch2_FOUND) + message(STATUS "Packaged version of Catch will be used.") +else() + message(STATUS "Bundled version of Catch will be downloaded and used.") + include(FetchContent) + FetchContent_Declare(Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.3.2) + FetchContent_MakeAvailable(Catch2) +endif() + +set(SPDLOG_UTESTS_SOURCES + test_file_helper.cpp + test_file_logging.cpp + test_daily_logger.cpp + test_misc.cpp + test_eventlog.cpp + test_pattern_formatter.cpp + test_async.cpp + test_registry.cpp + test_macros.cpp + utils.cpp + main.cpp + test_mpmc_q.cpp + test_dup_filter.cpp + test_fmt_helper.cpp + test_stdout_api.cpp + test_backtrace.cpp + test_create_dir.cpp + test_custom_callbacks.cpp + test_cfg.cpp + test_time_point.cpp + test_stopwatch.cpp) + +if(NOT SPDLOG_NO_EXCEPTIONS) + list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp) +endif() + +if(systemd_FOUND) + list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp) +endif() + +if(NOT SPDLOG_USE_STD_FORMAT) + list(APPEND SPDLOG_UTESTS_SOURCES test_bin_to_hex.cpp) +endif() + +enable_testing() + +function(spdlog_prepare_test test_target spdlog_lib) + add_executable(${test_target} ${SPDLOG_UTESTS_SOURCES}) + spdlog_enable_warnings(${test_target}) + target_link_libraries(${test_target} PRIVATE ${spdlog_lib}) + if(systemd_FOUND) + target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES}) + endif() + target_link_libraries(${test_target} PRIVATE Catch2::Catch2WithMain) + if(SPDLOG_SANITIZE_ADDRESS) + spdlog_enable_sanitizer(${test_target}) + endif() + add_test(NAME ${test_target} COMMAND ${test_target}) + set_tests_properties(${test_target} PROPERTIES RUN_SERIAL ON) +endfunction() + +# The compiled library tests +if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_ALL) + spdlog_prepare_test(spdlog-utests spdlog::spdlog) +endif() + +# The header-only library version tests +if(SPDLOG_BUILD_TESTS_HO OR SPDLOG_BUILD_ALL) + spdlog_prepare_test(spdlog-utests-ho spdlog::spdlog_header_only) +endif() diff --git a/Lumos/External/spdlog/tests/includes.h b/Lumos/External/spdlog/tests/includes.h new file mode 100644 index 000000000..6e46992b5 --- /dev/null +++ b/Lumos/External/spdlog/tests/includes.h @@ -0,0 +1,36 @@ +#pragma once + +#if defined(__GNUC__) && __GNUC__ == 12 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12 +#endif +#include +#if defined(__GNUC__) && __GNUC__ == 12 +# pragma GCC diagnostic pop +#endif + +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG + +#include "spdlog/spdlog.h" +#include "spdlog/async.h" +#include "spdlog/details/fmt_helper.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/daily_file_sink.h" +#include "spdlog/sinks/null_sink.h" +#include "spdlog/sinks/ostream_sink.h" +#include "spdlog/sinks/rotating_file_sink.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/sinks/msvc_sink.h" +#include "spdlog/pattern_formatter.h" diff --git a/Lumos/External/spdlog/tests/main.cpp b/Lumos/External/spdlog/tests/main.cpp new file mode 100644 index 000000000..c8dca1936 --- /dev/null +++ b/Lumos/External/spdlog/tests/main.cpp @@ -0,0 +1,10 @@ +#if defined(__GNUC__) && __GNUC__ == 12 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12 +#endif + +#include + +#if defined(__GNUC__) && __GNUC__ == 12 +# pragma GCC diagnostic pop +#endif diff --git a/Lumos/External/spdlog/tests/test_async.cpp b/Lumos/External/spdlog/tests/test_async.cpp new file mode 100644 index 000000000..06c5c9214 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_async.cpp @@ -0,0 +1,198 @@ +#include "includes.h" +#include "spdlog/async.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "test_sink.h" + +#define TEST_FILENAME "test_logs/async_test.log" + +TEST_CASE("basic async test ", "[async]") +{ + auto test_sink = std::make_shared(); + size_t overrun_counter = 0; + size_t queue_size = 128; + size_t messages = 256; + { + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); + for (size_t i = 0; i < messages; i++) + { + logger->info("Hello message #{}", i); + } + logger->flush(); + overrun_counter = tp->overrun_counter(); + } + REQUIRE(test_sink->msg_counter() == messages); + REQUIRE(test_sink->flush_counter() == 1); + REQUIRE(overrun_counter == 0); +} + +TEST_CASE("discard policy ", "[async]") +{ + auto test_sink = std::make_shared(); + test_sink->set_delay(std::chrono::milliseconds(1)); + size_t queue_size = 4; + size_t messages = 1024; + + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::overrun_oldest); + for (size_t i = 0; i < messages; i++) + { + logger->info("Hello message"); + } + REQUIRE(test_sink->msg_counter() < messages); + REQUIRE(tp->overrun_counter() > 0); +} + +TEST_CASE("discard policy using factory ", "[async]") +{ + size_t queue_size = 4; + size_t messages = 1024; + spdlog::init_thread_pool(queue_size, 1); + + auto logger = spdlog::create_async_nb("as2"); + auto test_sink = std::static_pointer_cast(logger->sinks()[0]); + test_sink->set_delay(std::chrono::milliseconds(3)); + + for (size_t i = 0; i < messages; i++) + { + logger->info("Hello message"); + } + + REQUIRE(test_sink->msg_counter() < messages); + spdlog::drop_all(); +} + +TEST_CASE("flush", "[async]") +{ + auto test_sink = std::make_shared(); + size_t queue_size = 256; + size_t messages = 256; + { + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); + for (size_t i = 0; i < messages; i++) + { + logger->info("Hello message #{}", i); + } + + logger->flush(); + } + // std::this_thread::sleep_for(std::chrono::milliseconds(250)); + REQUIRE(test_sink->msg_counter() == messages); + REQUIRE(test_sink->flush_counter() == 1); +} + +TEST_CASE("async periodic flush", "[async]") +{ + + auto logger = spdlog::create_async("as"); + auto test_sink = std::static_pointer_cast(logger->sinks()[0]); + + spdlog::flush_every(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1700)); + REQUIRE(test_sink->flush_counter() == 1); + spdlog::flush_every(std::chrono::seconds(0)); + spdlog::drop_all(); +} + +TEST_CASE("tp->wait_empty() ", "[async]") +{ + auto test_sink = std::make_shared(); + test_sink->set_delay(std::chrono::milliseconds(5)); + size_t messages = 100; + + auto tp = std::make_shared(messages, 2); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); + for (size_t i = 0; i < messages; i++) + { + logger->info("Hello message #{}", i); + } + logger->flush(); + tp.reset(); + + REQUIRE(test_sink->msg_counter() == messages); + REQUIRE(test_sink->flush_counter() == 1); +} + +TEST_CASE("multi threads", "[async]") +{ + auto test_sink = std::make_shared(); + size_t queue_size = 128; + size_t messages = 256; + size_t n_threads = 10; + { + auto tp = std::make_shared(queue_size, 1); + auto logger = std::make_shared("as", test_sink, tp, spdlog::async_overflow_policy::block); + + std::vector threads; + for (size_t i = 0; i < n_threads; i++) + { + threads.emplace_back([logger, messages] { + for (size_t j = 0; j < messages; j++) + { + logger->info("Hello message #{}", j); + } + }); + logger->flush(); + } + + for (auto &t : threads) + { + t.join(); + } + } + + REQUIRE(test_sink->msg_counter() == messages * n_threads); + REQUIRE(test_sink->flush_counter() == n_threads); +} + +TEST_CASE("to_file", "[async]") +{ + prepare_logdir(); + size_t messages = 1024; + size_t tp_threads = 1; + spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME); + { + auto file_sink = std::make_shared(filename, true); + auto tp = std::make_shared(messages, tp_threads); + auto logger = std::make_shared("as", std::move(file_sink), std::move(tp)); + + for (size_t j = 0; j < messages; j++) + { + logger->info("Hello message #{}", j); + } + } + + require_message_count(TEST_FILENAME, messages); + auto contents = file_contents(TEST_FILENAME); + using spdlog::details::os::default_eol; + REQUIRE(ends_with(contents, spdlog::fmt_lib::format("Hello message #1023{}", default_eol))); +} + +TEST_CASE("to_file multi-workers", "[async]") +{ + prepare_logdir(); + size_t messages = 1024 * 10; + size_t tp_threads = 10; + spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME); + { + auto file_sink = std::make_shared(filename, true); + auto tp = std::make_shared(messages, tp_threads); + auto logger = std::make_shared("as", std::move(file_sink), std::move(tp)); + + for (size_t j = 0; j < messages; j++) + { + logger->info("Hello message #{}", j); + } + } + require_message_count(TEST_FILENAME, messages); +} + +TEST_CASE("bad_tp", "[async]") +{ + auto test_sink = std::make_shared(); + std::shared_ptr const empty_tp; + auto logger = std::make_shared("as", test_sink, empty_tp); + logger->info("Please throw an exception"); + REQUIRE(test_sink->msg_counter() == 0); +} diff --git a/Lumos/External/spdlog/tests/test_backtrace.cpp b/Lumos/External/spdlog/tests/test_backtrace.cpp new file mode 100644 index 000000000..6cf9ec550 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_backtrace.cpp @@ -0,0 +1,78 @@ +#include "includes.h" +#include "test_sink.h" +#include "spdlog/async.h" + +TEST_CASE("bactrace1", "[bactrace]") +{ + + using spdlog::sinks::test_sink_st; + auto test_sink = std::make_shared(); + size_t backtrace_size = 5; + + spdlog::logger logger("test-backtrace", test_sink); + logger.set_pattern("%v"); + logger.enable_backtrace(backtrace_size); + + logger.info("info message"); + for (int i = 0; i < 100; i++) + logger.debug("debug message {}", i); + + REQUIRE(test_sink->lines().size() == 1); + REQUIRE(test_sink->lines()[0] == "info message"); + + logger.dump_backtrace(); + REQUIRE(test_sink->lines().size() == backtrace_size + 3); + REQUIRE(test_sink->lines()[1] == "****************** Backtrace Start ******************"); + REQUIRE(test_sink->lines()[2] == "debug message 95"); + REQUIRE(test_sink->lines()[3] == "debug message 96"); + REQUIRE(test_sink->lines()[4] == "debug message 97"); + REQUIRE(test_sink->lines()[5] == "debug message 98"); + REQUIRE(test_sink->lines()[6] == "debug message 99"); + REQUIRE(test_sink->lines()[7] == "****************** Backtrace End ********************"); +} + +TEST_CASE("bactrace-empty", "[bactrace]") +{ + using spdlog::sinks::test_sink_st; + auto test_sink = std::make_shared(); + size_t backtrace_size = 5; + + spdlog::logger logger("test-backtrace", test_sink); + logger.set_pattern("%v"); + logger.enable_backtrace(backtrace_size); + logger.dump_backtrace(); + REQUIRE(test_sink->lines().size() == 0); +} + +TEST_CASE("bactrace-async", "[bactrace]") +{ + using spdlog::sinks::test_sink_mt; + auto test_sink = std::make_shared(); + using spdlog::details::os::sleep_for_millis; + + size_t backtrace_size = 5; + + spdlog::init_thread_pool(120, 1); + auto logger = std::make_shared("test-bactrace-async", test_sink, spdlog::thread_pool()); + logger->set_pattern("%v"); + logger->enable_backtrace(backtrace_size); + + logger->info("info message"); + for (int i = 0; i < 100; i++) + logger->debug("debug message {}", i); + + sleep_for_millis(100); + REQUIRE(test_sink->lines().size() == 1); + REQUIRE(test_sink->lines()[0] == "info message"); + + logger->dump_backtrace(); + sleep_for_millis(100); // give time for the async dump to complete + REQUIRE(test_sink->lines().size() == backtrace_size + 3); + REQUIRE(test_sink->lines()[1] == "****************** Backtrace Start ******************"); + REQUIRE(test_sink->lines()[2] == "debug message 95"); + REQUIRE(test_sink->lines()[3] == "debug message 96"); + REQUIRE(test_sink->lines()[4] == "debug message 97"); + REQUIRE(test_sink->lines()[5] == "debug message 98"); + REQUIRE(test_sink->lines()[6] == "debug message 99"); + REQUIRE(test_sink->lines()[7] == "****************** Backtrace End ********************"); +} diff --git a/Lumos/External/spdlog/tests/test_bin_to_hex.cpp b/Lumos/External/spdlog/tests/test_bin_to_hex.cpp new file mode 100644 index 000000000..3c50c74a9 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_bin_to_hex.cpp @@ -0,0 +1,93 @@ +#include "includes.h" +#include "test_sink.h" +#include "spdlog/fmt/bin_to_hex.h" + +TEST_CASE("to_hex", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0xc, 0xff, 0xff}; + oss_logger.info("{}", spdlog::to_hex(v)); + + auto output = oss.str(); + REQUIRE(ends_with(output, "0000: 09 0a 0b 0c ff ff" + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_upper", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0xc, 0xff, 0xff}; + oss_logger.info("{:X}", spdlog::to_hex(v)); + + auto output = oss.str(); + REQUIRE(ends_with(output, "0000: 09 0A 0B 0C FF FF" + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_no_delimiter", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0xc, 0xff, 0xff}; + oss_logger.info("{:sX}", spdlog::to_hex(v)); + + auto output = oss.str(); + REQUIRE(ends_with(output, "0000: 090A0B0CFFFF" + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_show_ascii", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff}; + oss_logger.info("{:Xsa}", spdlog::to_hex(v, 8)); + + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF ...A.K.." + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_different_size_per_line", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff}; + + oss_logger.info("{:Xsa}", spdlog::to_hex(v, 10)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF ...A.K.." + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xs}", spdlog::to_hex(v, 10)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xsa}", spdlog::to_hex(v, 6)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B ...A.K" + std::string(spdlog::details::os::default_eol) + "0006: FFFF .." + + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xs}", spdlog::to_hex(v, 6)); + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4B" + std::string(spdlog::details::os::default_eol) + "0006: FFFF" + + std::string(spdlog::details::os::default_eol))); +} + +TEST_CASE("to_hex_no_ascii", "[to_hex]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("oss", oss_sink); + + std::vector v{9, 0xa, 0xb, 0x41, 0xc, 0x4b, 0xff, 0xff}; + oss_logger.info("{:Xs}", spdlog::to_hex(v, 8)); + + REQUIRE(ends_with(oss.str(), "0000: 090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol))); + + oss_logger.info("{:Xsna}", spdlog::to_hex(v, 8)); + + REQUIRE(ends_with(oss.str(), "090A0B410C4BFFFF" + std::string(spdlog::details::os::default_eol))); +} diff --git a/Lumos/External/spdlog/tests/test_cfg.cpp b/Lumos/External/spdlog/tests/test_cfg.cpp new file mode 100644 index 000000000..11aefa208 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_cfg.cpp @@ -0,0 +1,183 @@ + +#include "includes.h" +#include "test_sink.h" + +#include +#include + +using spdlog::cfg::load_argv_levels; +using spdlog::cfg::load_env_levels; +using spdlog::sinks::test_sink_st; + +TEST_CASE("env", "[cfg]") +{ + spdlog::drop("l1"); + auto l1 = spdlog::create("l1"); +#ifdef CATCH_PLATFORM_WINDOWS + _putenv_s("SPDLOG_LEVEL", "l1=warn"); +#else + setenv("SPDLOG_LEVEL", "l1=warn", 1); +#endif + load_env_levels(); + REQUIRE(l1->level() == spdlog::level::warn); + spdlog::set_default_logger(spdlog::create("cfg-default")); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("argv1", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("argv2", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=warn,trace"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); +} + +TEST_CASE("argv3", "[cfg]") +{ + spdlog::set_level(spdlog::level::trace); + + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=junk_name=warn"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::trace); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); +} + +TEST_CASE("argv4", "[cfg]") +{ + spdlog::set_level(spdlog::level::info); + spdlog::drop("l1"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=junk"}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::info); +} + +TEST_CASE("argv5", "[cfg]") +{ + spdlog::set_level(spdlog::level::info); + spdlog::drop("l1"); + const char *argv[] = {"ignore", "ignore", "SPDLOG_LEVEL=l1=warn,trace"}; + load_argv_levels(3, argv); + auto l1 = spdlog::create("l1"); + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::trace); + spdlog::set_level(spdlog::level::info); +} + +TEST_CASE("argv6", "[cfg]") +{ + spdlog::set_level(spdlog::level::err); + const char *argv[] = {""}; + load_argv_levels(1, argv); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::err); + spdlog::set_level(spdlog::level::info); +} + +TEST_CASE("argv7", "[cfg]") +{ + spdlog::set_level(spdlog::level::err); + const char *argv[] = {""}; + load_argv_levels(0, argv); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::err); + spdlog::set_level(spdlog::level::info); +} + +TEST_CASE("level-not-set-test1", "[cfg]") +{ + spdlog::drop("l1"); + const char *argv[] = {"ignore", ""}; + load_argv_levels(2, argv); + auto l1 = spdlog::create("l1"); + l1->set_level(spdlog::level::trace); + REQUIRE(l1->level() == spdlog::level::trace); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("level-not-set-test2", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=trace"}; + + auto l1 = spdlog::create("l1"); + l1->set_level(spdlog::level::warn); + auto l2 = spdlog::create("l2"); + l2->set_level(spdlog::level::warn); + + load_argv_levels(2, argv); + + REQUIRE(l1->level() == spdlog::level::trace); + REQUIRE(l2->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("level-not-set-test3", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=trace"}; + + load_argv_levels(2, argv); + + auto l1 = spdlog::create("l1"); + auto l2 = spdlog::create("l2"); + + REQUIRE(l1->level() == spdlog::level::trace); + REQUIRE(l2->level() == spdlog::level::info); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} + +TEST_CASE("level-not-set-test4", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=trace,warn"}; + + load_argv_levels(2, argv); + + auto l1 = spdlog::create("l1"); + auto l2 = spdlog::create("l2"); + + REQUIRE(l1->level() == spdlog::level::trace); + REQUIRE(l2->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::warn); +} + +TEST_CASE("level-not-set-test5", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=l1=junk,warn"}; + + load_argv_levels(2, argv); + + auto l1 = spdlog::create("l1"); + auto l2 = spdlog::create("l2"); + + REQUIRE(l1->level() == spdlog::level::warn); + REQUIRE(l2->level() == spdlog::level::warn); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::warn); +} + +TEST_CASE("restore-to-default", "[cfg]") +{ + spdlog::drop("l1"); + spdlog::drop("l2"); + const char *argv[] = {"ignore", "SPDLOG_LEVEL=info"}; + load_argv_levels(2, argv); + REQUIRE(spdlog::default_logger()->level() == spdlog::level::info); +} diff --git a/Lumos/External/spdlog/tests/test_create_dir.cpp b/Lumos/External/spdlog/tests/test_create_dir.cpp new file mode 100644 index 000000000..f17126bc3 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_create_dir.cpp @@ -0,0 +1,75 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" + +using spdlog::details::os::create_dir; +using spdlog::details::os::path_exists; + +bool try_create_dir(const spdlog::filename_t &path, const spdlog::filename_t &normalized_path) +{ + auto rv = create_dir(path); + REQUIRE(rv == true); + return path_exists(normalized_path); +} + +TEST_CASE("create_dir", "[create_dir]") +{ + prepare_logdir(); + + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/dir1/dir1"), SPDLOG_FILENAME_T("test_logs/dir1/dir1"))); + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/dir1/dir1"), SPDLOG_FILENAME_T("test_logs/dir1/dir1"))); // test existing + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/dir1///dir2//"), SPDLOG_FILENAME_T("test_logs/dir1/dir2"))); + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("./test_logs/dir1/dir3"), SPDLOG_FILENAME_T("test_logs/dir1/dir3"))); + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs/../test_logs/dir1/dir4"), SPDLOG_FILENAME_T("test_logs/dir1/dir4"))); + +#ifdef WIN32 + // test backslash folder separator + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs\\dir1\\dir222"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir222"))); + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs\\dir1\\dir223\\"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir223\\"))); + REQUIRE( + try_create_dir(SPDLOG_FILENAME_T(".\\test_logs\\dir1\\dir2\\dir99\\..\\dir23"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir2\\dir23"))); + REQUIRE(try_create_dir(SPDLOG_FILENAME_T("test_logs\\..\\test_logs\\dir1\\dir5"), SPDLOG_FILENAME_T("test_logs\\dir1\\dir5"))); +#endif +} + +TEST_CASE("create_invalid_dir", "[create_dir]") +{ + REQUIRE(create_dir(SPDLOG_FILENAME_T("")) == false); + REQUIRE(create_dir(spdlog::filename_t{}) == false); +#ifdef __linux__ + REQUIRE(create_dir("/proc/spdlog-utest") == false); +#endif +} + +TEST_CASE("dir_name", "[create_dir]") +{ + using spdlog::details::os::dir_name; + REQUIRE(dir_name(SPDLOG_FILENAME_T("")).empty()); + REQUIRE(dir_name(SPDLOG_FILENAME_T("dir")).empty()); + +#ifdef WIN32 + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\)")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\\\)")) == SPDLOG_FILENAME_T(R"(dir\\)")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file)")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir/file)")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file.txt)")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir/file)")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(dir\file.txt\)")) == SPDLOG_FILENAME_T(R"(dir\file.txt)")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\dir)")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(\\dir\file.txt)")) == SPDLOG_FILENAME_T(R"(\\dir)")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(..\file.txt)")) == SPDLOG_FILENAME_T("..")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(.\file.txt)")) == SPDLOG_FILENAME_T(".")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(c:\\a\b\c\d\file.txt)")) == SPDLOG_FILENAME_T(R"(c:\\a\b\c\d)")); + REQUIRE(dir_name(SPDLOG_FILENAME_T(R"(c://a/b/c/d/file.txt)")) == SPDLOG_FILENAME_T(R"(c://a/b/c/d)")); +#endif + REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("dir///")) == SPDLOG_FILENAME_T("dir//")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file.txt")) == SPDLOG_FILENAME_T("dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("dir/file.txt/")) == SPDLOG_FILENAME_T("dir/file.txt")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("/dir/file.txt")) == SPDLOG_FILENAME_T("/dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("//dir/file.txt")) == SPDLOG_FILENAME_T("//dir")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("../file.txt")) == SPDLOG_FILENAME_T("..")); + REQUIRE(dir_name(SPDLOG_FILENAME_T("./file.txt")) == SPDLOG_FILENAME_T(".")); +} diff --git a/Lumos/External/spdlog/tests/test_custom_callbacks.cpp b/Lumos/External/spdlog/tests/test_custom_callbacks.cpp new file mode 100644 index 000000000..78babd790 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_custom_callbacks.cpp @@ -0,0 +1,34 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" +#include "test_sink.h" +#include "spdlog/sinks/callback_sink.h" +#include "spdlog/async.h" +#include "spdlog/common.h" + +TEST_CASE("custom_callback_logger", "[custom_callback_logger]") +{ + std::vector lines; + spdlog::pattern_formatter formatter; + auto callback_logger = std::make_shared([&](const spdlog::details::log_msg &msg) { + spdlog::memory_buf_t formatted; + formatter.format(msg, formatted); + auto eol_len = strlen(spdlog::details::os::default_eol); + lines.emplace_back(formatted.begin(), formatted.end() - eol_len); + }); + std::shared_ptr test_sink(new spdlog::sinks::test_sink_st); + + spdlog::logger logger("test-callback", {callback_logger, test_sink}); + + logger.info("test message 1"); + logger.info("test message 2"); + logger.info("test message 3"); + + std::vector ref_lines = test_sink->lines(); + + REQUIRE(lines[0] == ref_lines[0]); + REQUIRE(lines[1] == ref_lines[1]); + REQUIRE(lines[2] == ref_lines[2]); + spdlog::drop_all(); +} diff --git a/Lumos/External/spdlog/tests/test_daily_logger.cpp b/Lumos/External/spdlog/tests/test_daily_logger.cpp new file mode 100644 index 000000000..82f289416 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_daily_logger.cpp @@ -0,0 +1,183 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" + +#ifdef SPDLOG_USE_STD_FORMAT +using filename_memory_buf_t = std::basic_string; +#else +using filename_memory_buf_t = fmt::basic_memory_buffer; +#endif + +#ifdef SPDLOG_WCHAR_FILENAMES +std::string filename_buf_to_utf8string(const filename_memory_buf_t &w) +{ + spdlog::memory_buf_t buf; + spdlog::details::os::wstr_to_utf8buf(spdlog::wstring_view_t(w.data(), w.size()), buf); + return SPDLOG_BUF_TO_STRING(buf); +} +#else +std::string filename_buf_to_utf8string(const filename_memory_buf_t &w) +{ + return SPDLOG_BUF_TO_STRING(w); +} +#endif + +TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]") +{ + using sink_type = spdlog::sinks::daily_file_sink; + + prepare_logdir(); + + // calculate filename (time based) + spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly"); + std::tm tm = spdlog::details::os::localtime(); + filename_memory_buf_t w; + spdlog::fmt_lib::format_to( + std::back_inserter(w), SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + auto logger = spdlog::create("logger", basename, 0, 0); + for (int i = 0; i < 10; ++i) + { + + logger->info("Test message {}", i); + } + logger->flush(); + + require_message_count(filename_buf_to_utf8string(w), 10); +} + +struct custom_daily_file_name_calculator +{ + static spdlog::filename_t calc_filename(const spdlog::filename_t &basename, const tm &now_tm) + { + filename_memory_buf_t w; + spdlog::fmt_lib::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, now_tm.tm_year + 1900, + now_tm.tm_mon + 1, now_tm.tm_mday); + + return SPDLOG_BUF_TO_STRING(w); + } +}; + +TEST_CASE("daily_logger with custom calculator", "[daily_logger]") +{ + using sink_type = spdlog::sinks::daily_file_sink; + + prepare_logdir(); + + // calculate filename (time based) + spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly"); + std::tm tm = spdlog::details::os::localtime(); + filename_memory_buf_t w; + spdlog::fmt_lib::format_to( + std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + auto logger = spdlog::create("logger", basename, 0, 0); + for (int i = 0; i < 10; ++i) + { + logger->info("Test message {}", i); + } + + logger->flush(); + + require_message_count(filename_buf_to_utf8string(w), 10); +} + +/* + * File name calculations + */ + +TEST_CASE("rotating_file_sink::calc_filename1", "[rotating_file_sink]") +{ + auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 3); + REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3.txt")); +} + +TEST_CASE("rotating_file_sink::calc_filename2", "[rotating_file_sink]") +{ + auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated"), 3); + REQUIRE(filename == SPDLOG_FILENAME_T("rotated.3")); +} + +TEST_CASE("rotating_file_sink::calc_filename3", "[rotating_file_sink]") +{ + auto filename = spdlog::sinks::rotating_file_sink_st::calc_filename(SPDLOG_FILENAME_T("rotated.txt"), 0); + REQUIRE(filename == SPDLOG_FILENAME_T("rotated.txt")); +} + +// regex supported only from gcc 4.9 and above +#if defined(_MSC_VER) || !(__GNUC__ <= 4 && __GNUC_MINOR__ < 9) + +# include + +TEST_CASE("daily_file_sink::daily_filename_calculator", "[daily_file_sink]") +{ + // daily_YYYY-MM-DD_hh-mm.txt + auto filename = + spdlog::sinks::daily_filename_calculator::calc_filename(SPDLOG_FILENAME_T("daily.txt"), spdlog::details::os::localtime()); + // date regex based on https://www.regular-expressions.info/dates.html + std::basic_regex re( + SPDLOG_FILENAME_T(R"(^daily_(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\.txt$)")); + std::match_results match; + REQUIRE(std::regex_match(filename, match, re)); +} +#endif + +TEST_CASE("daily_file_sink::daily_filename_format_calculator", "[daily_file_sink]") +{ + std::tm tm = spdlog::details::os::localtime(); + // example-YYYY-MM-DD.log + auto filename = spdlog::sinks::daily_filename_format_calculator::calc_filename(SPDLOG_FILENAME_T("example-%Y-%m-%d.log"), tm); + + REQUIRE(filename == + spdlog::fmt_lib::format(SPDLOG_FILENAME_T("example-{:04d}-{:02d}-{:02d}.log"), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday)); +} + +/* Test removal of old files */ +static spdlog::details::log_msg create_msg(std::chrono::seconds offset) +{ + using spdlog::log_clock; + spdlog::details::log_msg msg{"test", spdlog::level::info, "Hello Message"}; + msg.time = log_clock::now() + offset; + return msg; +} + +static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_files) +{ + using spdlog::log_clock; + using spdlog::details::log_msg; + using spdlog::sinks::daily_file_sink_st; + + prepare_logdir(); + + spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_rotate.txt"); + daily_file_sink_st sink{basename, 2, 30, true, max_days}; + + // simulate messages with 24 intervals + + for (int i = 0; i < days_to_run; i++) + { + auto offset = std::chrono::seconds{24 * 3600 * i}; + sink.log(create_msg(offset)); + } + + REQUIRE(count_files("test_logs") == static_cast(expected_n_files)); +} + +TEST_CASE("daily_logger rotate", "[daily_file_sink]") +{ + int days_to_run = 1; + test_rotate(days_to_run, 0, 1); + test_rotate(days_to_run, 1, 1); + test_rotate(days_to_run, 3, 1); + test_rotate(days_to_run, 10, 1); + + days_to_run = 10; + test_rotate(days_to_run, 0, 10); + test_rotate(days_to_run, 1, 1); + test_rotate(days_to_run, 3, 3); + test_rotate(days_to_run, 9, 9); + test_rotate(days_to_run, 10, 10); + test_rotate(days_to_run, 11, 10); + test_rotate(days_to_run, 20, 10); +} diff --git a/Lumos/External/spdlog/tests/test_dup_filter.cpp b/Lumos/External/spdlog/tests/test_dup_filter.cpp new file mode 100644 index 000000000..8ae2ee60a --- /dev/null +++ b/Lumos/External/spdlog/tests/test_dup_filter.cpp @@ -0,0 +1,90 @@ +#include "includes.h" +#include "spdlog/sinks/dup_filter_sink.h" +#include "test_sink.h" + +TEST_CASE("dup_filter_test1", "[dup_filter_sink]") +{ + using spdlog::sinks::dup_filter_sink_st; + using spdlog::sinks::test_sink_mt; + + dup_filter_sink_st dup_sink{std::chrono::seconds{5}}; + auto test_sink = std::make_shared(); + dup_sink.add_sink(test_sink); + + for (int i = 0; i < 10; i++) + { + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"}); + } + + REQUIRE(test_sink->msg_counter() == 1); +} + +TEST_CASE("dup_filter_test2", "[dup_filter_sink]") +{ + using spdlog::sinks::dup_filter_sink_st; + using spdlog::sinks::test_sink_mt; + + dup_filter_sink_st dup_sink{std::chrono::seconds{0}}; + auto test_sink = std::make_shared(); + dup_sink.add_sink(test_sink); + + for (int i = 0; i < 10; i++) + { + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"}); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + REQUIRE(test_sink->msg_counter() == 10); +} + +TEST_CASE("dup_filter_test3", "[dup_filter_sink]") +{ + using spdlog::sinks::dup_filter_sink_st; + using spdlog::sinks::test_sink_mt; + + dup_filter_sink_st dup_sink{std::chrono::seconds{1}}; + auto test_sink = std::make_shared(); + dup_sink.add_sink(test_sink); + + for (int i = 0; i < 10; i++) + { + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"}); + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message2"}); + } + + REQUIRE(test_sink->msg_counter() == 20); +} + +TEST_CASE("dup_filter_test4", "[dup_filter_sink]") +{ + using spdlog::sinks::dup_filter_sink_mt; + using spdlog::sinks::test_sink_mt; + + dup_filter_sink_mt dup_sink{std::chrono::milliseconds{10}}; + auto test_sink = std::make_shared(); + dup_sink.add_sink(test_sink); + + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message"}); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message"}); + REQUIRE(test_sink->msg_counter() == 2); +} + +TEST_CASE("dup_filter_test5", "[dup_filter_sink]") +{ + using spdlog::sinks::dup_filter_sink_mt; + using spdlog::sinks::test_sink_mt; + + dup_filter_sink_mt dup_sink{std::chrono::seconds{5}}; + auto test_sink = std::make_shared(); + test_sink->set_pattern("%v"); + dup_sink.add_sink(test_sink); + + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"}); + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"}); + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message1"}); + dup_sink.log(spdlog::details::log_msg{"test", spdlog::level::info, "message2"}); + + REQUIRE(test_sink->msg_counter() == 3); // skip 2 messages but log the "skipped.." message before message2 + REQUIRE(test_sink->lines()[1] == "Skipped 2 duplicate messages.."); +} diff --git a/Lumos/External/spdlog/tests/test_errors.cpp b/Lumos/External/spdlog/tests/test_errors.cpp new file mode 100644 index 000000000..780324822 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_errors.cpp @@ -0,0 +1,124 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" + +#include + +#define SIMPLE_LOG "test_logs/simple_log.txt" +#define SIMPLE_ASYNC_LOG "test_logs/simple_async_log.txt" + +class failing_sink : public spdlog::sinks::base_sink +{ +protected: + void sink_it_(const spdlog::details::log_msg &) final + { + throw std::runtime_error("some error happened during log"); + } + + void flush_() final + { + throw std::runtime_error("some error happened during flush"); + } +}; +struct custom_ex +{}; + +#if !defined(SPDLOG_USE_STD_FORMAT) // std formt doesn't fully support tuntime strings +TEST_CASE("default_error_handler", "[errors]") +{ + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); + + auto logger = spdlog::create("test-error", filename, true); + logger->set_pattern("%v"); + logger->info(SPDLOG_FMT_RUNTIME("Test message {} {}"), 1); + logger->info("Test message {}", 2); + logger->flush(); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol)); + REQUIRE(count_lines(SIMPLE_LOG) == 1); +} + +TEST_CASE("custom_error_handler", "[errors]") +{ + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); + auto logger = spdlog::create("logger", filename, true); + logger->flush_on(spdlog::level::info); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + logger->info("Good message #1"); + + REQUIRE_THROWS_AS(logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"), custom_ex); + logger->info("Good message #2"); + require_message_count(SIMPLE_LOG, 2); +} +#endif + +TEST_CASE("default_error_handler2", "[errors]") +{ + spdlog::drop_all(); + auto logger = spdlog::create("failed_logger"); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + REQUIRE_THROWS_AS(logger->info("Some message"), custom_ex); +} + +TEST_CASE("flush_error_handler", "[errors]") +{ + spdlog::drop_all(); + auto logger = spdlog::create("failed_logger"); + logger->set_error_handler([=](const std::string &) { throw custom_ex(); }); + REQUIRE_THROWS_AS(logger->flush(), custom_ex); +} + +#if !defined(SPDLOG_USE_STD_FORMAT) +TEST_CASE("async_error_handler", "[errors]") +{ + prepare_logdir(); + std::string err_msg("log failed with some msg"); + + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_ASYNC_LOG); + { + spdlog::init_thread_pool(128, 1); + auto logger = spdlog::create_async("logger", filename, true); + logger->set_error_handler([=](const std::string &) { + std::ofstream ofs("test_logs/custom_err.txt"); + if (!ofs) + { + throw std::runtime_error("Failed open test_logs/custom_err.txt"); + } + ofs << err_msg; + }); + logger->info("Good message #1"); + logger->info(SPDLOG_FMT_RUNTIME("Bad format msg {} {}"), "xxx"); + logger->info("Good message #2"); + spdlog::drop("logger"); // force logger to drain the queue and shutdown + } + spdlog::init_thread_pool(128, 1); + require_message_count(SIMPLE_ASYNC_LOG, 2); + REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg); +} +#endif + +// Make sure async error handler is executed +TEST_CASE("async_error_handler2", "[errors]") +{ + prepare_logdir(); + std::string err_msg("This is async handler error message"); + { + spdlog::details::os::create_dir(SPDLOG_FILENAME_T("test_logs")); + spdlog::init_thread_pool(128, 1); + auto logger = spdlog::create_async("failed_logger"); + logger->set_error_handler([=](const std::string &) { + std::ofstream ofs("test_logs/custom_err2.txt"); + if (!ofs) + throw std::runtime_error("Failed open test_logs/custom_err2.txt"); + ofs << err_msg; + }); + logger->info("Hello failure"); + spdlog::drop("failed_logger"); // force logger to drain the queue and shutdown + } + + spdlog::init_thread_pool(128, 1); + REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg); +} diff --git a/Lumos/External/spdlog/tests/test_eventlog.cpp b/Lumos/External/spdlog/tests/test_eventlog.cpp new file mode 100644 index 000000000..5253c5a7e --- /dev/null +++ b/Lumos/External/spdlog/tests/test_eventlog.cpp @@ -0,0 +1,71 @@ +#if _WIN32 + +# include "includes.h" +# include "test_sink.h" + +# include "spdlog/sinks/win_eventlog_sink.h" + +static const LPCSTR TEST_SOURCE = "spdlog_test"; + +static void test_single_print(std::function do_log, std::string const &expected_contents, WORD expected_ev_type) +{ + using namespace std::chrono; + do_log(expected_contents); + const auto expected_time_generated = duration_cast(system_clock::now().time_since_epoch()).count(); + + struct handle_t + { + HANDLE handle_; + + ~handle_t() + { + if (handle_) + { + REQUIRE(CloseEventLog(handle_)); + } + } + } event_log{::OpenEventLogA(nullptr, TEST_SOURCE)}; + + REQUIRE(event_log.handle_); + + DWORD read_bytes{}, size_needed{}; + auto ok = ::ReadEventLogA( + event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, &read_bytes, 0, &read_bytes, &size_needed); + REQUIRE(!ok); + REQUIRE(::GetLastError() == ERROR_INSUFFICIENT_BUFFER); + + std::vector record_buffer(size_needed); + PEVENTLOGRECORD record = (PEVENTLOGRECORD)record_buffer.data(); + + ok = ::ReadEventLogA( + event_log.handle_, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, record, size_needed, &read_bytes, &size_needed); + REQUIRE(ok); + + REQUIRE(record->NumStrings == 1); + REQUIRE(record->EventType == expected_ev_type); + REQUIRE((expected_time_generated - record->TimeGenerated) <= 3u); + + std::string message_in_log(((char *)record + record->StringOffset)); + REQUIRE(message_in_log == expected_contents + spdlog::details::os::default_eol); +} + +TEST_CASE("eventlog", "[eventlog]") +{ + using namespace spdlog; + + auto test_sink = std::make_shared(TEST_SOURCE); + + spdlog::logger test_logger("eventlog", test_sink); + test_logger.set_level(level::trace); + + test_sink->set_pattern("%v"); + + test_single_print([&test_logger](std::string const &msg) { test_logger.trace(msg); }, "my trace message", EVENTLOG_SUCCESS); + test_single_print([&test_logger](std::string const &msg) { test_logger.debug(msg); }, "my debug message", EVENTLOG_SUCCESS); + test_single_print([&test_logger](std::string const &msg) { test_logger.info(msg); }, "my info message", EVENTLOG_INFORMATION_TYPE); + test_single_print([&test_logger](std::string const &msg) { test_logger.warn(msg); }, "my warn message", EVENTLOG_WARNING_TYPE); + test_single_print([&test_logger](std::string const &msg) { test_logger.error(msg); }, "my error message", EVENTLOG_ERROR_TYPE); + test_single_print([&test_logger](std::string const &msg) { test_logger.critical(msg); }, "my critical message", EVENTLOG_ERROR_TYPE); +} + +#endif //_WIN32 diff --git a/Lumos/External/spdlog/tests/test_file_helper.cpp b/Lumos/External/spdlog/tests/test_file_helper.cpp new file mode 100644 index 000000000..dd3ca4f8a --- /dev/null +++ b/Lumos/External/spdlog/tests/test_file_helper.cpp @@ -0,0 +1,168 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" + +#define TEST_FILENAME "test_logs/file_helper_test.txt" + +using spdlog::details::file_helper; + +static void write_with_helper(file_helper &helper, size_t howmany) +{ + spdlog::memory_buf_t formatted; + spdlog::fmt_lib::format_to(std::back_inserter(formatted), "{}", std::string(howmany, '1')); + helper.write(formatted); + helper.flush(); +} + +TEST_CASE("file_helper_filename", "[file_helper::filename()]") +{ + prepare_logdir(); + + file_helper helper; + spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); + helper.open(target_filename); + REQUIRE(helper.filename() == target_filename); +} + +TEST_CASE("file_helper_size", "[file_helper::size()]") +{ + prepare_logdir(); + spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); + size_t expected_size = 123; + { + file_helper helper; + helper.open(target_filename); + write_with_helper(helper, expected_size); + REQUIRE(static_cast(helper.size()) == expected_size); + } + REQUIRE(get_filesize(TEST_FILENAME) == expected_size); +} + +TEST_CASE("file_helper_reopen", "[file_helper::reopen()]") +{ + prepare_logdir(); + spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); + file_helper helper; + helper.open(target_filename); + write_with_helper(helper, 12); + REQUIRE(helper.size() == 12); + helper.reopen(true); + REQUIRE(helper.size() == 0); +} + +TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]") +{ + prepare_logdir(); + spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); + size_t expected_size = 14; + file_helper helper; + helper.open(target_filename); + write_with_helper(helper, expected_size); + REQUIRE(helper.size() == expected_size); + helper.reopen(false); + REQUIRE(helper.size() == expected_size); +} + +static void test_split_ext(const spdlog::filename_t::value_type *fname, const spdlog::filename_t::value_type *expect_base, + const spdlog::filename_t::value_type *expect_ext) +{ + spdlog::filename_t filename(fname); + spdlog::filename_t expected_base(expect_base); + spdlog::filename_t expected_ext(expect_ext); + + spdlog::filename_t basename; + spdlog::filename_t ext; + std::tie(basename, ext) = file_helper::split_by_extension(filename); + REQUIRE(basename == expected_base); + REQUIRE(ext == expected_ext); +} + +TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]") +{ + test_split_ext(SPDLOG_FILENAME_T("mylog.txt"), SPDLOG_FILENAME_T("mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T(".mylog.txt"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("../mylog.txt"), SPDLOG_FILENAME_T("../mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T(".././mylog.txt"), SPDLOG_FILENAME_T(".././mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("/mylog.txt"), SPDLOG_FILENAME_T("/mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T("//mylog.txt"), SPDLOG_FILENAME_T("//mylog"), SPDLOG_FILENAME_T(".txt")); + test_split_ext(SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T("")); + test_split_ext(SPDLOG_FILENAME_T("..txt"), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(".txt")); +} + +TEST_CASE("file_event_handlers", "[file_helper]") +{ + enum class flags + { + before_open, + after_open, + before_close, + after_close + }; + prepare_logdir(); + + spdlog::filename_t test_filename = SPDLOG_FILENAME_T(TEST_FILENAME); + // define event handles that update vector of flags when called + std::vector events; + spdlog::file_event_handlers handlers; + handlers.before_open = [&](spdlog::filename_t filename) { + REQUIRE(filename == test_filename); + events.push_back(flags::before_open); + }; + handlers.after_open = [&](spdlog::filename_t filename, std::FILE *fstream) { + REQUIRE(filename == test_filename); + REQUIRE(fstream); + fputs("after_open\n", fstream); + events.push_back(flags::after_open); + }; + handlers.before_close = [&](spdlog::filename_t filename, std::FILE *fstream) { + REQUIRE(filename == test_filename); + REQUIRE(fstream); + fputs("before_close\n", fstream); + events.push_back(flags::before_close); + }; + handlers.after_close = [&](spdlog::filename_t filename) { + REQUIRE(filename == test_filename); + events.push_back(flags::after_close); + }; + { + spdlog::details::file_helper helper{handlers}; + REQUIRE(events.empty()); + + helper.open(test_filename); + REQUIRE(events == std::vector{flags::before_open, flags::after_open}); + + events.clear(); + helper.close(); + REQUIRE(events == std::vector{flags::before_close, flags::after_close}); + REQUIRE(file_contents(TEST_FILENAME) == "after_open\nbefore_close\n"); + + helper.reopen(true); + events.clear(); + } + // make sure that the file_helper destrcutor calls the close callbacks if needed + REQUIRE(events == std::vector{flags::before_close, flags::after_close}); + REQUIRE(file_contents(TEST_FILENAME) == "after_open\nbefore_close\n"); +} + +TEST_CASE("file_helper_open", "[file_helper]") +{ + prepare_logdir(); + spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME); + file_helper helper; + helper.open(target_filename); + helper.close(); + + target_filename += SPDLOG_FILENAME_T("/invalid"); + REQUIRE_THROWS_AS(helper.open(target_filename), spdlog::spdlog_ex); +} diff --git a/Lumos/External/spdlog/tests/test_file_logging.cpp b/Lumos/External/spdlog/tests/test_file_logging.cpp new file mode 100644 index 000000000..7a7119ad8 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_file_logging.cpp @@ -0,0 +1,109 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" + +#define SIMPLE_LOG "test_logs/simple_log" +#define ROTATING_LOG "test_logs/rotating_log" + +TEST_CASE("simple_file_logger", "[simple_logger]") +{ + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); + + auto logger = spdlog::create("logger", filename); + logger->set_pattern("%v"); + + logger->info("Test message {}", 1); + logger->info("Test message {}", 2); + + logger->flush(); + require_message_count(SIMPLE_LOG, 2); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 1{}Test message 2{}", default_eol, default_eol)); +} + +TEST_CASE("flush_on", "[flush_on]") +{ + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG); + + auto logger = spdlog::create("logger", filename); + logger->set_pattern("%v"); + logger->set_level(spdlog::level::trace); + logger->flush_on(spdlog::level::info); + logger->trace("Should not be flushed"); + REQUIRE(count_lines(SIMPLE_LOG) == 0); + + logger->info("Test message {}", 1); + logger->info("Test message {}", 2); + + require_message_count(SIMPLE_LOG, 3); + using spdlog::details::os::default_eol; + REQUIRE(file_contents(SIMPLE_LOG) == + spdlog::fmt_lib::format("Should not be flushed{}Test message 1{}Test message 2{}", default_eol, default_eol, default_eol)); +} + +TEST_CASE("rotating_file_logger1", "[rotating_logger]") +{ + prepare_logdir(); + size_t max_size = 1024 * 10; + spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); + auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0); + + for (int i = 0; i < 10; ++i) + { + logger->info("Test message {}", i); + } + + logger->flush(); + require_message_count(ROTATING_LOG, 10); +} + +TEST_CASE("rotating_file_logger2", "[rotating_logger]") +{ + prepare_logdir(); + size_t max_size = 1024 * 10; + spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); + + { + // make an initial logger to create the first output file + auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 2, true); + for (int i = 0; i < 10; ++i) + { + logger->info("Test message {}", i); + } + // drop causes the logger destructor to be called, which is required so the + // next logger can rename the first output file. + spdlog::drop(logger->name()); + } + + auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 2, true); + for (int i = 0; i < 10; ++i) + { + logger->info("Test message {}", i); + } + + logger->flush(); + + require_message_count(ROTATING_LOG, 10); + + for (int i = 0; i < 1000; i++) + { + + logger->info("Test message {}", i); + } + + logger->flush(); + REQUIRE(get_filesize(ROTATING_LOG) <= max_size); + REQUIRE(get_filesize(ROTATING_LOG ".1") <= max_size); +} + +// test that passing max_size=0 throws +TEST_CASE("rotating_file_logger3", "[rotating_logger]") +{ + prepare_logdir(); + size_t max_size = 0; + spdlog::filename_t basename = SPDLOG_FILENAME_T(ROTATING_LOG); + REQUIRE_THROWS_AS(spdlog::rotating_logger_mt("logger", basename, max_size, 0), spdlog::spdlog_ex); +} diff --git a/Lumos/External/spdlog/tests/test_fmt_helper.cpp b/Lumos/External/spdlog/tests/test_fmt_helper.cpp new file mode 100644 index 000000000..521419024 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_fmt_helper.cpp @@ -0,0 +1,90 @@ + +#include "includes.h" + +using spdlog::memory_buf_t; +using spdlog::details::to_string_view; + +void test_pad2(int n, const char *expected) +{ + memory_buf_t buf; + spdlog::details::fmt_helper::pad2(n, buf); + + REQUIRE(to_string_view(buf) == expected); +} + +void test_pad3(uint32_t n, const char *expected) +{ + memory_buf_t buf; + spdlog::details::fmt_helper::pad3(n, buf); + + REQUIRE(to_string_view(buf) == expected); +} + +void test_pad6(std::size_t n, const char *expected) +{ + memory_buf_t buf; + spdlog::details::fmt_helper::pad6(n, buf); + + REQUIRE(to_string_view(buf) == expected); +} + +void test_pad9(std::size_t n, const char *expected) +{ + memory_buf_t buf; + spdlog::details::fmt_helper::pad9(n, buf); + + REQUIRE(to_string_view(buf) == expected); +} + +TEST_CASE("pad2", "[fmt_helper]") +{ + test_pad2(0, "00"); + test_pad2(3, "03"); + test_pad2(10, "10"); + test_pad2(23, "23"); + test_pad2(99, "99"); + test_pad2(100, "100"); + test_pad2(123, "123"); + test_pad2(1234, "1234"); + test_pad2(-5, "-5"); +} + +TEST_CASE("pad3", "[fmt_helper]") +{ + test_pad3(0, "000"); + test_pad3(3, "003"); + test_pad3(10, "010"); + test_pad3(23, "023"); + test_pad3(99, "099"); + test_pad3(100, "100"); + test_pad3(123, "123"); + test_pad3(999, "999"); + test_pad3(1000, "1000"); + test_pad3(1234, "1234"); +} + +TEST_CASE("pad6", "[fmt_helper]") +{ + test_pad6(0, "000000"); + test_pad6(3, "000003"); + test_pad6(23, "000023"); + test_pad6(123, "000123"); + test_pad6(1234, "001234"); + test_pad6(12345, "012345"); + test_pad6(123456, "123456"); +} + +TEST_CASE("pad9", "[fmt_helper]") +{ + test_pad9(0, "000000000"); + test_pad9(3, "000000003"); + test_pad9(23, "000000023"); + test_pad9(123, "000000123"); + test_pad9(1234, "000001234"); + test_pad9(12345, "000012345"); + test_pad9(123456, "000123456"); + test_pad9(1234567, "001234567"); + test_pad9(12345678, "012345678"); + test_pad9(123456789, "123456789"); + test_pad9(1234567891, "1234567891"); +} diff --git a/Lumos/External/spdlog/tests/test_macros.cpp b/Lumos/External/spdlog/tests/test_macros.cpp new file mode 100644 index 000000000..36537958b --- /dev/null +++ b/Lumos/External/spdlog/tests/test_macros.cpp @@ -0,0 +1,54 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ + +#include "includes.h" + +#if SPDLOG_ACTIVE_LEVEL != SPDLOG_LEVEL_DEBUG +# error "Invalid SPDLOG_ACTIVE_LEVEL in test. Should be SPDLOG_LEVEL_DEBUG" +#endif + +#define TEST_FILENAME "test_logs/simple_log" + +TEST_CASE("debug and trace w/o format string", "[macros]") +{ + + prepare_logdir(); + spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME); + + auto logger = spdlog::create("logger", filename); + logger->set_pattern("%v"); + logger->set_level(spdlog::level::trace); + + SPDLOG_LOGGER_TRACE(logger, "Test message 1"); + SPDLOG_LOGGER_DEBUG(logger, "Test message 2"); + logger->flush(); + + using spdlog::details::os::default_eol; + REQUIRE(ends_with(file_contents(TEST_FILENAME), spdlog::fmt_lib::format("Test message 2{}", default_eol))); + REQUIRE(count_lines(TEST_FILENAME) == 1); + + auto orig_default_logger = spdlog::default_logger(); + spdlog::set_default_logger(logger); + + SPDLOG_TRACE("Test message 3"); + SPDLOG_DEBUG("Test message {}", 4); + logger->flush(); + + require_message_count(TEST_FILENAME, 2); + REQUIRE(ends_with(file_contents(TEST_FILENAME), spdlog::fmt_lib::format("Test message 4{}", default_eol))); + spdlog::set_default_logger(std::move(orig_default_logger)); +} + +TEST_CASE("disable param evaluation", "[macros]") +{ + SPDLOG_TRACE("Test message {}", throw std::runtime_error("Should not be evaluated")); +} + +TEST_CASE("pass logger pointer", "[macros]") +{ + auto logger = spdlog::create("refmacro"); + auto &ref = *logger; + SPDLOG_LOGGER_TRACE(&ref, "Test message 1"); + SPDLOG_LOGGER_DEBUG(&ref, "Test message 2"); +} diff --git a/Lumos/External/spdlog/tests/test_misc.cpp b/Lumos/External/spdlog/tests/test_misc.cpp new file mode 100644 index 000000000..9f3cb1744 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_misc.cpp @@ -0,0 +1,180 @@ +#include "includes.h" +#include "test_sink.h" + +template +std::string log_info(const T &what, spdlog::level::level_enum logger_level = spdlog::level::info) +{ + + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + + spdlog::logger oss_logger("oss", oss_sink); + oss_logger.set_level(logger_level); + oss_logger.set_pattern("%v"); + oss_logger.info(what); + + return oss.str().substr(0, oss.str().length() - strlen(spdlog::details::os::default_eol)); +} + +TEST_CASE("basic_logging ", "[basic_logging]") +{ + // const char + REQUIRE(log_info("Hello") == "Hello"); + REQUIRE(log_info("").empty()); + + // std::string + REQUIRE(log_info(std::string("Hello")) == "Hello"); + REQUIRE(log_info(std::string()).empty()); + + // Numbers + REQUIRE(log_info(5) == "5"); + REQUIRE(log_info(5.6) == "5.6"); + + // User defined class + // REQUIRE(log_info(some_logged_class("some_val")) == "some_val"); +} + +TEST_CASE("log_levels", "[log_levels]") +{ + REQUIRE(log_info("Hello", spdlog::level::err).empty()); + REQUIRE(log_info("Hello", spdlog::level::critical).empty()); + REQUIRE(log_info("Hello", spdlog::level::info) == "Hello"); + REQUIRE(log_info("Hello", spdlog::level::debug) == "Hello"); + REQUIRE(log_info("Hello", spdlog::level::trace) == "Hello"); +} + +TEST_CASE("level_to_string_view", "[convert_to_string_view") +{ + REQUIRE(spdlog::level::to_string_view(spdlog::level::trace) == "trace"); + REQUIRE(spdlog::level::to_string_view(spdlog::level::debug) == "debug"); + REQUIRE(spdlog::level::to_string_view(spdlog::level::info) == "info"); + REQUIRE(spdlog::level::to_string_view(spdlog::level::warn) == "warning"); + REQUIRE(spdlog::level::to_string_view(spdlog::level::err) == "error"); + REQUIRE(spdlog::level::to_string_view(spdlog::level::critical) == "critical"); + REQUIRE(spdlog::level::to_string_view(spdlog::level::off) == "off"); +} + +TEST_CASE("to_short_c_str", "[convert_to_short_c_str]") +{ + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::trace)) == "T"); + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::debug)) == "D"); + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::info)) == "I"); + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::warn)) == "W"); + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::err)) == "E"); + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::critical)) == "C"); + REQUIRE(std::string(spdlog::level::to_short_c_str(spdlog::level::off)) == "O"); +} + +TEST_CASE("to_level_enum", "[convert_to_level_enum]") +{ + REQUIRE(spdlog::level::from_str("trace") == spdlog::level::trace); + REQUIRE(spdlog::level::from_str("debug") == spdlog::level::debug); + REQUIRE(spdlog::level::from_str("info") == spdlog::level::info); + REQUIRE(spdlog::level::from_str("warning") == spdlog::level::warn); + REQUIRE(spdlog::level::from_str("warn") == spdlog::level::warn); + REQUIRE(spdlog::level::from_str("error") == spdlog::level::err); + REQUIRE(spdlog::level::from_str("critical") == spdlog::level::critical); + REQUIRE(spdlog::level::from_str("off") == spdlog::level::off); + REQUIRE(spdlog::level::from_str("null") == spdlog::level::off); +} + +TEST_CASE("periodic flush", "[periodic_flush]") +{ + using spdlog::sinks::test_sink_mt; + auto logger = spdlog::create("periodic_flush"); + auto test_sink = std::static_pointer_cast(logger->sinks()[0]); + + spdlog::flush_every(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1250)); + REQUIRE(test_sink->flush_counter() == 1); + spdlog::flush_every(std::chrono::seconds(0)); + spdlog::drop_all(); +} + +TEST_CASE("clone-logger", "[clone]") +{ + using spdlog::sinks::test_sink_mt; + auto test_sink = std::make_shared(); + auto logger = std::make_shared("orig", test_sink); + logger->set_pattern("%v"); + auto cloned = logger->clone("clone"); + + REQUIRE(cloned->name() == "clone"); + REQUIRE(logger->sinks() == cloned->sinks()); + REQUIRE(logger->level() == cloned->level()); + REQUIRE(logger->flush_level() == cloned->flush_level()); + logger->info("Some message 1"); + cloned->info("Some message 2"); + + REQUIRE(test_sink->lines().size() == 2); + REQUIRE(test_sink->lines()[0] == "Some message 1"); + REQUIRE(test_sink->lines()[1] == "Some message 2"); + + spdlog::drop_all(); +} + +TEST_CASE("clone async", "[clone]") +{ + using spdlog::sinks::test_sink_st; + spdlog::init_thread_pool(4, 1); + auto test_sink = std::make_shared(); + auto logger = std::make_shared("orig", test_sink, spdlog::thread_pool()); + logger->set_pattern("%v"); + auto cloned = logger->clone("clone"); + + REQUIRE(cloned->name() == "clone"); + REQUIRE(logger->sinks() == cloned->sinks()); + REQUIRE(logger->level() == cloned->level()); + REQUIRE(logger->flush_level() == cloned->flush_level()); + + logger->info("Some message 1"); + cloned->info("Some message 2"); + + spdlog::details::os::sleep_for_millis(100); + + REQUIRE(test_sink->lines().size() == 2); + REQUIRE(test_sink->lines()[0] == "Some message 1"); + REQUIRE(test_sink->lines()[1] == "Some message 2"); + + spdlog::drop_all(); +} + +TEST_CASE("default logger API", "[default logger]") +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + + spdlog::set_default_logger(std::make_shared("oss", oss_sink)); + spdlog::set_pattern("*** %v"); + + spdlog::default_logger()->set_level(spdlog::level::trace); + spdlog::trace("hello trace"); + REQUIRE(oss.str() == "*** hello trace" + std::string(spdlog::details::os::default_eol)); + + oss.str(""); + spdlog::debug("hello debug"); + REQUIRE(oss.str() == "*** hello debug" + std::string(spdlog::details::os::default_eol)); + + oss.str(""); + spdlog::info("Hello"); + REQUIRE(oss.str() == "*** Hello" + std::string(spdlog::details::os::default_eol)); + + oss.str(""); + spdlog::warn("Hello again {}", 2); + REQUIRE(oss.str() == "*** Hello again 2" + std::string(spdlog::details::os::default_eol)); + + oss.str(""); + spdlog::error(123); + REQUIRE(oss.str() == "*** 123" + std::string(spdlog::details::os::default_eol)); + + oss.str(""); + spdlog::critical(std::string("some string")); + REQUIRE(oss.str() == "*** some string" + std::string(spdlog::details::os::default_eol)); + + oss.str(""); + spdlog::set_level(spdlog::level::info); + spdlog::debug("should not be logged"); + REQUIRE(oss.str().empty()); + spdlog::drop_all(); + spdlog::set_pattern("%v"); +} diff --git a/Lumos/External/spdlog/tests/test_mpmc_q.cpp b/Lumos/External/spdlog/tests/test_mpmc_q.cpp new file mode 100644 index 000000000..1540dcc89 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_mpmc_q.cpp @@ -0,0 +1,126 @@ +#include "includes.h" + +using std::chrono::milliseconds; +using test_clock = std::chrono::high_resolution_clock; + +static milliseconds millis_from(const test_clock::time_point &tp0) +{ + return std::chrono::duration_cast(test_clock::now() - tp0); +} +TEST_CASE("dequeue-empty-nowait", "[mpmc_blocking_q]") +{ + size_t q_size = 100; + milliseconds tolerance_wait(20); + spdlog::details::mpmc_blocking_queue q(q_size); + int popped_item = 0; + + auto start = test_clock::now(); + auto rv = q.dequeue_for(popped_item, milliseconds::zero()); + auto delta_ms = millis_from(start); + + REQUIRE(rv == false); + INFO("Delta " << delta_ms.count() << " millis"); + REQUIRE(delta_ms <= tolerance_wait); +} + +TEST_CASE("dequeue-empty-wait", "[mpmc_blocking_q]") +{ + + size_t q_size = 100; + milliseconds wait_ms(250); + milliseconds tolerance_wait(250); + + spdlog::details::mpmc_blocking_queue q(q_size); + int popped_item = 0; + auto start = test_clock::now(); + auto rv = q.dequeue_for(popped_item, wait_ms); + auto delta_ms = millis_from(start); + + REQUIRE(rv == false); + + INFO("Delta " << delta_ms.count() << " millis"); + REQUIRE(delta_ms >= wait_ms - tolerance_wait); + REQUIRE(delta_ms <= wait_ms + tolerance_wait); +} + +TEST_CASE("dequeue-full-nowait", "[mpmc_blocking_q]") +{ + spdlog::details::mpmc_blocking_queue q(1); + q.enqueue(42); + + int item = 0; + q.dequeue_for(item, milliseconds::zero()); + REQUIRE(item == 42); +} + +TEST_CASE("dequeue-full-wait", "[mpmc_blocking_q]") +{ + spdlog::details::mpmc_blocking_queue q(1); + q.enqueue(42); + + int item = 0; + q.dequeue(item); + REQUIRE(item == 42); +} + +TEST_CASE("enqueue_nowait", "[mpmc_blocking_q]") +{ + + size_t q_size = 1; + spdlog::details::mpmc_blocking_queue q(q_size); + milliseconds tolerance_wait(10); + + q.enqueue(1); + REQUIRE(q.overrun_counter() == 0); + + auto start = test_clock::now(); + q.enqueue_nowait(2); + auto delta_ms = millis_from(start); + + INFO("Delta " << delta_ms.count() << " millis"); + REQUIRE(delta_ms <= tolerance_wait); + REQUIRE(q.overrun_counter() == 1); +} + +TEST_CASE("bad_queue", "[mpmc_blocking_q]") +{ + size_t q_size = 0; + spdlog::details::mpmc_blocking_queue q(q_size); + q.enqueue_nowait(1); + REQUIRE(q.overrun_counter() == 1); + int i = 0; + REQUIRE(q.dequeue_for(i, milliseconds(0)) == false); +} + +TEST_CASE("empty_queue", "[mpmc_blocking_q]") +{ + size_t q_size = 10; + spdlog::details::mpmc_blocking_queue q(q_size); + int i = 0; + REQUIRE(q.dequeue_for(i, milliseconds(10)) == false); +} + +TEST_CASE("full_queue", "[mpmc_blocking_q]") +{ + size_t q_size = 100; + spdlog::details::mpmc_blocking_queue q(q_size); + for (int i = 0; i < static_cast(q_size); i++) + { + q.enqueue(i + 0); // i+0 to force rvalue and avoid tidy warnings on the same time if we std::move(i) instead + } + + q.enqueue_nowait(123456); + REQUIRE(q.overrun_counter() == 1); + + for (int i = 1; i < static_cast(q_size); i++) + { + int item = -1; + q.dequeue(item); + REQUIRE(item == i); + } + + // last item pushed has overridden the oldest. + int item = -1; + q.dequeue(item); + REQUIRE(item == 123456); +} diff --git a/Lumos/External/spdlog/tests/test_pattern_formatter.cpp b/Lumos/External/spdlog/tests/test_pattern_formatter.cpp new file mode 100644 index 000000000..bafea8842 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_pattern_formatter.cpp @@ -0,0 +1,501 @@ +#include "includes.h" +#include "test_sink.h" + +using spdlog::memory_buf_t; +using spdlog::details::to_string_view; + +// log to str and return it +template +static std::string log_to_str(const std::string &msg, const Args &...args) +{ + std::ostringstream oss; + auto oss_sink = std::make_shared(oss); + spdlog::logger oss_logger("pattern_tester", oss_sink); + oss_logger.set_level(spdlog::level::info); + + oss_logger.set_formatter(std::unique_ptr(new spdlog::pattern_formatter(args...))); + + oss_logger.info(msg); + return oss.str(); +} + +TEST_CASE("custom eol", "[pattern_formatter]") +{ + std::string msg = "Hello custom eol test"; + std::string eol = ";)"; + REQUIRE(log_to_str(msg, "%v", spdlog::pattern_time_type::local, ";)") == msg + eol); +} + +TEST_CASE("empty format", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "", spdlog::pattern_time_type::local, "").empty()); +} + +TEST_CASE("empty format2", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "", spdlog::pattern_time_type::local, "\n") == "\n"); +} + +TEST_CASE("level", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%l] %v", spdlog::pattern_time_type::local, "\n") == "[info] Some message\n"); +} + +TEST_CASE("short level", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%L] %v", spdlog::pattern_time_type::local, "\n") == "[I] Some message\n"); +} + +TEST_CASE("name", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); +} + +TEST_CASE("date MM/DD/YY ", "[pattern_formatter]") +{ + auto now_tm = spdlog::details::os::localtime(); + std::stringstream oss; + oss << std::setfill('0') << std::setw(2) << now_tm.tm_mon + 1 << "/" << std::setw(2) << now_tm.tm_mday << "/" << std::setw(2) + << (now_tm.tm_year + 1900) % 1000 << " Some message\n"; + REQUIRE(log_to_str("Some message", "%D %v", spdlog::pattern_time_type::local, "\n") == oss.str()); +} + +TEST_CASE("color range test1", "[pattern_formatter]") +{ + auto formatter = std::make_shared("%^%v%$", spdlog::pattern_time_type::local, "\n"); + + memory_buf_t buf; + spdlog::fmt_lib::format_to(std::back_inserter(buf), "Hello"); + memory_buf_t formatted; + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, spdlog::string_view_t(buf.data(), buf.size())); + formatter->format(msg, formatted); + REQUIRE(msg.color_range_start == 0); + REQUIRE(msg.color_range_end == 5); + REQUIRE(log_to_str("hello", "%^%v%$", spdlog::pattern_time_type::local, "\n") == "hello\n"); +} + +TEST_CASE("color range test2", "[pattern_formatter]") +{ + auto formatter = std::make_shared("%^%$", spdlog::pattern_time_type::local, "\n"); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, ""); + memory_buf_t formatted; + formatter->format(msg, formatted); + REQUIRE(msg.color_range_start == 0); + REQUIRE(msg.color_range_end == 0); + REQUIRE(log_to_str("", "%^%$", spdlog::pattern_time_type::local, "\n") == "\n"); +} + +TEST_CASE("color range test3", "[pattern_formatter]") +{ + auto formatter = std::make_shared("%^***%$"); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "ignored"); + memory_buf_t formatted; + formatter->format(msg, formatted); + REQUIRE(msg.color_range_start == 0); + REQUIRE(msg.color_range_end == 3); +} + +TEST_CASE("color range test4", "[pattern_formatter]") +{ + auto formatter = std::make_shared("XX%^YYY%$", spdlog::pattern_time_type::local, "\n"); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "ignored"); + + memory_buf_t formatted; + formatter->format(msg, formatted); + REQUIRE(msg.color_range_start == 2); + REQUIRE(msg.color_range_end == 5); + REQUIRE(log_to_str("ignored", "XX%^YYY%$", spdlog::pattern_time_type::local, "\n") == "XXYYY\n"); +} + +TEST_CASE("color range test5", "[pattern_formatter]") +{ + auto formatter = std::make_shared("**%^"); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "ignored"); + memory_buf_t formatted; + formatter->format(msg, formatted); + REQUIRE(msg.color_range_start == 2); + REQUIRE(msg.color_range_end == 0); +} + +TEST_CASE("color range test6", "[pattern_formatter]") +{ + auto formatter = std::make_shared("**%$"); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "ignored"); + memory_buf_t formatted; + formatter->format(msg, formatted); + REQUIRE(msg.color_range_start == 0); + REQUIRE(msg.color_range_end == 2); +} + +// +// Test padding +// + +TEST_CASE("level_left_padded", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n"); + REQUIRE(log_to_str("Some message", "[%8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n"); +} + +TEST_CASE("level_right_padded", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%-8l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-8!l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n"); +} + +TEST_CASE("level_center_padded", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%=8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n"); +} + +TEST_CASE("short level_left_padded", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n"); + REQUIRE(log_to_str("Some message", "[%3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n"); +} + +TEST_CASE("short level_right_padded", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%-3L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-3!L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n"); +} + +TEST_CASE("short level_center_padded", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%=3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n"); +} + +TEST_CASE("left_padded_short", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); +} + +TEST_CASE("right_padded_short", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%-3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%-3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); +} + +TEST_CASE("center_padded_short", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%=3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n"); + REQUIRE(log_to_str("Some message", "[%=3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n"); +} + +TEST_CASE("left_padded_huge", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%-300n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); + + REQUIRE(log_to_str("Some message", "[%-300!n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); +} + +TEST_CASE("left_padded_max", "[pattern_formatter]") +{ + REQUIRE(log_to_str("Some message", "[%-64n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); + + REQUIRE(log_to_str("Some message", "[%-64!n] %v", spdlog::pattern_time_type::local, "\n") == + "[pattern_tester ] Some message\n"); +} + +// Test padding + truncate flag + +TEST_CASE("paddinng_truncate", "[pattern_formatter]") +{ + REQUIRE(log_to_str("123456", "%6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%7!v", spdlog::pattern_time_type::local, "\n") == " 123456\n"); + + REQUIRE(log_to_str("123456", "%-6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%-5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%-7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n"); + + REQUIRE(log_to_str("123456", "%=6!v", spdlog::pattern_time_type::local, "\n") == "123456\n"); + REQUIRE(log_to_str("123456", "%=5!v", spdlog::pattern_time_type::local, "\n") == "12345\n"); + REQUIRE(log_to_str("123456", "%=7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n"); + + REQUIRE(log_to_str("123456", "%0!v", spdlog::pattern_time_type::local, "\n") == "\n"); +} + +TEST_CASE("padding_truncate_funcname", "[pattern_formatter]") +{ + spdlog::sinks::test_sink_st test_sink; + + const char *pattern = "%v [%5!!]"; + auto formatter = std::unique_ptr(new spdlog::pattern_formatter(pattern)); + test_sink.set_formatter(std::move(formatter)); + + spdlog::details::log_msg msg1{spdlog::source_loc{"ignored", 1, "func"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg1); + REQUIRE(test_sink.lines()[0] == "message [ func]"); + + spdlog::details::log_msg msg2{spdlog::source_loc{"ignored", 1, "function"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg2); + REQUIRE(test_sink.lines()[1] == "message [funct]"); +} + +TEST_CASE("padding_funcname", "[pattern_formatter]") +{ + spdlog::sinks::test_sink_st test_sink; + + const char *pattern = "%v [%10!]"; + auto formatter = std::unique_ptr(new spdlog::pattern_formatter(pattern)); + test_sink.set_formatter(std::move(formatter)); + + spdlog::details::log_msg msg1{spdlog::source_loc{"ignored", 1, "func"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg1); + REQUIRE(test_sink.lines()[0] == "message [ func]"); + + spdlog::details::log_msg msg2{spdlog::source_loc{"ignored", 1, "func567890123"}, "test_logger", spdlog::level::info, "message"}; + test_sink.log(msg2); + REQUIRE(test_sink.lines()[1] == "message [func567890123]"); +} + +TEST_CASE("clone-default-formatter", "[pattern_formatter]") +{ + auto formatter_1 = std::make_shared(); + auto formatter_2 = formatter_1->clone(); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "some message"); + + memory_buf_t formatted_1; + memory_buf_t formatted_2; + formatter_1->format(msg, formatted_1); + formatter_2->format(msg, formatted_2); + + REQUIRE(to_string_view(formatted_1) == to_string_view(formatted_2)); +} + +TEST_CASE("clone-default-formatter2", "[pattern_formatter]") +{ + auto formatter_1 = std::make_shared("%+"); + auto formatter_2 = formatter_1->clone(); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "some message"); + + memory_buf_t formatted_1; + memory_buf_t formatted_2; + formatter_1->format(msg, formatted_1); + formatter_2->format(msg, formatted_2); + + REQUIRE(to_string_view(formatted_1) == to_string_view(formatted_2)); +} + +TEST_CASE("clone-formatter", "[pattern_formatter]") +{ + auto formatter_1 = std::make_shared("%D %X [%] [%n] %v"); + auto formatter_2 = formatter_1->clone(); + std::string logger_name = "test"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "some message"); + + memory_buf_t formatted_1; + memory_buf_t formatted_2; + formatter_1->format(msg, formatted_1); + formatter_2->format(msg, formatted_2); + + REQUIRE(to_string_view(formatted_1) == to_string_view(formatted_2)); +} + +TEST_CASE("clone-formatter-2", "[pattern_formatter]") +{ + using spdlog::pattern_time_type; + auto formatter_1 = std::make_shared("%D %X [%] [%n] %v", pattern_time_type::utc, "xxxxxx\n"); + auto formatter_2 = formatter_1->clone(); + std::string logger_name = "test2"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "some message"); + + memory_buf_t formatted_1; + memory_buf_t formatted_2; + formatter_1->format(msg, formatted_1); + formatter_2->format(msg, formatted_2); + + REQUIRE(to_string_view(formatted_1) == to_string_view(formatted_2)); +} + +class custom_test_flag : public spdlog::custom_flag_formatter +{ +public: + explicit custom_test_flag(std::string txt) + : some_txt{std::move(txt)} + {} + + void format(const spdlog::details::log_msg &, const std::tm &tm, spdlog::memory_buf_t &dest) override + { + if (some_txt == "throw_me") + { + throw spdlog::spdlog_ex("custom_flag_exception_test"); + } + else if (some_txt == "time") + { + auto formatted = spdlog::fmt_lib::format("{:d}:{:02d}{:s}", tm.tm_hour % 12, tm.tm_min, tm.tm_hour / 12 ? "PM" : "AM"); + dest.append(formatted.data(), formatted.data() + formatted.size()); + return; + } + some_txt = std::string(padinfo_.width_, ' ') + some_txt; + dest.append(some_txt.data(), some_txt.data() + some_txt.size()); + } + spdlog::details::padding_info get_padding_info() + { + return padinfo_; + } + + std::string some_txt; + + std::unique_ptr clone() const override + { + return spdlog::details::make_unique(some_txt); + } +}; +// test clone with custom flag formatters +TEST_CASE("clone-custom_formatter", "[pattern_formatter]") +{ + auto formatter_1 = std::make_shared(); + formatter_1->add_flag('t', "custom_output").set_pattern("[%n] [%t] %v"); + auto formatter_2 = formatter_1->clone(); + std::string logger_name = "logger-name"; + spdlog::details::log_msg msg(logger_name, spdlog::level::info, "some message"); + + memory_buf_t formatted_1; + memory_buf_t formatted_2; + formatter_1->format(msg, formatted_1); + formatter_2->format(msg, formatted_2); + + auto expected = spdlog::fmt_lib::format("[logger-name] [custom_output] some message{}", spdlog::details::os::default_eol); + + REQUIRE(to_string_view(formatted_1) == expected); + REQUIRE(to_string_view(formatted_2) == expected); +} + +// +// Test source location formatting +// + +#ifdef _WIN32 +static const char *const test_path = "\\a\\b\\c/myfile.cpp"; +#else +static const char *const test_path = "/a/b//myfile.cpp"; +#endif + +TEST_CASE("short filename formatter-1", "[pattern_formatter]") +{ + spdlog::pattern_formatter formatter("%s", spdlog::pattern_time_type::local, ""); + memory_buf_t formatted; + std::string logger_name = "logger-name"; + spdlog::source_loc source_loc{test_path, 123, "some_func()"}; + spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello"); + formatter.format(msg, formatted); + + REQUIRE(to_string_view(formatted) == "myfile.cpp"); +} + +TEST_CASE("short filename formatter-2", "[pattern_formatter]") +{ + spdlog::pattern_formatter formatter("%s:%#", spdlog::pattern_time_type::local, ""); + memory_buf_t formatted; + std::string logger_name = "logger-name"; + spdlog::source_loc source_loc{"myfile.cpp", 123, "some_func()"}; + spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello"); + formatter.format(msg, formatted); + + REQUIRE(to_string_view(formatted) == "myfile.cpp:123"); +} + +TEST_CASE("short filename formatter-3", "[pattern_formatter]") +{ + spdlog::pattern_formatter formatter("%s %v", spdlog::pattern_time_type::local, ""); + memory_buf_t formatted; + std::string logger_name = "logger-name"; + spdlog::source_loc source_loc{"", 123, "some_func()"}; + spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello"); + formatter.format(msg, formatted); + + REQUIRE(to_string_view(formatted) == " Hello"); +} + +TEST_CASE("full filename formatter", "[pattern_formatter]") +{ + spdlog::pattern_formatter formatter("%g", spdlog::pattern_time_type::local, ""); + memory_buf_t formatted; + std::string logger_name = "logger-name"; + spdlog::source_loc source_loc{test_path, 123, "some_func()"}; + spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello"); + formatter.format(msg, formatted); + + REQUIRE(to_string_view(formatted) == test_path); +} + +TEST_CASE("custom flags", "[pattern_formatter]") +{ + auto formatter = std::make_shared(); + formatter->add_flag('t', "custom1").add_flag('u', "custom2").set_pattern("[%n] [%t] [%u] %v"); + + memory_buf_t formatted; + + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + formatter->format(msg, formatted); + auto expected = spdlog::fmt_lib::format("[logger-name] [custom1] [custom2] some message{}", spdlog::details::os::default_eol); + + REQUIRE(to_string_view(formatted) == expected); +} + +TEST_CASE("custom flags-padding", "[pattern_formatter]") +{ + auto formatter = std::make_shared(); + formatter->add_flag('t', "custom1").add_flag('u', "custom2").set_pattern("[%n] [%t] [%5u] %v"); + + memory_buf_t formatted; + + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + formatter->format(msg, formatted); + auto expected = spdlog::fmt_lib::format("[logger-name] [custom1] [ custom2] some message{}", spdlog::details::os::default_eol); + + REQUIRE(to_string_view(formatted) == expected); +} + +TEST_CASE("custom flags-exception", "[pattern_formatter]") +{ + auto formatter = std::make_shared(); + formatter->add_flag('t', "throw_me").add_flag('u', "custom2").set_pattern("[%n] [%t] [%u] %v"); + + memory_buf_t formatted; + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + CHECK_THROWS_AS(formatter->format(msg, formatted), spdlog::spdlog_ex); +} + +TEST_CASE("override need_localtime", "[pattern_formatter]") +{ + auto formatter = std::make_shared(spdlog::pattern_time_type::local, "\n"); + formatter->add_flag('t', "time").set_pattern("%t> %v"); + + { + memory_buf_t formatted; + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + formatter->format(msg, formatted); + REQUIRE(to_string_view(formatted) == "0:00AM> some message\n"); + } + + { + formatter->need_localtime(); + + auto now_tm = spdlog::details::os::localtime(); + std::stringstream oss; + oss << (now_tm.tm_hour % 12) << ":" << std::setfill('0') << std::setw(2) << now_tm.tm_min << (now_tm.tm_hour / 12 ? "PM" : "AM") + << "> some message\n"; + + memory_buf_t formatted; + spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message"); + formatter->format(msg, formatted); + REQUIRE(to_string_view(formatted) == oss.str()); + } +} diff --git a/Lumos/External/spdlog/tests/test_registry.cpp b/Lumos/External/spdlog/tests/test_registry.cpp new file mode 100644 index 000000000..8e632cc64 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_registry.cpp @@ -0,0 +1,116 @@ +#include "includes.h" + +static const char *const tested_logger_name = "null_logger"; +static const char *const tested_logger_name2 = "null_logger2"; + +#ifndef SPDLOG_NO_EXCEPTIONS +TEST_CASE("register_drop", "[registry]") +{ + spdlog::drop_all(); + spdlog::create(tested_logger_name); + REQUIRE(spdlog::get(tested_logger_name) != nullptr); + // Throw if registering existing name + REQUIRE_THROWS_AS(spdlog::create(tested_logger_name), spdlog::spdlog_ex); +} + +TEST_CASE("explicit register", "[registry]") +{ + spdlog::drop_all(); + auto logger = std::make_shared(tested_logger_name, std::make_shared()); + spdlog::register_logger(logger); + REQUIRE(spdlog::get(tested_logger_name) != nullptr); + // Throw if registering existing name + REQUIRE_THROWS_AS(spdlog::create(tested_logger_name), spdlog::spdlog_ex); +} +#endif + +TEST_CASE("apply_all", "[registry]") +{ + spdlog::drop_all(); + auto logger = std::make_shared(tested_logger_name, std::make_shared()); + spdlog::register_logger(logger); + auto logger2 = std::make_shared(tested_logger_name2, std::make_shared()); + spdlog::register_logger(logger2); + + int counter = 0; + spdlog::apply_all([&counter](std::shared_ptr) { counter++; }); + REQUIRE(counter == 2); + + counter = 0; + spdlog::drop(tested_logger_name2); + spdlog::apply_all([&counter](std::shared_ptr l) { + REQUIRE(l->name() == tested_logger_name); + counter++; + }); + REQUIRE(counter == 1); +} + +TEST_CASE("drop", "[registry]") +{ + spdlog::drop_all(); + spdlog::create(tested_logger_name); + spdlog::drop(tested_logger_name); + REQUIRE_FALSE(spdlog::get(tested_logger_name)); +} + +TEST_CASE("drop-default", "[registry]") +{ + spdlog::set_default_logger(spdlog::null_logger_st(tested_logger_name)); + spdlog::drop(tested_logger_name); + REQUIRE_FALSE(spdlog::default_logger()); + REQUIRE_FALSE(spdlog::get(tested_logger_name)); +} + +TEST_CASE("drop_all", "[registry]") +{ + spdlog::drop_all(); + spdlog::create(tested_logger_name); + spdlog::create(tested_logger_name2); + spdlog::drop_all(); + REQUIRE_FALSE(spdlog::get(tested_logger_name)); + REQUIRE_FALSE(spdlog::get(tested_logger_name2)); + REQUIRE_FALSE(spdlog::default_logger()); +} + +TEST_CASE("drop non existing", "[registry]") +{ + spdlog::drop_all(); + spdlog::create(tested_logger_name); + spdlog::drop("some_name"); + REQUIRE_FALSE(spdlog::get("some_name")); + REQUIRE(spdlog::get(tested_logger_name)); + spdlog::drop_all(); +} + +TEST_CASE("default logger", "[registry]") +{ + spdlog::drop_all(); + spdlog::set_default_logger(spdlog::null_logger_st(tested_logger_name)); + REQUIRE(spdlog::get(tested_logger_name) == spdlog::default_logger()); + spdlog::drop_all(); +} + +TEST_CASE("set_default_logger(nullptr)", "[registry]") +{ + spdlog::set_default_logger(nullptr); + REQUIRE_FALSE(spdlog::default_logger()); +} + +TEST_CASE("disable automatic registration", "[registry]") +{ + // set some global parameters + spdlog::level::level_enum log_level = spdlog::level::level_enum::warn; + spdlog::set_level(log_level); + // but disable automatic registration + spdlog::set_automatic_registration(false); + auto logger1 = spdlog::create(tested_logger_name, SPDLOG_FILENAME_T("filename"), 11, 59); + auto logger2 = spdlog::create_async(tested_logger_name2); + // loggers should not be part of the registry + REQUIRE_FALSE(spdlog::get(tested_logger_name)); + REQUIRE_FALSE(spdlog::get(tested_logger_name2)); + // but make sure they are still initialized according to global defaults + REQUIRE(logger1->level() == log_level); + REQUIRE(logger2->level() == log_level); + spdlog::set_level(spdlog::level::info); + spdlog::set_automatic_registration(true); +} diff --git a/Lumos/External/spdlog/tests/test_sink.h b/Lumos/External/spdlog/tests/test_sink.h new file mode 100644 index 000000000..57db65c10 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_sink.h @@ -0,0 +1,79 @@ +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/base_sink.h" +#include "spdlog/fmt/fmt.h" +#include +#include +#include + +namespace spdlog { +namespace sinks { + +template +class test_sink : public base_sink +{ + const size_t lines_to_save = 100; + +public: + size_t msg_counter() + { + std::lock_guard lock(base_sink::mutex_); + return msg_counter_; + } + + size_t flush_counter() + { + std::lock_guard lock(base_sink::mutex_); + return flush_counter_; + } + + void set_delay(std::chrono::milliseconds delay) + { + std::lock_guard lock(base_sink::mutex_); + delay_ = delay; + } + + // return last output without the eol + std::vector lines() + { + std::lock_guard lock(base_sink::mutex_); + return lines_; + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + // save the line without the eol + auto eol_len = strlen(details::os::default_eol); + if (lines_.size() < lines_to_save) + { + lines_.emplace_back(formatted.begin(), formatted.end() - eol_len); + } + msg_counter_++; + std::this_thread::sleep_for(delay_); + } + + void flush_() override + { + flush_counter_++; + } + + size_t msg_counter_{0}; + size_t flush_counter_{0}; + std::chrono::milliseconds delay_{std::chrono::milliseconds::zero()}; + std::vector lines_; +}; + +using test_sink_mt = test_sink; +using test_sink_st = test_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/Lumos/External/spdlog/tests/test_stdout_api.cpp b/Lumos/External/spdlog/tests/test_stdout_api.cpp new file mode 100644 index 000000000..d55223fff --- /dev/null +++ b/Lumos/External/spdlog/tests/test_stdout_api.cpp @@ -0,0 +1,98 @@ +/* + * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE + */ +#include "includes.h" +#include "spdlog/sinks/stdout_sinks.h" +#include "spdlog/sinks/stdout_color_sinks.h" +TEST_CASE("stdout_st", "[stdout]") +{ + auto l = spdlog::stdout_logger_st("test"); + l->set_pattern("%+"); + l->set_level(spdlog::level::trace); + l->trace("Test stdout_st"); + spdlog::drop_all(); +} + +TEST_CASE("stdout_mt", "[stdout]") +{ + auto l = spdlog::stdout_logger_mt("test"); + l->set_pattern("%+"); + l->set_level(spdlog::level::debug); + l->debug("Test stdout_mt"); + spdlog::drop_all(); +} + +TEST_CASE("stderr_st", "[stderr]") +{ + auto l = spdlog::stderr_logger_st("test"); + l->set_pattern("%+"); + l->info("Test stderr_st"); + spdlog::drop_all(); +} + +TEST_CASE("stderr_mt", "[stderr]") +{ + auto l = spdlog::stderr_logger_mt("test"); + l->set_pattern("%+"); + l->info("Test stderr_mt"); + l->warn("Test stderr_mt"); + l->error("Test stderr_mt"); + l->critical("Test stderr_mt"); + spdlog::drop_all(); +} + +// color loggers +TEST_CASE("stdout_color_st", "[stdout]") +{ + auto l = spdlog::stdout_color_st("test"); + l->set_pattern("%+"); + l->info("Test stdout_color_st"); + spdlog::drop_all(); +} + +TEST_CASE("stdout_color_mt", "[stdout]") +{ + auto l = spdlog::stdout_color_mt("test"); + l->set_pattern("%+"); + l->set_level(spdlog::level::trace); + l->trace("Test stdout_color_mt"); + spdlog::drop_all(); +} + +TEST_CASE("stderr_color_st", "[stderr]") +{ + auto l = spdlog::stderr_color_st("test"); + l->set_pattern("%+"); + l->set_level(spdlog::level::debug); + l->debug("Test stderr_color_st"); + spdlog::drop_all(); +} + +TEST_CASE("stderr_color_mt", "[stderr]") +{ + auto l = spdlog::stderr_color_mt("test"); + l->set_pattern("%+"); + l->info("Test stderr_color_mt"); + l->warn("Test stderr_color_mt"); + l->error("Test stderr_color_mt"); + l->critical("Test stderr_color_mt"); + spdlog::drop_all(); +} + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + +TEST_CASE("wchar_api", "[stdout]") +{ + auto l = spdlog::stdout_logger_st("wchar_logger"); + l->set_pattern("%+"); + l->set_level(spdlog::level::trace); + l->trace(L"Test wchar_api"); + l->trace(L"Test wchar_api {}", L"param"); + l->trace(L"Test wchar_api {}", 1); + l->trace(L"Test wchar_api {}", std::wstring{L"wstring param"}); + l->trace(std::wstring{L"Test wchar_api wstring"}); + SPDLOG_LOGGER_DEBUG(l, L"Test SPDLOG_LOGGER_DEBUG {}", L"param"); + spdlog::drop_all(); +} + +#endif diff --git a/Lumos/External/spdlog/tests/test_stopwatch.cpp b/Lumos/External/spdlog/tests/test_stopwatch.cpp new file mode 100644 index 000000000..81827b87e --- /dev/null +++ b/Lumos/External/spdlog/tests/test_stopwatch.cpp @@ -0,0 +1,44 @@ +#include "includes.h" +#include "test_sink.h" +#include "spdlog/stopwatch.h" + +TEST_CASE("stopwatch1", "[stopwatch]") +{ + using std::chrono::milliseconds; + using clock = std::chrono::steady_clock; + milliseconds wait_ms(200); + milliseconds tolerance_ms(250); + auto start = clock::now(); + spdlog::stopwatch sw; + std::this_thread::sleep_for(wait_ms); + auto stop = clock::now(); + auto diff_ms = std::chrono::duration_cast(stop - start); + REQUIRE(sw.elapsed() >= diff_ms); + REQUIRE(sw.elapsed() <= diff_ms + tolerance_ms); +} + +TEST_CASE("stopwatch2", "[stopwatch]") +{ + using spdlog::sinks::test_sink_st; + using std::chrono::duration_cast; + using std::chrono::milliseconds; + using clock = std::chrono::steady_clock; + + clock::duration wait_duration(milliseconds(200)); + clock::duration tolerance_duration(milliseconds(250)); + + auto test_sink = std::make_shared(); + + auto start = clock::now(); + spdlog::stopwatch sw; + spdlog::logger logger("test-stopwatch", test_sink); + logger.set_pattern("%v"); + std::this_thread::sleep_for(wait_duration); + auto stop = clock::now(); + logger.info("{}", sw); + auto val = std::stod(test_sink->lines()[0]); + auto diff_duration = duration_cast>(stop - start); + + REQUIRE(val >= (diff_duration).count() - 0.001); + REQUIRE(val <= (diff_duration + tolerance_duration).count()); +} diff --git a/Lumos/External/spdlog/tests/test_systemd.cpp b/Lumos/External/spdlog/tests/test_systemd.cpp new file mode 100644 index 000000000..8688f41d5 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_systemd.cpp @@ -0,0 +1,15 @@ +#include "includes.h" +#include "spdlog/sinks/systemd_sink.h" + +TEST_CASE("systemd", "[all]") +{ + auto systemd_sink = std::make_shared(); + spdlog::logger logger("spdlog_systemd_test", systemd_sink); + logger.set_level(spdlog::level::trace); + logger.trace("test spdlog trace"); + logger.debug("test spdlog debug"); + SPDLOG_LOGGER_INFO((&logger), "test spdlog info"); + SPDLOG_LOGGER_WARN((&logger), "test spdlog warn"); + SPDLOG_LOGGER_ERROR((&logger), "test spdlog error"); + SPDLOG_LOGGER_CRITICAL((&logger), "test spdlog critical"); +} diff --git a/Lumos/External/spdlog/tests/test_time_point.cpp b/Lumos/External/spdlog/tests/test_time_point.cpp new file mode 100644 index 000000000..bacff69a4 --- /dev/null +++ b/Lumos/External/spdlog/tests/test_time_point.cpp @@ -0,0 +1,36 @@ +#include "includes.h" +#include "test_sink.h" +#include "spdlog/async.h" + +TEST_CASE("time_point1", "[time_point log_msg]") +{ + std::shared_ptr test_sink(new spdlog::sinks::test_sink_st); + spdlog::logger logger("test-time_point", test_sink); + + spdlog::source_loc source{}; + std::chrono::system_clock::time_point tp{std::chrono::system_clock::now()}; + test_sink->set_pattern("%T.%F"); // interested in the time_point + + // all the following should have the same time + test_sink->set_delay(std::chrono::milliseconds(10)); + for (int i = 0; i < 5; i++) + { + spdlog::details::log_msg msg{tp, source, "test_logger", spdlog::level::info, "message"}; + test_sink->log(msg); + } + + logger.log(tp, source, spdlog::level::info, "formatted message"); + logger.log(tp, source, spdlog::level::info, "formatted message"); + logger.log(tp, source, spdlog::level::info, "formatted message"); + logger.log(tp, source, spdlog::level::info, "formatted message"); + logger.log(source, spdlog::level::info, "formatted message"); // last line has different time_point + + // now the real test... that the times are the same. + std::vector lines = test_sink->lines(); + REQUIRE(lines[0] == lines[1]); + REQUIRE(lines[2] == lines[3]); + REQUIRE(lines[4] == lines[5]); + REQUIRE(lines[6] == lines[7]); + REQUIRE(lines[8] != lines[9]); + spdlog::drop_all(); +} diff --git a/Lumos/External/spdlog/tests/utils.cpp b/Lumos/External/spdlog/tests/utils.cpp new file mode 100644 index 000000000..6d027797b --- /dev/null +++ b/Lumos/External/spdlog/tests/utils.cpp @@ -0,0 +1,127 @@ +#include "includes.h" + +#ifdef _WIN32 +# include +#else +# include +# include +#endif + +void prepare_logdir() +{ + spdlog::drop_all(); +#ifdef _WIN32 + system("rmdir /S /Q test_logs"); +#else + auto rv = system("rm -rf test_logs"); + if (rv != 0) + { + throw std::runtime_error("Failed to rm -rf test_logs"); + } +#endif +} + +std::string file_contents(const std::string &filename) +{ + std::ifstream ifs(filename, std::ios_base::binary); + if (!ifs) + { + throw std::runtime_error("Failed open file "); + } + return std::string((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); +} + +std::size_t count_lines(const std::string &filename) +{ + std::ifstream ifs(filename); + if (!ifs) + { + throw std::runtime_error("Failed open file "); + } + + std::string line; + size_t counter = 0; + while (std::getline(ifs, line)) + counter++; + return counter; +} + +void require_message_count(const std::string &filename, const std::size_t messages) +{ + if (strlen(spdlog::details::os::default_eol) == 0) + { + REQUIRE(count_lines(filename) == 1); + } + else + { + REQUIRE(count_lines(filename) == messages); + } +} + +std::size_t get_filesize(const std::string &filename) +{ + std::ifstream ifs(filename, std::ifstream::ate | std::ifstream::binary); + if (!ifs) + { + throw std::runtime_error("Failed open file "); + } + + return static_cast(ifs.tellg()); +} + +// source: https://stackoverflow.com/a/2072890/192001 +bool ends_with(std::string const &value, std::string const &ending) +{ + if (ending.size() > value.size()) + { + return false; + } + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +#ifdef _WIN32 +// Based on: https://stackoverflow.com/a/37416569/192001 +std::size_t count_files(const std::string &folder) +{ + size_t counter = 0; + WIN32_FIND_DATAA ffd; + + // Start iterating over the files in the folder directory. + HANDLE hFind = ::FindFirstFileA((folder + "\\*").c_str(), &ffd); + if (hFind != INVALID_HANDLE_VALUE) + { + do // Managed to locate and create an handle to that folder. + { + if (ffd.cFileName[0] != '.') + counter++; + } while (::FindNextFileA(hFind, &ffd) != 0); + ::FindClose(hFind); + } + else + { + throw std::runtime_error("Failed open folder " + folder); + } + + return counter; +} +#else +// Based on: https://stackoverflow.com/a/2802255/192001 +std::size_t count_files(const std::string &folder) +{ + size_t counter = 0; + DIR *dp = opendir(folder.c_str()); + if (dp == nullptr) + { + throw std::runtime_error("Failed open folder " + folder); + } + + struct dirent *ep = nullptr; + while ((ep = readdir(dp)) != nullptr) + { + if (ep->d_name[0] != '.') + counter++; + } + (void)closedir(dp); + return counter; +} +#endif diff --git a/Lumos/External/spdlog/tests/utils.h b/Lumos/External/spdlog/tests/utils.h new file mode 100644 index 000000000..53c09b469 --- /dev/null +++ b/Lumos/External/spdlog/tests/utils.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +std::size_t count_files(const std::string &folder); + +void prepare_logdir(); + +std::string file_contents(const std::string &filename); + +std::size_t count_lines(const std::string &filename); + +void require_message_count(const std::string &filename, const std::size_t messages); + +std::size_t get_filesize(const std::string &filename); + +bool ends_with(std::string const &value, std::string const &ending); \ No newline at end of file diff --git a/Lumos/Source/Lumos/Core/CommandLine.h b/Lumos/Source/Lumos/Core/CommandLine.h index a19dfc746..914fe134a 100644 --- a/Lumos/Source/Lumos/Core/CommandLine.h +++ b/Lumos/Source/Lumos/Core/CommandLine.h @@ -20,7 +20,7 @@ namespace Lumos { NONE = 0, REQUIRE = 1, - OPTIONAL = 2 + OPT = 2 }; #if 0 struct option_t diff --git a/Lumos/Source/Lumos/Core/OS/Allocators/PoolAllocator.h b/Lumos/Source/Lumos/Core/OS/Allocators/PoolAllocator.h new file mode 100644 index 000000000..1d11b24b1 --- /dev/null +++ b/Lumos/Source/Lumos/Core/OS/Allocators/PoolAllocator.h @@ -0,0 +1,97 @@ +#pragma once +#include "Memory.h" + +namespace Lumos +{ +// Pool Allocator +template +class PoolAllocator +{ + public: + explicit PoolAllocator(Arena* arena = nullptr, size_t poolSize = Megabytes(50)) + : m_Arena(arena) + , m_PoolSize(poolSize) + , m_NextAvailable(nullptr) + { + if(!arena) + { + m_ArenaOwned = true; + m_Arena = ArenaAlloc(Megabytes(51)); + } + + assert(m_Arena); + assert(m_PoolSize >= sizeof(Node)); + + m_AlignSize = (sizeof(T) + alignof(T) - 1) & ~(alignof(T) - 1); + + // Calculate the number of elements that fit in a pool + m_ElementsPerPool = (m_PoolSize - sizeof(Node)) / m_AlignSize; + + AllocateNewPool(); + } + + ~PoolAllocator() + { + while(m_HeadPool) + { + Node* nextPool = m_HeadPool->next; + m_Arena->Position = reinterpret_cast(m_HeadPool); + m_HeadPool = nextPool; + } + + if(m_ArenaOwned) + ArenaRelease(m_Arena); + } + + T* Allocate() + { + if(!m_NextAvailable) + { + AllocateNewPool(); + } + + Node* node = m_NextAvailable; + m_NextAvailable = m_NextAvailable->next; + + return reinterpret_cast(node); + } + + void Deallocate(T* ptr) + { + Node* node = reinterpret_cast(ptr); + node->next = m_NextAvailable; + m_NextAvailable = node; + } + + private: + struct Node + { + Node* next; + }; + + Arena* m_Arena; + size_t m_PoolSize; + size_t m_AlignSize; + size_t m_ElementsPerPool; + Node* m_HeadPool; + Node* m_NextAvailable; + bool m_ArenaOwned = false; + + void AllocateNewPool() + { + void* poolMemory = ArenaPush(m_Arena, m_PoolSize); + Node* pool = reinterpret_cast(poolMemory); + m_HeadPool = pool; + + // Create the linked list of available nodes in the pool + for(size_t i = 0; i < m_ElementsPerPool - 1; ++i) + { + pool->next = reinterpret_cast(reinterpret_cast(pool) + m_AlignSize); + pool = pool->next; + } + + pool->next = nullptr; + m_NextAvailable = m_HeadPool; + } +}; +} \ No newline at end of file diff --git a/Lumos/Source/Lumos/Core/OS/Memory.h b/Lumos/Source/Lumos/Core/OS/Memory.h index deddaedb7..b44593018 100644 --- a/Lumos/Source/Lumos/Core/OS/Memory.h +++ b/Lumos/Source/Lumos/Core/OS/Memory.h @@ -55,99 +55,6 @@ namespace Lumos #define ArenaTempBlock(arena, name) \ ArenaTemp name = { 0 }; \ DeferLoop(name = ArenaTempBegin(arena), ArenaTempEnd(name)) - - // Pool Allocator - template - class PoolAllocator - { - public: - explicit PoolAllocator(Arena* arena = nullptr, size_t poolSize = Megabytes(50)) - : m_Arena(arena) - , m_PoolSize(poolSize) - , m_NextAvailable(nullptr) - { - if(!arena) - { - m_ArenaOwned = true; - m_Arena = ArenaAlloc(Megabytes(51)); - } - - assert(m_Arena); - assert(m_PoolSize >= sizeof(Node)); - - m_AlignSize = (sizeof(T) + alignof(T) - 1) & ~(alignof(T) - 1); - - // Calculate the number of elements that fit in a pool - m_ElementsPerPool = (m_PoolSize - sizeof(Node)) / m_AlignSize; - - AllocateNewPool(); - } - - ~PoolAllocator() - { - while(m_HeadPool) - { - Node* nextPool = m_HeadPool->next; - m_Arena->Position = reinterpret_cast(m_HeadPool); - m_HeadPool = nextPool; - } - - if(m_ArenaOwned) - ArenaRelease(m_Arena); - } - - T* Allocate() - { - if(!m_NextAvailable) - { - AllocateNewPool(); - } - - Node* node = m_NextAvailable; - m_NextAvailable = m_NextAvailable->next; - - return reinterpret_cast(node); - } - - void Deallocate(T* ptr) - { - Node* node = reinterpret_cast(ptr); - node->next = m_NextAvailable; - m_NextAvailable = node; - } - - private: - struct Node - { - Node* next; - }; - - Arena* m_Arena; - size_t m_PoolSize; - size_t m_AlignSize; - size_t m_ElementsPerPool; - Node* m_HeadPool; - Node* m_NextAvailable; - bool m_ArenaOwned = false; - - void AllocateNewPool() - { - void* poolMemory = ArenaPush(m_Arena, m_PoolSize); - Node* pool = reinterpret_cast(poolMemory); - m_HeadPool = pool; - - // Create the linked list of available nodes in the pool - for(size_t i = 0; i < m_ElementsPerPool - 1; ++i) - { - pool->next = reinterpret_cast(reinterpret_cast(pool) + m_AlignSize); - pool = pool->next; - } - - pool->next = nullptr; - m_NextAvailable = m_HeadPool; - } - }; - } #define CUSTOM_MEMORY_ALLOCATOR diff --git a/Lumos/Source/Lumos/Core/OS/Window.h b/Lumos/Source/Lumos/Core/OS/Window.h index 5b4b69181..63b690911 100644 --- a/Lumos/Source/Lumos/Core/OS/Window.h +++ b/Lumos/Source/Lumos/Core/OS/Window.h @@ -1,10 +1,13 @@ #pragma once +#include "Core/Reference.h" #include "Events/Event.h" #include "Graphics/RHI/SwapChain.h" #include "Graphics/RHI/GraphicsContext.h" #include #include +#include +#include namespace Lumos { diff --git a/Lumos/Source/Lumos/Graphics/Camera/Camera.cpp b/Lumos/Source/Lumos/Graphics/Camera/Camera.cpp index e51a56281..7d23fd9ef 100644 --- a/Lumos/Source/Lumos/Graphics/Camera/Camera.cpp +++ b/Lumos/Source/Lumos/Graphics/Camera/Camera.cpp @@ -104,14 +104,14 @@ namespace Lumos if(flipY) y *= -1.0f; - glm::vec4 near = viewProjInverse * glm::vec4(x, y, 0.0f, 1.0f); - near /= near.w; + glm::vec4 n = viewProjInverse * glm::vec4(x, y, 0.0f, 1.0f); + n /= n.w; - glm::vec4 far = viewProjInverse * glm::vec4(x, y, 1.0f, 1.0f); - far /= far.w; + glm::vec4 f = viewProjInverse * glm::vec4(x, y, 1.0f, 1.0f); + f /= f.w; - ret.Origin = glm::vec3(near); - ret.Direction = glm::normalize(glm::vec3(far) - ret.Origin); + ret.Origin = glm::vec3(n); + ret.Direction = glm::normalize(glm::vec3(f) - ret.Origin); return ret; } diff --git a/Lumos/Source/Lumos/Graphics/ModelLoader/GLTFLoader.cpp b/Lumos/Source/Lumos/Graphics/ModelLoader/GLTFLoader.cpp index 08795ad0d..734064435 100644 --- a/Lumos/Source/Lumos/Graphics/ModelLoader/GLTFLoader.cpp +++ b/Lumos/Source/Lumos/Graphics/ModelLoader/GLTFLoader.cpp @@ -320,8 +320,8 @@ namespace Lumos::Graphics Maths::Vector3Simple* normals = reinterpret_cast(data.data()); for(auto p = 0; p < normalCount; ++p) { - vertices[p].Normal = (parentTransform.GetWorldMatrix() * Maths::ToVector4(normals[p])); - + //vertices[p].Normal = (parentTransform.GetWorldMatrix() * Maths::ToVector4(normals[p])); + vertices[p].Normal = glm::transpose(glm::inverse(glm::mat3(parentTransform.GetWorldMatrix()))) * (glm::vec3(Maths::ToVector4(normals[p]))); vertices[p].Normal = glm::normalize(vertices[p].Normal); } } diff --git a/Lumos/Source/Lumos/Graphics/RHI/Definitions.h b/Lumos/Source/Lumos/Graphics/RHI/Definitions.h index 6c2816518..000305d47 100644 --- a/Lumos/Source/Lumos/Graphics/RHI/Definitions.h +++ b/Lumos/Source/Lumos/Graphics/RHI/Definitions.h @@ -1,4 +1,6 @@ #pragma once +#include "Core/LMLog.h" +#include namespace Lumos { diff --git a/Lumos/Source/Lumos/Graphics/RHI/Renderer.cpp b/Lumos/Source/Lumos/Graphics/RHI/Renderer.cpp index 2dda2fdb7..db65c3780 100644 --- a/Lumos/Source/Lumos/Graphics/RHI/Renderer.cpp +++ b/Lumos/Source/Lumos/Graphics/RHI/Renderer.cpp @@ -152,6 +152,9 @@ namespace Lumos } } + GraphicsContext* Renderer::GetGraphicsContext() { return Application::Get().GetWindow()->GetGraphicsContext(); } + SwapChain* Renderer::GetMainSwapChain() { return Application::Get().GetWindow()->GetSwapChain(); } + void Renderer::DrawMesh(CommandBuffer* commandBuffer, Graphics::Pipeline* pipeline, Graphics::Mesh* mesh) { mesh->GetVertexBuffer()->Bind(commandBuffer, pipeline); diff --git a/Lumos/Source/Lumos/Graphics/RHI/Renderer.h b/Lumos/Source/Lumos/Graphics/RHI/Renderer.h index cdd27e1ae..376e03d78 100644 --- a/Lumos/Source/Lumos/Graphics/RHI/Renderer.h +++ b/Lumos/Source/Lumos/Graphics/RHI/Renderer.h @@ -1,5 +1,4 @@ #pragma once -#include "Core/Application.h" #include "Core/OS/Window.h" #include "Graphics/RHI/Definitions.h" #include @@ -88,8 +87,8 @@ namespace Lumos return capabilities; } - static GraphicsContext* GetGraphicsContext() { return Application::Get().GetWindow()->GetGraphicsContext(); } - static SwapChain* GetMainSwapChain() { return Application::Get().GetWindow()->GetSwapChain(); } + static GraphicsContext* GetGraphicsContext(); + static SwapChain* GetMainSwapChain(); static void DrawMesh(CommandBuffer* commandBuffer, Graphics::Pipeline* pipeline, Graphics::Mesh* mesh); protected: diff --git a/Lumos/Source/Lumos/Graphics/Renderers/RenderPasses.h b/Lumos/Source/Lumos/Graphics/Renderers/RenderPasses.h index 492cfc250..6265739a4 100644 --- a/Lumos/Source/Lumos/Graphics/Renderers/RenderPasses.h +++ b/Lumos/Source/Lumos/Graphics/Renderers/RenderPasses.h @@ -7,6 +7,9 @@ namespace Lumos { class Scene; + class TimeStep; + class WindowResizeEvent; + namespace Maths { class Transform; diff --git a/Lumos/Source/Lumos/ImGui/ImGuiUtilities.cpp b/Lumos/Source/Lumos/ImGui/ImGuiUtilities.cpp index 5132e9c00..6c4af3487 100644 --- a/Lumos/Source/Lumos/ImGui/ImGuiUtilities.cpp +++ b/Lumos/Source/Lumos/ImGui/ImGuiUtilities.cpp @@ -939,9 +939,9 @@ namespace Lumos colours[ImGuiCol_Border] = foreground; colours[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f); - colours[ImGuiCol_FrameBg] = background; - colours[ImGuiCol_FrameBgHovered] = background; - colours[ImGuiCol_FrameBgActive] = background; + colours[ImGuiCol_FrameBg] = foreground; + colours[ImGuiCol_FrameBgHovered] = foreground; + colours[ImGuiCol_FrameBgActive] = foreground; colours[ImGuiCol_TitleBg] = foreground; colours[ImGuiCol_TitleBgActive] = foreground; diff --git a/Lumos/Source/Lumos/Maths/Frustum.cpp b/Lumos/Source/Lumos/Maths/Frustum.cpp index bd123f144..3f5d92953 100644 --- a/Lumos/Source/Lumos/Maths/Frustum.cpp +++ b/Lumos/Source/Lumos/Maths/Frustum.cpp @@ -73,21 +73,21 @@ namespace Lumos CalculateVertices(transform); } - void Frustum::DefineOrtho(float scale, float aspectRatio, float near, float far, const glm::mat4& viewMatrix) + void Frustum::DefineOrtho(float scale, float aspectRatio, float n, float f, const glm::mat4& viewMatrix) { LUMOS_PROFILE_FUNCTION_LOW(); - glm::mat4 m = glm::ortho(-scale * aspectRatio, scale * aspectRatio, -scale, scale, near, far); + glm::mat4 m = glm::ortho(-scale * aspectRatio, scale * aspectRatio, -scale, scale, n, f); m = m * viewMatrix; Define(m); } - void Frustum::Define(float fov, float aspectRatio, float near, float far, const glm::mat4& viewMatrix) + void Frustum::Define(float fov, float aspectRatio, float n, float f, const glm::mat4& viewMatrix) { LUMOS_PROFILE_FUNCTION_LOW(); float tangent = tan(fov * 0.5f); - float height = near * tangent; + float height = n * tangent; float width = height * aspectRatio; - glm::mat4 m = glm::frustum(-width, width, -height, height, near, far); + glm::mat4 m = glm::frustum(-width, width, -height, height, n, f); m = m * viewMatrix; Define(m); } diff --git a/Lumos/Source/Lumos/Maths/Frustum.h b/Lumos/Source/Lumos/Maths/Frustum.h index 26a12c2c1..139d957c3 100644 --- a/Lumos/Source/Lumos/Maths/Frustum.h +++ b/Lumos/Source/Lumos/Maths/Frustum.h @@ -32,8 +32,8 @@ namespace Lumos void Transform(const glm::mat4& transform); void Define(const glm::mat4& projection, const glm::mat4& view); void Define(const glm::mat4& transform); - void DefineOrtho(float scale, float aspectRatio, float near, float far, const glm::mat4& viewMatrix); - void Define(float fov, float aspectRatio, float near, float far, const glm::mat4& viewMatrix); + void DefineOrtho(float scale, float aspectRatio, float n, float f, const glm::mat4& viewMatrix); + void Define(float fov, float aspectRatio, float n, float f, const glm::mat4& viewMatrix); bool IsInside(const glm::vec3& point) const; bool IsInside(const BoundingSphere& sphere) const; diff --git a/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/LumosPhysicsEngine.h b/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/LumosPhysicsEngine.h index b2930e7eb..72f2e5c5d 100644 --- a/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/LumosPhysicsEngine.h +++ b/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/LumosPhysicsEngine.h @@ -5,6 +5,7 @@ #include "Narrowphase/Manifold.h" #include "Broadphase/Broadphase.h" #include "Scene/ISystem.h" +#include "Core/OS/Allocators/PoolAllocator.h" namespace Lumos { @@ -111,7 +112,7 @@ namespace Lumos uint32_t GetPositionIterations() const { return m_PositionIterations; } void SetPositionIterations(uint32_t iterations) { m_PositionIterations = iterations; } - RigidBody3D* CreateBody(const RigidBody3DProperties& properties); + RigidBody3D* CreateBody(const RigidBody3DProperties& properties = {}); void DestroyBody(RigidBody3D* body); const PhysicsStats3D& GetStats() const { return m_Stats; } diff --git a/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/Narrowphase/CollisionDetection.cpp b/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/Narrowphase/CollisionDetection.cpp index 2694a5cba..ce45c9166 100644 --- a/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/Narrowphase/CollisionDetection.cpp +++ b/Lumos/Source/Lumos/Physics/LumosPhysicsEngine/Narrowphase/CollisionDetection.cpp @@ -35,7 +35,7 @@ namespace Lumos bool CollisionDetection::CheckCollision(RigidBody3D* obj1, RigidBody3D* obj2, CollisionShape* shape1, CollisionShape* shape2, CollisionData* out_coldata) { LUMOS_PROFILE_FUNCTION_LOW(); - LUMOS_ASSERT(((shape1->GetType() | shape2->GetType()) < m_MaxSize), "Invalid collision func {0}, {1}, {2}, {3}", shape1->GetType(), shape2->GetType(), shape2->GetType() | shape2->GetType(), m_MaxSize); + LUMOS_ASSERT(((shape1->GetType() | shape2->GetType()) < m_MaxSize), "Invalid collision func {0}, {1}, {2}, {3}", (int)shape1->GetType(), (int)shape2->GetType(), (int)shape2->GetType() | (int)shape2->GetType(), m_MaxSize); return CALL_MEMBER_FN(*this, m_CollisionCheckFunctions[shape1->GetType() | shape2->GetType()])(obj1, obj2, shape1, shape2, out_coldata); } diff --git a/Lumos/Source/Lumos/Platform/OpenGL/GLContext.cpp b/Lumos/Source/Lumos/Platform/OpenGL/GLContext.cpp index 8fc10d1a7..5df433edf 100644 --- a/Lumos/Source/Lumos/Platform/OpenGL/GLContext.cpp +++ b/Lumos/Source/Lumos/Platform/OpenGL/GLContext.cpp @@ -127,9 +127,9 @@ namespace Lumos { LUMOS_LOG_INFO("----------------------------------"); LUMOS_LOG_INFO(OPENGLLOG); - LUMOS_LOG_INFO(glGetString(GL_VERSION)); - LUMOS_LOG_INFO(glGetString(GL_VENDOR)); - LUMOS_LOG_INFO(glGetString(GL_RENDERER)); + LUMOS_LOG_INFO((const char*)(glGetString(GL_VERSION))); + LUMOS_LOG_INFO((const char*)(glGetString(GL_VENDOR))); + LUMOS_LOG_INFO((const char*)(glGetString(GL_RENDERER))); LUMOS_LOG_INFO("----------------------------------"); #if LUMOS_DEBUG diff --git a/Lumos/Source/Lumos/Platform/Vulkan/VKShader.cpp b/Lumos/Source/Lumos/Platform/Vulkan/VKShader.cpp index 4d2553282..8b7a975b5 100644 --- a/Lumos/Source/Lumos/Platform/Vulkan/VKShader.cpp +++ b/Lumos/Source/Lumos/Platform/Vulkan/VKShader.cpp @@ -374,7 +374,7 @@ namespace Lumos case VK_FORMAT_R32G32B32A32_UINT: return sizeof(glm::ivec4); // Need uintvec? default: - LUMOS_LOG_ERROR("Unsupported Format {0}", format); + LUMOS_LOG_ERROR("Unsupported Format {0}", (int)format); return 0; } diff --git a/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.cpp b/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.cpp index cebbc5872..3df0ee764 100644 --- a/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.cpp +++ b/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.cpp @@ -18,6 +18,12 @@ namespace Lumos { } + RigidBody3DComponent::RigidBody3DComponent(const RigidBody3DProperties& properties) + { + m_RigidBody = Application::Get().GetSystem()->CreateBody(properties); + + } + RigidBody3DComponent::RigidBody3DComponent(const RigidBody3DComponent& other) { m_RigidBody = other.m_RigidBody; diff --git a/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.h b/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.h index 9991d7f2b..d27dd2b0c 100644 --- a/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.h +++ b/Lumos/Source/Lumos/Scene/Component/RigidBody3DComponent.h @@ -106,7 +106,8 @@ namespace Lumos RigidBody3DComponent(); RigidBody3DComponent(const RigidBody3DComponent& other); - explicit RigidBody3DComponent(RigidBody3D* physics); + RigidBody3DComponent(RigidBody3D* physics); + RigidBody3DComponent(const RigidBody3DProperties& params); ~RigidBody3DComponent() = default; diff --git a/Lumos/Source/Lumos/Scripting/Lua/LuaManager.cpp b/Lumos/Source/Lumos/Scripting/Lua/LuaManager.cpp index 858159bb0..51e9c220f 100644 --- a/Lumos/Source/Lumos/Scripting/Lua/LuaManager.cpp +++ b/Lumos/Source/Lumos/Scripting/Lua/LuaManager.cpp @@ -25,6 +25,7 @@ #include "Scene/EntityManager.h" #include "Scene/EntityFactory.h" #include "Physics/LumosPhysicsEngine/LumosPhysicsEngine.h" +#include "Physics/LumosPhysicsEngine/RigidBody3D.h" #include "ImGuiLua.h" #include "PhysicsLua.h" @@ -614,9 +615,11 @@ namespace Lumos REGISTER_COMPONENT_WITH_ECS(state, Camera, static_cast(&Entity::AddComponent)); - sol::usertype RigidBody3DComponent_type = state.new_usertype("RigidBody3DComponent" /*, sol::constructors&>>()*/); + sol::usertype RigidBody3DComponent_type = state.new_usertype("RigidBody3DComponent", sol::constructors>()); RigidBody3DComponent_type.set_function("GetRigidBody", &RigidBody3DComponent::GetRigidBody); - REGISTER_COMPONENT_WITH_ECS(state, RigidBody3DComponent, static_cast&)>(&Entity::AddComponent)); //, SharedPtr&>)); + + REGISTER_COMPONENT_WITH_ECS(state, RigidBody3DComponent, static_cast(&Entity::AddComponent)); + //REGISTER_COMPONENT_WITH_ECS(state, RigidBody3DComponent, static_cast(&Entity::AddComponent RigidBody2DComponent_type = state.new_usertype("RigidBody2DComponent", sol::constructors>()); RigidBody2DComponent_type.set_function("GetRigidBody", &RigidBody2DComponent::GetRigidBody); diff --git a/Lumos/Source/Lumos/Scripting/Lua/PhysicsLua.cpp b/Lumos/Source/Lumos/Scripting/Lua/PhysicsLua.cpp index 526f2b157..d5ecc94ca 100644 --- a/Lumos/Source/Lumos/Scripting/Lua/PhysicsLua.cpp +++ b/Lumos/Source/Lumos/Scripting/Lua/PhysicsLua.cpp @@ -334,6 +334,15 @@ namespace Lumos physicsObjectParameters_type["scale"] = &RigidBodyParameters::scale; physicsObjectParameters_type["isStatic"] = &RigidBodyParameters::isStatic; physicsObjectParameters_type["customShapePositions"] = &RigidBodyParameters::custumShapePositions; + + + sol::usertype physicsObjectParameters3D_type = state.new_usertype("RigidBodyParameters3D"); + physicsObjectParameters3D_type["mass"] = &RigidBody3DProperties::Mass; + //physicsObjectParameters3D_type["shape"] = &RigidBody3DProperties::Shape; + physicsObjectParameters3D_type["position"] = &RigidBody3DProperties::Position; + //physicsObjectParameters3D_type["scale"] = &RigidBody3DProperties::Scale; + physicsObjectParameters3D_type["isStatic"] = &RigidBody3DProperties::Static; + //physicsObjectParameters3D_type["customShapePositions"] = &RigidBody3DProperties::custumShapePositions; sol::usertype physics3D_type = state.new_usertype("RigidBody3D"); //, sol::constructors()); //;const RigidBodyParameters&)>()); physics3D_type.set_function("SetForce", &RigidBody3D::SetForce); diff --git a/Lumos/Source/Precompiled.h b/Lumos/Source/Precompiled.h index 0913fba5c..5fc449752 100644 --- a/Lumos/Source/Precompiled.h +++ b/Lumos/Source/Precompiled.h @@ -27,4 +27,11 @@ #include "Core/LMLog.h" #include "Core/Core.h" #include "Core/Profiler.h" + +#include +#include + +#ifdef LUMOS_PLATFORM_WINDOWS +#include +#endif #endif diff --git a/README.md b/README.md index f2e329ea9..7f876c2cb 100755 --- a/README.md +++ b/README.md @@ -9,14 +9,13 @@ Dependencies

-Build +Build platforms -license +license
-Issues -size -stars -Discord +stars +release +Discord

diff --git a/Resources/Screenshot 2023-09-04 100048.png b/Resources/Screenshot 2023-09-04 100048.png new file mode 100644 index 000000000..4d32f61a8 Binary files /dev/null and b/Resources/Screenshot 2023-09-04 100048.png differ