From 8b963dc7ada1034e04ec40e3f419a01dfd20df78 Mon Sep 17 00:00:00 2001 From: miloyip Date: Wed, 16 Jul 2014 19:14:00 +0800 Subject: [PATCH 1/6] Start benchmarking different itoa implementation --- include/rapidjson/msinttypes/stdint.h | 38 +- include/rapidjson/stringbuffer.h | 1 + test/perftest/misctest.cpp | 502 +- thirdparty/cppformat/format.cc | 1202 ++ thirdparty/cppformat/format.h | 2019 ++ thirdparty/strtk/strtk.hpp | 23653 ++++++++++++++++++++++++ 6 files changed, 27413 insertions(+), 2 deletions(-) create mode 100644 thirdparty/cppformat/format.cc create mode 100644 thirdparty/cppformat/format.h create mode 100644 thirdparty/strtk/strtk.hpp diff --git a/include/rapidjson/msinttypes/stdint.h b/include/rapidjson/msinttypes/stdint.h index b811df7db..bbad95af1 100644 --- a/include/rapidjson/msinttypes/stdint.h +++ b/include/rapidjson/msinttypes/stdint.h @@ -42,8 +42,44 @@ #endif // miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. -#if _MSC_VER >= 1700 // [ +#if _MSC_VER >= 1600 // [ #include + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +#undef INT8_C +#undef INT16_C +#undef INT32_C +#undef INT64_C +#undef UINT8_C +#undef UINT16_C +#undef UINT32_C +#undef UINT64_C + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + #else // ] _MSC_VER >= 1700 [ #include diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h index 162e5f166..8c7eb4f17 100644 --- a/include/rapidjson/stringbuffer.h +++ b/include/rapidjson/stringbuffer.h @@ -22,6 +22,7 @@ struct GenericStringBuffer { void Flush() {} void Clear() { stack_.Clear(); } + Ch* Allocate(size_t count) { return stack_.template Push(count); } const Ch* GetString() const { // Push and pop a null terminator. This is safe. diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index bf47e6ebf..94c2ef2d1 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -2,6 +2,24 @@ #if TEST_MISC +#define __STDC_FORMAT_MACROS + +#define strtk_no_tr1_or_boost +#include "strtk/strtk.hpp" +#include "rapidjson/stringbuffer.h" + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4245; disable: 4512) +#endif + +#include "cppformat/format.h" +#include "cppformat/format.cc" + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + class Misc : public PerfTest { }; @@ -58,4 +76,486 @@ TEST_F(Misc, Hoehrmann_IsUTF8) { } } -#endif // TEST_ULTRAJSON +// https://gist.github.com/anonymous/7179097 +static const int randval[] ={ + 936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064, + -644712, 944969, 640463, -366588, 471577, -69401, -744294, -505829, 923883, 831785, + -601136, -636767, -437054, 591718, 100758, 231907, -719038, 973540, -605220, 506659, + -871653, 462533, 764843, -919138, 404305, -630931, -288711, -751454, -173726, -718208, + 432689, -281157, 360737, 659827, 19174, -376450, 769984, -858198, 439127, 734703, + -683426, 7, 386135, 186997, -643900, -744422, -604708, -629545, 42313, -933592, + -635566, 182308, 439024, -367219, -73924, -516649, 421935, -470515, 413507, -78952, + -427917, -561158, 737176, 94538, 572322, 405217, 709266, -357278, -908099, -425447, + 601119, 750712, -862285, -177869, 900102, 384877, 157859, -641680, 503738, -702558, + 278225, 463290, 268378, -212840, 580090, 347346, -473985, -950968, -114547, -839893, + -738032, -789424, 409540, 493495, 432099, 119755, 905004, -174834, 338266, 234298, + 74641, -965136, -754593, 685273, 466924, 920560, 385062, 796402, -67229, 994864, + 376974, 299869, -647540, -128724, 469890, -163167, -547803, -743363, 486463, -621028, + 612288, 27459, -514224, 126342, -66612, 803409, -777155, -336453, -284002, 472451, + 342390, -163630, 908356, -456147, -825607, 268092, -974715, 287227, 227890, -524101, + 616370, -782456, 922098, -624001, -813690, 171605, -192962, 796151, 707183, -95696, + -23163, -721260, 508892, 430715, 791331, 482048, -996102, 863274, 275406, -8279, + -556239, -902076, 268647, -818565, 260069, -798232, -172924, -566311, -806503, -885992, + 813969, -78468, 956632, 304288, 494867, -508784, 381751, 151264, 762953, 76352, + 594902, 375424, 271700, -743062, 390176, 924237, 772574, 676610, 435752, -153847, + 3959, -971937, -294181, -538049, -344620, -170136, 19120, -703157, 868152, -657961, + -818631, 219015, -872729, -940001, -956570, 880727, -345910, 942913, -942271, -788115, + 225294, 701108, -517736, -416071, 281940, 488730, 942698, 711494, 838382, -892302, + -533028, 103052, 528823, 901515, 949577, 159364, 718227, -241814, -733661, -462928, + -495829, 165170, 513580, -629188, -509571, -459083, 198437, 77198, -644612, 811276, + -422298, -860842, -52584, 920369, 686424, -530667, -243476, 49763, 345866, -411960, + -114863, 470810, -302860, 683007, -509080, 2, -174981, -772163, -48697, 447770, + -268246, 213268, 269215, 78810, -236340, -639140, -864323, 505113, -986569, -325215, + 541859, 163070, -819998, -645161, -583336, 573414, 696417, -132375, 3, -294501, + 320435, 682591, 840008, 351740, 426951, 609354, 898154, -943254, 227321, -859793, + -727993, 44137, -497965, -782239, 14955, -746080, -243366, 9837, -233083, 606507, + -995864, -615287, -994307, 602715, 770771, -315040, 610860, 446102, -307120, 710728, + -590392, -230474, -762625, -637525, 134963, -202700, -766902, -985541, 218163, 682009, + 926051, 525156, -61195, 403211, -810098, 245539, -431733, 179998, -806533, 745943, + 447597, 131973, -187130, 826019, 286107, -937230, -577419, 20254, 681802, -340500, + 323080, 266283, -667617, 309656, 416386, 611863, 759991, -534257, 523112, -634892, + -169913, -204905, -909867, -882185, -944908, 741811, -717675, 967007, -317396, 407230, + -412805, 792905, 994873, 744793, -456797, 713493, 355232, 116900, -945199, 880539, + 342505, -580824, -262273, 982968, -349497, -735488, 311767, -455191, 570918, 389734, + -958386, 10262, -99267, 155481, 304210, 204724, 704367, -144893, -233664, -671441, + 896849, 408613, 762236, 322697, 981321, 688476, 13663, -970704, -379507, 896412, + 977084, 348869, 875948, 341348, 318710, 512081, 6163, 669044, 833295, 811883, + 708756, -802534, -536057, 608413, -389625, -694603, 541106, -110037, 720322, -540581, + 645420, 32980, 62442, 510157, -981870, -87093, -325960, -500494, -718291, -67889, + 991501, 374804, 769026, -978869, 294747, 714623, 413327, -199164, 671368, 804789, + -362507, 798196, -170790, -568895, -869379, 62020, -316693, -837793, 644994, -39341, + -417504, -243068, -957756, 99072, 622234, -739992, 225668, 8863, -505910, 82483, + -559244, 241572, 1315, -36175, -54990, 376813, -11, 162647, -688204, -486163, + -54934, -197470, 744223, -762707, 732540, 996618, 351561, -445933, -898491, 486531, + 456151, 15276, 290186, -817110, -52995, 313046, -452533, -96267, 94470, -500176, + -818026, -398071, -810548, -143325, -819741, 1338, -897676, -101577, -855445, 37309, + 285742, 953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953, + -552279, 329142, -570048, -505756, 682898, -381089, -14352, 175138, 152390, -582268, + -485137, 717035, 805329, 239572, -730409, 209643, -184403, -385864, 675086, 819648, + 629058, -527109, -488666, -171981, 532788, 552441, 174666, 984921, 766514, 758787, + 716309, 338801, -978004, -412163, 876079, -734212, 789557, -160491, -522719, 56644, + -991, -286038, -53983, 663740, 809812, 919889, -717502, -137704, 220511, 184396, + -825740, -588447, 430870, 124309, 135956, 558662, -307087, -788055, -451328, 812260, + 931601, 324347, -482989, -117858, -278861, 189068, -172774, 929057, 293787, 198161, + -342386, -47173, 906555, -759955, -12779, 777604, -97869, 899320, 927486, -25284, + -848550, 259450, -485856, -17820, 88, 171400, 235492, -326783, -340793, 886886, + 112428, -246280, 5979, 648444, -114982, 991013, -56489, -9497, 419706, 632820, + -341664, 393926, -848977, -22538, 257307, 773731, -905319, 491153, 734883, -868212, + -951053, 644458, -580758, 764735, 584316, 297077, 28852, -397710, -953669, 201772, + 879050, -198237, -588468, 448102, -116837, 770007, -231812, 642906, -582166, -885828, + 9, 305082, -996577, 303559, 75008, -772956, -447960, 599825, -295552, 870739, + -386278, -950300, 485359, -457081, 629461, -850276, 550496, -451755, -620841, -11766, + -950137, 832337, 28711, -273398, -507197, 91921, -271360, -705991, -753220, -388968, + 967945, 340434, -320883, -662793, -554617, -574568, 477946, -6148, -129519, 689217, + 920020, -656315, -974523, -212525, 80921, -612532, 645096, 545655, 655713, -591631, + -307385, -816688, -618823, -113713, 526430, 673063, 735916, -809095, -850417, 639004, + 432281, -388185, 270708, 860146, -39902, -786157, -258180, -246169, -966720, -264957, + 548072, -306010, -57367, -635665, 933824, 70553, -989936, -488741, 72411, -452509, + 529831, 956277, 449019, -577850, -360986, -803418, 48833, 296073, 203430, 609591, + 715483, 470964, 658106, -718254, -96424, 790163, 334739, 181070, -373578, 5, + -435088, 329841, 330939, -256602, 394355, 912412, 231910, 927278, -661933, 788539, + -769664, -893274, -96856, 298205, 901043, -608122, -527430, 183618, -553963, -35246, + -393924, 948832, -483198, 594501, 35460, -407007, 93494, -336881, -634072, 984205, + -812161, 944664, -31062, 753872, 823933, -69566, 50445, 290147, 85134, 34706, + 551902, 405202, -991246, -84642, 154341, 316432, -695101, -651588, -5030, 137564, + -294665, 332541, 528307, -90572, -344923, 523766, -758498, -968047, 339028, 494578, + 593129, -725773, 31834, -718406, -208638, 159665, -2043, 673344, -442767, 75816, + 755442, 769257, -158730, -410272, 691688, 589550, -878398, -184121, 460679, 346312, + 294163, -544602, 653308, 254167, -276979, 52073, -892684, 887653, -41222, 983065, + -68258, -408799, -99069, -674069, -863635, -32890, 622757, -743862, 40872, -4837, + -967228, 522370, -903951, -818669, 524459, 514702, 925801, 20007, -299229, 579348, + 626021, 430089, 348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892, + -312230, 143337, 109746, 880042, -339658, -785614, 938995, 540916, 118429, 661351, + -402967, 404729, -40918, -976535, 743230, 713110, 440182, -381314, -499252, 74613, + 193652, 912717, 491323, 583633, 324691, 459397, 281253, 195540, -2764, -888651, + 892449, 132663, -478373, -430002, -314551, 527826, 247165, 557966, 554778, 481531, + -946634, 431685, -769059, -348371, 174046, 184597, -354867, 584422, 227390, -850397, + -542924, -849093, -737769, 325359, 736314, 269101, 767940, 674809, 81413, -447458, + 445076, 189072, 906218, 502688, -718476, -863827, -731381, 100660, 623249, 710008, + 572060, 922203, 685740, 55096, 263394, -243695, -353910, -516788, 388471, 455165, + 844103, -643772, 363976, 268875, -899450, 104470, 104029, -238874, -274659, 732969, + -676443, 953291, -916289, -861849, -242344, 958083, -479593, -970395, 799831, 277841, + -243236, -283462, -201510, 166263, -259105, -575706, 878926, 891064, 895297, 655262, + -34807, -809833, -89281, 342585, 554920, 1, 902141, -333425, 139703, 852318, + -618438, 329498, -932596, -692836, -513372, 733656, -523411, 85779, 500478, -682697, + -502836, 138776, 156341, -420037, -557964, -556378, 710993, -50383, -877159, 916334, + 132996, 583516, -603392, -111615, -12288, -780214, 476780, 123327, 137607, 519956, + 745837, 17358, -158581, -53490 +}; +static const size_t randvalCount = sizeof(randval) / sizeof(randval[0]); +static const size_t kItoaTrialCount = 10000; + +// Prevent code being optimized out +#define OUTPUT_LENGTH(length) printf("", length) +//#define OUTPUT_LENGTH(length) printf("%d\n", length) + +template +class Writer1 { +public: + Writer1() : os_() {} + Writer1(OutputStream& os) : os_(&os) {} + + void Reset(OutputStream& os) { + os_ = &os; + } + + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } + + bool WriteUint(unsigned u) { + char buffer[10]; + char *p = buffer; + do { + *p++ = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char *p = buffer; + do { + *p++ = char(u64 % 10) + '0'; + u64 /= 10; + } while (u64 > 0); + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + +private: + OutputStream* os_; +}; + +static const char digits[201] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +// Using digits LUT to reduce divsion/modulo +template +class Writer2 { +public: + Writer2() : os_() {} + Writer2(OutputStream& os) : os_(&os) {} + + void Reset(OutputStream& os) { + os_ = &os; + } + + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } + + bool WriteUint(unsigned u) { + char buffer[10]; + char* p = buffer; + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u < 10) + *p++ = char(u) + '0'; + else { + const unsigned i = u << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* p = buffer; + while (u64 >= 100) { + const unsigned i = static_cast(u64 % 100) << 1; + u64 /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u64 < 10) + *p++ = char(u64) + '0'; + else { + const unsigned i = static_cast(u64) << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + +private: + OutputStream* os_; +}; + +template +void itoa_Writer_Verify() { + rapidjson::StringBuffer sb; + Writer writer(sb); + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + sprintf(buffer, "%d", randval[j]); + writer.WriteInt(randval[j]); + ASSERT_STREQ(buffer, sb.GetString()); + sb.Clear(); + } +} + +template +void itoa_Writer_StringBuffer() { + size_t length = 0; + + rapidjson::StringBuffer sb; + Writer writer(sb); + + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + writer.WriteInt(randval[j]); + length += sb.GetSize(); + sb.Clear(); + } + } + OUTPUT_LENGTH(length); +} + +template +void itoa_Writer_InsituStringStream() { + size_t length = 0; + + char buffer[32]; + Writer writer; + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + rapidjson::InsituStringStream ss(buffer); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt(randval[j]); + length += ss.PutEnd(begin); + } + } + OUTPUT_LENGTH(length); +}; + +template +void itoa64_Writer_Verify() { + rapidjson::StringBuffer sb; + Writer writer(sb); + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + int64_t x = randval[j] * randval[j]; + sprintf(buffer, "%" PRIi64, x); + writer.WriteInt64(x); + ASSERT_STREQ(buffer, sb.GetString()); + sb.Clear(); + } +} + +template +void itoa64_Writer_StringBuffer() { + size_t length = 0; + + rapidjson::StringBuffer sb; + Writer writer(sb); + + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + writer.WriteInt64(randval[j] * randval[j]); + length += sb.GetSize(); + sb.Clear(); + } + } + OUTPUT_LENGTH(length); +} + +template +void itoa64_Writer_InsituStringStream() { + size_t length = 0; + + char buffer[32]; + Writer writer; + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + rapidjson::InsituStringStream ss(buffer); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt64(randval[j] * randval[j]); + length += ss.PutEnd(begin); + } + } + OUTPUT_LENGTH(length); +}; + +TEST_F(Misc, itoa_Writer1_Verify) { + itoa_Writer_Verify >(); +} + +TEST_F(Misc, itoa_Writer2_Verify) { + itoa_Writer_Verify >(); +} + +TEST_F(Misc, itoa_Writer1_StringBuffer) { + itoa_Writer_StringBuffer >(); +} + +TEST_F(Misc, itoa_Writer1_InsituStringStream) { + itoa_Writer_InsituStringStream >(); +} + +TEST_F(Misc, itoa_Writer2_StringBuffer) { + itoa_Writer_StringBuffer >(); +} + +TEST_F(Misc, itoa_Writer2_InsituStringStream) { + itoa_Writer_InsituStringStream >(); +} + +TEST_F(Misc, itoa64_Writer1_Verify) { + itoa64_Writer_Verify >(); +} + +TEST_F(Misc, itoa64_Writer2_Verify) { + itoa64_Writer_Verify >(); +} + +TEST_F(Misc, itoa64_Writer1_StringBuffer) { + itoa64_Writer_StringBuffer >(); +} + +TEST_F(Misc, itoa64_Writer1_InsituStringStream) { + itoa64_Writer_InsituStringStream >(); +} + +TEST_F(Misc, itoa64_Writer2_StringBuffer) { + itoa64_Writer_StringBuffer >(); +} + +TEST_F(Misc, itoa64_Writer2_InsituStringStream) { + itoa64_Writer_InsituStringStream >(); +} + +TEST_F(Misc, itoa_sprintf) { + size_t length = 0; + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + length += sprintf(buffer, "%d", randval[j]); + } + } + OUTPUT_LENGTH(length); +} + +TEST_F(Misc, itoa64_sprintf) { + size_t length = 0; + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + length += sprintf(buffer, "%" PRIi64, randval[j] * randval[j]); + } + } + OUTPUT_LENGTH(length); +} + +TEST_F(Misc, itoa_strtk) { + size_t length = 0; + std::string s; + s.reserve(32); + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + s = strtk::type_to_string(randval[j]); + length += s.size(); + } + } + OUTPUT_LENGTH(length); +} + +TEST_F(Misc, itoa64_strtk) { + size_t length = 0; + std::string s; + s.reserve(32); + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + int64_t x = randval[j] * randval[j]; + s = strtk::type_to_string(x); + length += s.size(); + } + } + OUTPUT_LENGTH(length); +} + +TEST_F(Misc, itoa_cppformat) { + size_t length = 0; + char buffer[32]; + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + char* p = buffer; + fmt::FormatDec(p, randval[j]); + length += (p - buffer); + } + } + OUTPUT_LENGTH(length); +} + +TEST_F(Misc, itoa64_cppformat) { + size_t length = 0; + char buffer[32]; + for (int i = 0; i < kItoaTrialCount; i++) { + for (int j = 0; j < randvalCount; j++) { + char* p = buffer; + int64_t x = randval[j] * randval[j]; + fmt::FormatDec(p, x); + length += (p - buffer); + } + } + OUTPUT_LENGTH(length); +} + +#endif // TEST_MISC diff --git a/thirdparty/cppformat/format.cc b/thirdparty/cppformat/format.cc new file mode 100644 index 000000000..895a79613 --- /dev/null +++ b/thirdparty/cppformat/format.cc @@ -0,0 +1,1202 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2014, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// Disable useless MSVC warnings. +#undef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#undef _SCL_SECURE_NO_WARNINGS +#define _SCL_SECURE_NO_WARNINGS + +#include "format.h" + +#include + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# ifdef __MINGW32__ +# include +# endif +# include +# undef ERROR +#endif + +using fmt::LongLong; +using fmt::ULongLong; +using fmt::internal::Arg; + +#if _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +#endif + +namespace { + +#ifndef _MSC_VER + +inline int SignBit(double value) { + // When compiled in C++11 mode signbit is no longer a macro but a function + // defined in namespace std and the macro is undefined. +#ifdef signbit + return signbit(value); +#else + return std::signbit(value); +#endif +} + +inline int IsInf(double x) { +#ifdef isinf + return isinf(x); +#else + return std::isinf(x); +#endif +} + +#define FMT_SNPRINTF snprintf + +#else // _MSC_VER + +inline int SignBit(double value) { + if (value < 0) return 1; + if (value == value) return 0; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); + return sign; +} + +inline int IsInf(double x) { return !_finite(x); } + +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; +} + +#endif // _MSC_VER + +const char RESET_COLOR[] = "\x1b[0m"; + +typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef); + +void ReportError(FormatFunc func, + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { + try { + fmt::Writer full_message; + func(full_message, error_code, message); // TODO: make sure this doesn't throw + std::fwrite(full_message.c_str(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); + } catch (...) {} +} + +const Arg DUMMY_ARG = {Arg::INT, 0}; + +fmt::ULongLong GetIntValue(const Arg &arg) { + switch (arg.type) { + case Arg::INT: + return arg.int_value; + case Arg::UINT: + return arg.uint_value; + case Arg::LONG_LONG: + return arg.long_long_value; + case Arg::ULONG_LONG: + return arg.ulong_long_value; + default: + return -1; + } +} + +// Parses an unsigned integer advancing s to the end of the parsed input. +// This function assumes that the first character of s is a digit. +template +int ParseNonnegativeInt(const Char *&s, const char *&error) FMT_NOEXCEPT(true) { + assert('0' <= *s && *s <= '9'); + unsigned value = 0; + do { + unsigned new_value = value * 10 + (*s++ - '0'); + // Check if value wrapped around. + value = new_value >= value ? new_value : UINT_MAX; + } while ('0' <= *s && *s <= '9'); + if (value > INT_MAX) { + if (!error) + error = "number is too big in format"; + return 0; + } + return value; +} + +template +const Char *find_closing_brace(const Char *s, int num_open_braces = 1) { + for (int n = num_open_braces; *s; ++s) { + if (*s == '{') { + ++n; + } else if (*s == '}') { + if (--n == 0) + return s; + } + } + throw fmt::FormatError("unmatched '{' in format"); +} + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +struct WidthHandler : public fmt::internal::ArgVisitor { + private: + fmt::FormatSpec &spec_; + + public: + explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} + + ULongLong visit_unhandled_arg() { + throw fmt::FormatError("width is not integer"); + } + + ULongLong visit_any_int(fmt::LongLong value) { + ULongLong width = value; + if (value < 0) { + spec_.align_ = fmt::ALIGN_LEFT; + width = 0 - width; + } + return width; + } + + ULongLong visit_any_uint(ULongLong value) { return value; } +}; + +// This function template is used to prevent compile errors when handling +// incompatible string arguments, e.g. handling a wide string in a narrow +// string formatter. +template +Arg::StringValue ignore_incompatible_str(Arg::StringValue); + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue) { return Arg::StringValue(); } + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue s) { return s; } +} // namespace + +int fmt::internal::SignBitNoInline(double value) { return SignBit(value); } + +void fmt::SystemError::init( + int error_code, StringRef format_str, const ArgList &args) { + error_code_ = error_code; + Writer w; + internal::FormatSystemErrorMessage(w, error_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +template +int fmt::internal::CharTraits::FormatFloat( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, width, value) : + FMT_SNPRINTF(buffer, size, format, width, precision, value); +} + +template +int fmt::internal::CharTraits::FormatFloat( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + swprintf(buffer, size, format, value) : + swprintf(buffer, size, format, precision, value); + } + return precision < 0 ? + swprintf(buffer, size, format, width, value) : + swprintf(buffer, size, format, width, precision, value); +} + +const char fmt::internal::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)}; +const uint64_t fmt::internal::POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(ULongLong(1000000000)), + // Multiply several constants instead of using a single long long constants + // to avoid warnings about C++98 not supporting long long. + ULongLong(1000000000) * ULongLong(1000000000) * 10 +}; + +void fmt::internal::ReportUnknownType(char code, const char *type) { + if (std::isprint(static_cast(code))) { + throw fmt::FormatError( + fmt::format("unknown format code '{}' for {}", code, type)); + } + throw fmt::FormatError( + fmt::format("unknown format code '\\x{:02x}' for {}", + static_cast(code), type)); +} + +#ifdef _WIN32 + +fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); + static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; + if (length == 0) + throw WindowsError(GetLastError(), ERROR); + buffer_.resize(length); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); + if (length == 0) + throw WindowsError(GetLastError(), ERROR); +} + +fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { + if (int error_code = Convert(s)) { + throw WindowsError(error_code, + "cannot convert string from UTF-16 to UTF-8"); + } +} + +int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) { + int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); + if (length == 0) + return GetLastError(); + buffer_.resize(length); + length = WideCharToMultiByte( + CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); + if (length == 0) + return GetLastError(); + return 0; +} + +void fmt::WindowsError::init( + int error_code, StringRef format_str, const ArgList &args) { + error_code_ = error_code; + Writer w; + internal::FormatWinErrorMessage(w, error_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +#endif + +int fmt::internal::StrError( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) { + assert(buffer != 0 && buffer_size != 0); + int result = 0; +#ifdef _GNU_SOURCE + char *message = strerror_r(error_code, buffer, buffer_size); + // If the buffer is full then the message is probably truncated. + if (message == buffer && strlen(buffer) == buffer_size - 1) + result = ERANGE; + buffer = message; +#elif __MINGW32__ + errno = 0; + (void)buffer_size; + buffer = strerror(error_code); + result = errno; +#elif _WIN32 + result = strerror_s(buffer, buffer_size, error_code); + // If the buffer is full then the message is probably truncated. + if (result == 0 && std::strlen(buffer) == buffer_size - 1) + result = ERANGE; +#else + result = strerror_r(error_code, buffer, buffer_size); + if (result == -1) + result = errno; // glibc versions before 2.13 return result in errno. +#endif + return result; +} + +void fmt::internal::FormatSystemErrorMessage( + fmt::Writer &out, int error_code, fmt::StringRef message) { + Array buffer; + buffer.resize(INLINE_BUFFER_SIZE); + char *system_message = 0; + for (;;) { + system_message = &buffer[0]; + int result = StrError(error_code, system_message, buffer.size()); + if (result == 0) + break; + if (result != ERANGE) { + // Can't get error message, report error code instead. + out << message << ": error code = " << error_code; + return; + } + buffer.resize(buffer.size() * 2); + } + out << message << ": " << system_message; +} + +#ifdef _WIN32 +void fmt::internal::FormatWinErrorMessage( + fmt::Writer &out, int error_code, fmt::StringRef message) { + class String { + private: + LPWSTR str_; + + public: + String() : str_() {} + ~String() { LocalFree(str_); } + LPWSTR *ptr() { return &str_; } + LPCWSTR c_str() const { return str_; } + }; + String system_message; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(system_message.ptr()), 0, 0)) { + UTF16ToUTF8 utf8_message; + if (!utf8_message.Convert(system_message.c_str())) { + out << message << ": " << utf8_message; + return; + } + } + // Can't get error message, report error code instead. + out << message << ": error code = " << error_code; +} +#endif + +// An argument formatter. +template +class fmt::internal::ArgFormatter : + public fmt::internal::ArgVisitor, void> { + private: + fmt::BasicWriter &writer_; + fmt::FormatSpec &spec_; + const Char *format_; + + public: + ArgFormatter(fmt::BasicWriter &w, fmt::FormatSpec &s, const Char *fmt) + : writer_(w), spec_(s), format_(fmt) {} + + void visit_int(int value) { + writer_.FormatInt(value, spec_); + } + void visit_uint(unsigned value) { + writer_.FormatInt(value, spec_); + } + void visit_long_long(LongLong value) { + writer_.FormatInt(value, spec_); + } + void visit_ulong_long(ULongLong value) { + writer_.FormatInt(value, spec_); + } + void visit_double(double value) { + writer_.FormatDouble(value, spec_); + } + void visit_long_double(long double value) { + writer_.FormatDouble(value, spec_); + } + + void visit_char(int value) { + if (spec_.type_ && spec_.type_ != 'c') + fmt::internal::ReportUnknownType(spec_.type_, "char"); + typedef typename fmt::BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (spec_.width_ > 1) { + Char fill = static_cast(spec_.fill()); + out = writer_.GrowBuffer(spec_.width_); + if (spec_.align_ == fmt::ALIGN_RIGHT) { + std::fill_n(out, spec_.width_ - 1, fill); + out += spec_.width_ - 1; + } else if (spec_.align_ == fmt::ALIGN_CENTER) { + out = writer_.FillPadding(out, spec_.width_, 1, fill); + } else { + std::fill_n(out + 1, spec_.width_ - 1, fill); + } + } else { + out = writer_.GrowBuffer(1); + } + *out = static_cast(value); + } + + void visit_string(Arg::StringValue value) { + writer_.write_str(value, spec_); + } + void visit_wstring(Arg::StringValue value) { + writer_.write_str(ignore_incompatible_str(value), spec_); + } + + void visit_pointer(const void *value) { + if (spec_.type_ && spec_.type_ != 'p') + fmt::internal::ReportUnknownType(spec_.type_, "pointer"); + spec_.flags_ = fmt::HASH_FLAG; + spec_.type_ = 'x'; + writer_.FormatInt(reinterpret_cast(value), spec_); + } + + void visit_custom(Arg::CustomValue c) { + c.format(this, c.value, format_); + } +}; + +template +void fmt::internal::FormatErrorReporter::operator()( + const Char *s, fmt::StringRef message) const { + if (find_closing_brace(s, num_open_braces)) + throw fmt::FormatError(message); +} + +// Fills the padding around the content and returns the pointer to the +// content area. +template +typename fmt::BasicWriter::CharPtr + fmt::BasicWriter::FillPadding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill) { + std::size_t padding = total_size - content_size; + std::size_t left_padding = padding / 2; + Char fill_char = static_cast(fill); + std::fill_n(buffer, left_padding, fill_char); + buffer += left_padding; + CharPtr content = buffer; + std::fill_n(buffer + content_size, padding - left_padding, fill_char); + return content; +} + +template +template +void fmt::BasicWriter::FormatDouble(T value, const FormatSpec &spec) { + // Check type. + char type = spec.type(); + bool upper = false; + switch (type) { + case 0: + type = 'g'; + break; + case 'e': case 'f': case 'g': case 'a': + break; + case 'F': +#ifdef _MSC_VER + // MSVC's printf doesn't support 'F'. + type = 'f'; +#endif + // Fall through. + case 'E': case 'G': case 'A': + upper = true; + break; + default: + internal::ReportUnknownType(type, "double"); + break; + } + + char sign = 0; + // Use SignBit instead of value < 0 because the latter is always + // false for NaN. + if (SignBit(static_cast(value))) { + sign = '-'; + value = -value; + } else if (spec.sign_flag()) { + sign = spec.plus_flag() ? '+' : ' '; + } + + if (value != value) { + // Format NaN ourselves because sprintf's output is not consistent + // across platforms. + std::size_t size = 4; + const char *nan = upper ? " NAN" : " nan"; + if (!sign) { + --size; + ++nan; + } + CharPtr out = write_str(nan, size, spec); + if (sign) + *out = sign; + return; + } + + if (IsInf(static_cast(value))) { + // Format infinity ourselves because sprintf's output is not consistent + // across platforms. + std::size_t size = 4; + const char *inf = upper ? " INF" : " inf"; + if (!sign) { + --size; + ++inf; + } + CharPtr out = write_str(inf, size, spec); + if (sign) + *out = sign; + return; + } + + std::size_t offset = buffer_.size(); + unsigned width = spec.width(); + if (sign) { + buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); + if (width > 0) + --width; + ++offset; + } + + // Build format string. + enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg + Char format[MAX_FORMAT_SIZE]; + Char *format_ptr = format; + *format_ptr++ = '%'; + unsigned width_for_sprintf = width; + if (spec.hash_flag()) + *format_ptr++ = '#'; + if (spec.align() == ALIGN_CENTER) { + width_for_sprintf = 0; + } else { + if (spec.align() == ALIGN_LEFT) + *format_ptr++ = '-'; + if (width != 0) + *format_ptr++ = '*'; + } + if (spec.precision() >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (internal::IsLongDouble::VALUE) + *format_ptr++ = 'L'; + *format_ptr++ = type; + *format_ptr = '\0'; + + // Format using snprintf. + Char fill = static_cast(spec.fill()); + for (;;) { + std::size_t size = buffer_.capacity() - offset; +#if _MSC_VER + // MSVC's vsnprintf_s doesn't work with zero size, so reserve + // space for at least one extra character to make the size non-zero. + // Note that the buffer's capacity will increase by more than 1. + if (size == 0) { + buffer_.reserve(offset + 1); + size = buffer_.capacity() - offset; + } +#endif + Char *start = &buffer_[offset]; + int n = internal::CharTraits::FormatFloat( + start, size, format, width_for_sprintf, spec.precision(), value); + if (n >= 0 && offset + n < buffer_.capacity()) { + if (sign) { + if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || + *start != ' ') { + *(start - 1) = sign; + sign = 0; + } else { + *(start - 1) = fill; + } + ++n; + } + if (spec.align() == ALIGN_CENTER && + spec.width() > static_cast(n)) { + unsigned width = spec.width(); + CharPtr p = GrowBuffer(width); + std::copy(p, p + n, p + (width - n) / 2); + FillPadding(p, spec.width(), n, fill); + return; + } + if (spec.fill() != ' ' || sign) { + while (*start == ' ') + *start++ = fill; + if (sign) + *(start - 1) = sign; + } + GrowBuffer(n); + return; + } + // If n is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); + } +} + +template +template +void fmt::BasicWriter::write_str( + const Arg::StringValue &str, const FormatSpec &spec) { + // Check if StringChar is convertible to Char. + internal::CharTraits::convert(StringChar()); + if (spec.type_ && spec.type_ != 's') + internal::ReportUnknownType(spec.type_, "string"); + const StringChar *s = str.value; + std::size_t size = str.size; + if (size == 0) { + if (!s) + throw FormatError("string pointer is null"); + if (*s) + size = std::char_traits::length(s); + } + write_str(s, size, spec); +} + +template +inline const Arg + &fmt::BasicFormatter::ParseArgIndex(const Char *&s) { + unsigned arg_index = 0; + if (*s < '0' || *s > '9') { + if (*s != '}' && *s != ':') + report_error_(s, "invalid argument index in format string"); + if (next_arg_index_ < 0) { + report_error_(s, + "cannot switch from manual to automatic argument indexing"); + } + arg_index = next_arg_index_++; + } else { + if (next_arg_index_ > 0) { + report_error_(s, + "cannot switch from automatic to manual argument indexing"); + } + next_arg_index_ = -1; + const char *error = 0; + arg_index = ParseNonnegativeInt(s, error); + if (error) + report_error_(s, error); // TODO + } + if (arg_index >= args_.size()) + report_error_(s, "argument index is out of range in format"); + return args_[arg_index]; +} + +template +void fmt::BasicFormatter::CheckSign( + const Char *&s, const Arg &arg) { + char sign = static_cast(*s); + if (arg.type > Arg::LAST_NUMERIC_TYPE) { + report_error_(s, + fmt::format("format specifier '{}' requires numeric argument", sign).c_str()); + } + if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { + report_error_(s, + fmt::format("format specifier '{}' requires signed argument", sign).c_str()); + } + ++s; +} + +template +void fmt::internal::PrintfParser::ParseFlags( + FormatSpec &spec, const Char *&s) { + for (;;) { + switch (*s++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags_ |= SIGN_FLAG; + break; + case '#': + spec.flags_ |= HASH_FLAG; + break; + default: + --s; + return; + } + } +} + +template +unsigned fmt::internal::PrintfParser::ParseHeader( + const Char *&s, FormatSpec &spec, const char *&error) { + unsigned arg_index = UINT_MAX; + Char c = *s; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + unsigned value = ParseNonnegativeInt(s, error); + if (*s == '$') { // value is an argument index + ++s; + arg_index = value; + } else { + if (c == '0') + spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + ParseFlags(spec, s); + // Parse width. + if (*s >= '0' && *s <= '9') { + spec.width_ = ParseNonnegativeInt(s, error); + } else if (*s == '*') { + ++s; + ULongLong width = WidthHandler(spec).visit(HandleArgIndex(UINT_MAX, error)); + if (width <= INT_MAX) + spec.width_ = static_cast(width); + else if (!error) + error = "number is too big in format"; + } + return arg_index; +} + +// TODO: move to a base class that doesn't depend on template argument +template +const Arg &fmt::internal::PrintfParser::HandleArgIndex( + unsigned arg_index, const char *&error) { + if (arg_index != UINT_MAX) { + if (next_arg_index_ <= 0) { + next_arg_index_ = -1; + --arg_index; + } else if (!error) { + error = "cannot switch from automatic to manual argument indexing"; + } + } else if (next_arg_index_ >= 0) { + arg_index = next_arg_index_++; + } else if (!error) { + error = "cannot switch from manual to automatic argument indexing"; + } + if (arg_index < args_.size()) + return args_[arg_index]; + if (!error) + error = "argument index is out of range in format"; + return DUMMY_ARG; +} + +template +void fmt::internal::PrintfParser::Format( + BasicWriter &writer, BasicStringRef format, + const ArgList &args) { + const Char *start = format.c_str(); + args_ = args; + next_arg_index_ = 0; + const Char *s = start; + while (*s) { + Char c = *s++; + if (c != '%') continue; + if (*s == c) { + writer.buffer_.append(start, s); + start = ++s; + continue; + } + writer.buffer_.append(start, s - 1); + + FormatSpec spec; + spec.align_ = ALIGN_RIGHT; + + // Reporting errors is delayed till the format specification is + // completely parsed. This is done to avoid potentially confusing + // error messages for incomplete format strings. For example, in + // sprintf("%2$", 42); + // the format specification is incomplete. In naive approach we + // would parse 2 as an argument index and report an error that the + // index is out of range which would be rather confusing if the + // use meant "%2d$" rather than "%2$d". If we delay an error, the + // user will get an error that the format string is invalid which + // is OK for both cases. + const char *error = 0; + + // Parse argument index, flags and width. + unsigned arg_index = ParseHeader(s, spec, error); + + // Parse precision. + if (*s == '.') { + ++s; + if ('0' <= *s && *s <= '9') { + spec.precision_ = ParseNonnegativeInt(s, error); + } else if (*s == '*') { + ++s; + const Arg &arg = HandleArgIndex(UINT_MAX, error); + if (arg.type <= Arg::LAST_INTEGER_TYPE) + spec.precision_ = static_cast(GetIntValue(arg)); // TODO: check for overflow + else if (!error) + error = "precision is not integer"; + } + } + + const Arg &arg = HandleArgIndex(arg_index, error); + if (spec.hash_flag() && GetIntValue(arg) == 0) + spec.flags_ &= ~HASH_FLAG; + if (spec.fill_ == '0') { + if (arg.type <= Arg::LAST_NUMERIC_TYPE) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. + } + + // Parse length. + switch (*s) { + case 'h': + // TODO: convert to short + case 'l': + case 'j': + case 'z': + case 't': + case 'L': + // TODO: handle length + ++s; + break; + } + + // Parse type. + if (!*s) + throw FormatError("invalid format string"); + if (error) + throw FormatError(error); + spec.type_ = static_cast(*s++); + + start = s; + + // Format argument. + switch (arg.type) { + case Arg::INT: + writer.FormatInt(arg.int_value, spec); + break; + case Arg::UINT: + writer.FormatInt(arg.uint_value, spec); + break; + case Arg::LONG_LONG: + writer.FormatInt(arg.long_long_value, spec); + break; + case Arg::ULONG_LONG: + writer.FormatInt(arg.ulong_long_value, spec); + break; + case Arg::DOUBLE: + writer.FormatDouble(arg.double_value, spec); + break; + case Arg::LONG_DOUBLE: + writer.FormatDouble(arg.long_double_value, spec); + break; + case Arg::CHAR: { + if (spec.type_ && spec.type_ != 'c') + internal::ReportUnknownType(spec.type_, "char"); + typedef typename BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (spec.width_ > 1) { + Char fill = static_cast(spec.fill()); + out = writer.GrowBuffer(spec.width_); + if (spec.align_ == ALIGN_RIGHT) { + std::fill_n(out, spec.width_ - 1, fill); + out += spec.width_ - 1; + } else if (spec.align_ == ALIGN_CENTER) { + out = writer.FillPadding(out, spec.width_, 1, fill); + } else { + std::fill_n(out + 1, spec.width_ - 1, fill); + } + } else { + out = writer.GrowBuffer(1); + } + *out = static_cast(arg.int_value); + break; + } + case Arg::STRING: + writer.write_str(arg.string, spec); + break; + case Arg::WSTRING: + writer.write_str(ignore_incompatible_str(arg.wstring), spec); + break; + case Arg::POINTER: + if (spec.type_ && spec.type_ != 'p') + internal::ReportUnknownType(spec.type_, "pointer"); + spec.flags_= HASH_FLAG; + spec.type_ = 'x'; + writer.FormatInt(reinterpret_cast(arg.pointer_value), spec); + break; + case Arg::CUSTOM: + if (spec.type_) + internal::ReportUnknownType(spec.type_, "object"); + arg.custom.format(&writer, arg.custom.value, "s"); + break; + default: + assert(false); + break; + } + } + writer.buffer_.append(start, s); +} + +template +const Char *fmt::BasicFormatter::format( + const Char *format_str, const Arg &arg) { + const Char *s = format_str; + const char *error = 0; + FormatSpec spec; + if (*s == ':') { + if (arg.type == Arg::CUSTOM) { + arg.custom.format(this, arg.custom.value, s); + return find_closing_brace(s) + 1; + } + ++s; + // Parse fill and alignment. + if (Char c = *s) { + const Char *p = s + 1; + spec.align_ = ALIGN_DEFAULT; + do { + switch (*p) { + case '<': + spec.align_ = ALIGN_LEFT; + break; + case '>': + spec.align_ = ALIGN_RIGHT; + break; + case '=': + spec.align_ = ALIGN_NUMERIC; + break; + case '^': + spec.align_ = ALIGN_CENTER; + break; + } + if (spec.align_ != ALIGN_DEFAULT) { + if (p != s) { + if (c == '}') break; + if (c == '{') + report_error_(s, "invalid fill character '{'"); + s += 2; + spec.fill_ = c; + } else ++s; + if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE) + report_error_(s, "format specifier '=' requires numeric argument"); + break; + } + } while (--p >= s); + } + + // Parse sign. + switch (*s) { + case '+': + CheckSign(s, arg); + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '-': + CheckSign(s, arg); + break; + case ' ': + CheckSign(s, arg); + spec.flags_ |= SIGN_FLAG; + break; + } + + if (*s == '#') { + if (arg.type > Arg::LAST_NUMERIC_TYPE) + report_error_(s, "format specifier '#' requires numeric argument"); + spec.flags_ |= HASH_FLAG; + ++s; + } + + // Parse width and zero flag. + if ('0' <= *s && *s <= '9') { + if (*s == '0') { + if (arg.type > Arg::LAST_NUMERIC_TYPE) + report_error_(s, "format specifier '0' requires numeric argument"); + spec.align_ = ALIGN_NUMERIC; + spec.fill_ = '0'; + } + // Zero may be parsed again as a part of the width, but it is simpler + // and more efficient than checking if the next char is a digit. + spec.width_ = ParseNonnegativeInt(s, error); + if (error) + report_error_(s, error); + } + + // Parse precision. + if (*s == '.') { + ++s; + spec.precision_ = 0; + if ('0' <= *s && *s <= '9') { + spec.precision_ = ParseNonnegativeInt(s, error); + if (error) + report_error_(s, error); + } else if (*s == '{') { + ++s; + ++report_error_.num_open_braces; + const Arg &precision_arg = ParseArgIndex(s); + ULongLong value = 0; + switch (precision_arg.type) { + case Arg::INT: + if (precision_arg.int_value < 0) + report_error_(s, "negative precision in format"); + value = precision_arg.int_value; + break; + case Arg::UINT: + value = precision_arg.uint_value; + break; + case Arg::LONG_LONG: + if (precision_arg.long_long_value < 0) + report_error_(s, "negative precision in format"); + value = precision_arg.long_long_value; + break; + case Arg::ULONG_LONG: + value = precision_arg.ulong_long_value; + break; + default: + report_error_(s, "precision is not integer"); + } + if (value > INT_MAX) + report_error_(s, "number is too big in format"); + spec.precision_ = static_cast(value); + if (*s++ != '}') + throw FormatError("unmatched '{' in format"); + --report_error_.num_open_braces; + } else { + report_error_(s, "missing precision in format"); + } + if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) { + report_error_(s, + "precision specifier requires floating-point argument"); + } + } + + // Parse type. + if (*s != '}' && *s) + spec.type_ = static_cast(*s++); + } + + if (*s++ != '}') + throw FormatError("unmatched '{' in format"); + start_ = s; + + // Format argument. + internal::ArgFormatter(writer_, spec, s - 1).visit(arg); + return s; +} + +template +void fmt::BasicFormatter::Format( + BasicStringRef format_str, const ArgList &args) { + const Char *s = start_ = format_str.c_str(); + args_ = args; + next_arg_index_ = 0; + while (*s) { + Char c = *s++; + if (c != '{' && c != '}') continue; + if (*s == c) { + writer_.buffer_.append(start_, s); + start_ = ++s; + continue; + } + if (c == '}') + throw FormatError("unmatched '}' in format"); + report_error_.num_open_braces = 1; + writer_.buffer_.append(start_, s - 1); + Arg arg = ParseArgIndex(s); + s = format(s, arg); + } + writer_.buffer_.append(start_, s); +} + +void fmt::ReportSystemError( + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { + // FIXME: FormatSystemErrorMessage may throw + ReportError(internal::FormatSystemErrorMessage, error_code, message); +} + +#ifdef _WIN32 +void fmt::ReportWinError( + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { + // FIXME: FormatWinErrorMessage may throw + ReportError(internal::FormatWinErrorMessage, error_code, message); +} +#endif + +void fmt::print(StringRef format, const ArgList &args) { + Writer w; + w.write(format, args); + std::fwrite(w.data(), 1, w.size(), stdout); +} + +void fmt::print(std::FILE *f, StringRef format, const ArgList &args) { + Writer w; + w.write(format, args); + std::fwrite(w.data(), 1, w.size(), f); +} + +void fmt::print(std::ostream &os, StringRef format, const ArgList &args) { + Writer w; + w.write(format, args); + os.write(w.data(), w.size()); +} + +void fmt::print_colored(Color c, StringRef format, const ArgList &args) { + char escape[] = "\x1b[30m"; + escape[3] = '0' + static_cast(c); + std::fputs(escape, stdout); + print(format, args); + std::fputs(RESET_COLOR, stdout); +} + +void fmt::printf(StringRef format, const ArgList &args) { + Writer w; + printf(w, format, args); + std::fwrite(w.data(), 1, w.size(), stdout); +} + +// Explicit instantiations for char. + +template fmt::BasicWriter::CharPtr + fmt::BasicWriter::FillPadding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill); + +template void fmt::BasicFormatter::Format( + BasicStringRef format, const ArgList &args); + +template void fmt::internal::PrintfParser::Format( + BasicWriter &writer, BasicStringRef format, const ArgList &args); + +// Explicit instantiations for wchar_t. + +template fmt::BasicWriter::CharPtr + fmt::BasicWriter::FillPadding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill); + +template void fmt::BasicFormatter::Format( + BasicStringRef format, const ArgList &args); + +template void fmt::internal::PrintfParser::Format( + BasicWriter &writer, BasicStringRef format, + const ArgList &args); + +#if _MSC_VER +# pragma warning(pop) +#endif diff --git a/thirdparty/cppformat/format.h b/thirdparty/cppformat/format.h new file mode 100644 index 000000000..6a30dbac1 --- /dev/null +++ b/thirdparty/cppformat/format.h @@ -0,0 +1,2019 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2014, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include + +#include +#include // for std::ptrdiff_t +#include +#include +#include +#include +#include +#include + +#if _SECURE_SCL +# include +#endif + +#ifdef __GNUC__ +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FMT_GCC_EXTENSION __extension__ +// Disable warning about "long long" which is sometimes reported even +// when using __extension__. +# if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +#else +# define FMT_GCC_EXTENSION +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifndef FMT_USE_VARIADIC_TEMPLATES +// Variadic templates are available in GCC since version 4.4 +// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ +// since version 2013. +# define FMT_USE_VARIADIC_TEMPLATES \ + (FMT_HAS_FEATURE(cxx_variadic_templates) || \ + (FMT_GCC_VERSION >= 404 && __cplusplus >= 201103) || _MSC_VER >= 1800) +#endif + +#ifndef FMT_USE_RVALUE_REFERENCES +// Don't use rvalue references when compiling with clang and an old libstdc++ +// as the latter doesn't provide std::move. +# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 +# define FMT_USE_RVALUE_REFERENCES 0 +# else +# define FMT_USE_RVALUE_REFERENCES \ + (FMT_HAS_FEATURE(cxx_rvalue_references) || \ + (FMT_GCC_VERSION >= 403 && __cplusplus >= 201103) || _MSC_VER >= 1600) +# endif +#endif + +#if FMT_USE_RVALUE_REFERENCES +# include // for std::move +#endif + +// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && __cplusplus >= 201103) +# define FMT_NOEXCEPT(expr) noexcept(expr) +#else +# define FMT_NOEXCEPT(expr) +#endif + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +namespace fmt { + +// Fix the warning about long long on older versions of GCC +// that don't support the diagnostic pragma. +FMT_GCC_EXTENSION typedef long long LongLong; +FMT_GCC_EXTENSION typedef unsigned long long ULongLong; + +#if FMT_USE_RVALUE_REFERENCES +using std::move; +#endif + +template +class BasicWriter; + +typedef BasicWriter Writer; +typedef BasicWriter WWriter; + +template +class BasicFormatter; + +template +void format(BasicFormatter &f, const Char *format_str, const T &value); + +/** + \rst + A string reference. It can be constructed from a C string or + ``std::string``. + + You can use one of the following typedefs for common character types: + + +------------+-------------------------+ + | Type | Definition | + +============+=========================+ + | StringRef | BasicStringRef | + +------------+-------------------------+ + | WStringRef | BasicStringRef | + +------------+-------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template + std::string format(StringRef format, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template +class BasicStringRef { + private: + const Char *data_; + mutable std::size_t size_; + + public: + /** + Constructs a string reference object from a C string and a size. + If *size* is zero, which is the default, the size is computed + automatically. + */ + BasicStringRef(const Char *s, std::size_t size = 0) : data_(s), size_(size) {} + + /** + Constructs a string reference from an `std::string` object. + */ + BasicStringRef(const std::basic_string &s) + : data_(s.c_str()), size_(s.size()) {} + + /** + Converts a string reference to an `std::string` object. + */ + operator std::basic_string() const { + return std::basic_string(data_, size()); + } + + /** + Returns the pointer to a C string. + */ + const Char *c_str() const { return data_; } + + /** + Returns the string size. + */ + std::size_t size() const { + if (size_ == 0 && data_) size_ = std::char_traits::length(data_); + return size_; + } + + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.data_ == rhs.data_; + } + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.data_ != rhs.data_; + } +}; + +typedef BasicStringRef StringRef; +typedef BasicStringRef WStringRef; + +/** + A formatting error such as invalid format string. +*/ +class FormatError : public std::runtime_error { +public: + explicit FormatError(const std::string &message) + : std::runtime_error(message) {} +}; + +namespace internal { + +// The number of characters to store in the Array object, representing the +// output buffer, itself to avoid dynamic memory allocation. +enum { INLINE_BUFFER_SIZE = 500 }; + +#if _SECURE_SCL +// Use checked iterator to avoid warnings on MSVC. +template +inline stdext::checked_array_iterator CheckPtr(T *ptr, std::size_t size) { + return stdext::checked_array_iterator(ptr, size); +} +#else +template +inline T *CheckPtr(T *ptr, std::size_t) { return ptr; } +#endif + +// A simple array for POD types with the first SIZE elements stored in +// the object itself. It supports a subset of std::vector's operations. +template +class Array { + private: + std::size_t size_; + std::size_t capacity_; + T *ptr_; + T data_[SIZE]; + + void grow(std::size_t size); + + // Free memory allocated by the array. + void free() { + if (ptr_ != data_) delete [] ptr_; + } + + // Move data from other to this array. + void move(Array &other) { + size_ = other.size_; + capacity_ = other.capacity_; + if (other.ptr_ == other.data_) { + ptr_ = data_; + std::copy(other.data_, other.data_ + size_, CheckPtr(data_, capacity_)); + } else { + ptr_ = other.ptr_; + // Set pointer to the inline array so that delete is not called + // when freeing. + other.ptr_ = other.data_; + } + } + + FMT_DISALLOW_COPY_AND_ASSIGN(Array); + + public: + Array() : size_(0), capacity_(SIZE), ptr_(data_) {} + ~Array() { free(); } + +#if FMT_USE_RVALUE_REFERENCES + Array(Array &&other) { + move(other); + } + + Array& operator=(Array &&other) { + assert(this != &other); + free(); + move(other); + return *this; + } +#endif + + // Returns the size of this array. + std::size_t size() const { return size_; } + + // Returns the capacity of this array. + std::size_t capacity() const { return capacity_; } + + // Resizes the array. If T is a POD type new elements are not initialized. + void resize(std::size_t new_size) { + if (new_size > capacity_) + grow(new_size); + size_ = new_size; + } + + // Reserves space to store at least capacity elements. + void reserve(std::size_t capacity) { + if (capacity > capacity_) + grow(capacity); + } + + void clear() { size_ = 0; } + + void push_back(const T &value) { + if (size_ == capacity_) + grow(size_ + 1); + ptr_[size_++] = value; + } + + // Appends data to the end of the array. + void append(const T *begin, const T *end); + + T &operator[](std::size_t index) { return ptr_[index]; } + const T &operator[](std::size_t index) const { return ptr_[index]; } +}; + +template +void Array::grow(std::size_t size) { + capacity_ = (std::max)(size, capacity_ + capacity_ / 2); + T *p = new T[capacity_]; + std::copy(ptr_, ptr_ + size_, CheckPtr(p, capacity_)); + if (ptr_ != data_) + delete [] ptr_; + ptr_ = p; +} + +template +void Array::append(const T *begin, const T *end) { + std::ptrdiff_t num_elements = end - begin; + if (size_ + num_elements > capacity_) + grow(size_ + num_elements); + std::copy(begin, end, CheckPtr(ptr_, capacity_) + size_); + size_ += num_elements; +} + +template +class BasicCharTraits { + public: +#if _SECURE_SCL + typedef stdext::checked_array_iterator CharPtr; +#else + typedef Char *CharPtr; +#endif +}; + +template +class CharTraits; + +template <> +class CharTraits : public BasicCharTraits { + private: + // Conversion from wchar_t to char is not allowed. + static char convert(wchar_t); + +public: + typedef const wchar_t *UnsupportedStrType; + + static char convert(char value) { return value; } + + template + static int FormatFloat(char *buffer, std::size_t size, + const char *format, unsigned width, int precision, T value); +}; + +template <> +class CharTraits : public BasicCharTraits { + public: + typedef const char *UnsupportedStrType; + + static wchar_t convert(char value) { return value; } + static wchar_t convert(wchar_t value) { return value; } + + template + static int FormatFloat(wchar_t *buffer, std::size_t size, + const wchar_t *format, unsigned width, int precision, T value); +}; + +// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. +template +struct TypeSelector { typedef uint32_t Type; }; + +template <> +struct TypeSelector { typedef uint64_t Type; }; + +// Checks if a number is negative - used to avoid warnings. +template +struct SignChecker { + template + static bool IsNegative(T) { return false; } +}; + +template <> +struct SignChecker { + template + static bool IsNegative(T value) { return value < 0; } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template +inline bool IsNegative(T value) { + return SignChecker::is_signed>::IsNegative(value); +} + +int SignBitNoInline(double value); + +template +struct IntTraits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename + TypeSelector::digits <= 32>::Type MainType; +}; + +template +struct IsLongDouble { enum {VALUE = 0}; }; + +template <> +struct IsLongDouble { enum {VALUE = 1}; }; + +void ReportUnknownType(char code, const char *type); + +extern const uint32_t POWERS_OF_10_32[]; +extern const uint64_t POWERS_OF_10_64[]; + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case CountDigits returns 1. +inline unsigned CountDigits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + uint64_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; + return t - (n < POWERS_OF_10_64[t]) + 1; +} +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +// Optional version of CountDigits for better performance on 32-bit platforms. +inline unsigned CountDigits(uint32_t n) { + uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; + return t - (n < POWERS_OF_10_32[t]) + 1; +} +# endif +#else +// Slower version of CountDigits used when __builtin_clz is not available. +inline unsigned CountDigits(uint64_t n) { + unsigned 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; + } +} +#endif + +extern const char DIGITS[]; + +// Formats a decimal unsigned integer value writing into buffer. +template +void FormatDecimal(Char *buffer, UInt value, unsigned num_digits) { + --num_digits; + 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. + unsigned index = (value % 100) * 2; + value /= 100; + buffer[num_digits] = DIGITS[index + 1]; + buffer[num_digits - 1] = DIGITS[index]; + num_digits -= 2; + } + if (value < 10) { + *buffer = static_cast('0' + value); + return; + } + unsigned index = static_cast(value * 2); + buffer[1] = DIGITS[index + 1]; + buffer[0] = DIGITS[index]; +} + +#ifdef _WIN32 +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems use UTF-8. +class UTF8ToUTF16 { + private: + Array buffer_; + + public: + explicit UTF8ToUTF16(StringRef s); + operator WStringRef() const { return WStringRef(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const wchar_t *c_str() const { return &buffer_[0]; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems use UTF-8. +class UTF16ToUTF8 { + private: + Array buffer_; + + public: + UTF16ToUTF8() {} + explicit UTF16ToUTF8(WStringRef s); + operator StringRef() const { return StringRef(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const char *c_str() const { return &buffer_[0]; } + std::string str() const { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a system error code instead of + // throwing exception on error. + int Convert(WStringRef s); +}; +#endif + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int StrError(int error_code, + char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true); + +void FormatSystemErrorMessage( + fmt::Writer &out, int error_code, fmt::StringRef message); + +#ifdef _WIN32 +void FormatWinErrorMessage( + fmt::Writer &out, int error_code, fmt::StringRef message); +#endif + +struct SimpleErrorReporter { + void operator()(const void *, fmt::StringRef message) const { + throw fmt::FormatError(message); + } +}; + +// Throws Exception(message) if format contains '}', otherwise throws +// FormatError reporting unmatched '{'. The idea is that unmatched '{' +// should override other errors. +template +struct FormatErrorReporter { + int num_open_braces; + void operator()(const Char *s, fmt::StringRef message) const; +}; + +// Computes max(Arg, 1) at compile time. It is used to avoid errors about +// allocating an array of 0 size. +template +struct NonZero { + enum { VALUE = Arg }; +}; + +template <> +struct NonZero<0> { + enum { VALUE = 1 }; +}; + +// A formatting argument. It is a POD type to allow storage in internal::Array. +struct Arg { + enum Type { + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, LAST_INTEGER_TYPE = ULONG_LONG, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + CHAR, STRING, WSTRING, POINTER, CUSTOM + }; + Type type; + + template + struct StringValue { + const Char *value; + std::size_t size; + }; + + typedef void (*FormatFunc)( + void *formatter, const void *arg, const void *format_str); + + struct CustomValue { + const void *value; + FormatFunc format; + }; + + union { + int int_value; + unsigned uint_value; + LongLong long_long_value; + ULongLong ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer_value; + StringValue string; + StringValue wstring; + CustomValue custom; + }; +}; + +// Makes an Arg object from any type. +template +class MakeArg : public Arg { + private: + // The following two methods are private to disallow formatting of + // arbitrary pointers. 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. + // Do not implement! + template + MakeArg(const T *value); + template + MakeArg(T *value); + + void set_string(StringRef str) { + type = STRING; + string.value = str.c_str(); + string.size = str.size(); + } + + void set_string(WStringRef str) { + type = WSTRING; + CharTraits::convert(wchar_t()); + wstring.value = str.c_str(); + wstring.size = str.size(); + } + + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg( + void *formatter, const void *arg, const void *format_str) { + format(*static_cast*>(formatter), + static_cast(format_str), *static_cast(arg)); + } + +public: + MakeArg() {} + MakeArg(bool value) { type = INT; int_value = value; } + MakeArg(short value) { type = INT; int_value = value; } + MakeArg(unsigned short value) { type = UINT; uint_value = value; } + MakeArg(int value) { type = INT; int_value = value; } + MakeArg(unsigned value) { type = UINT; uint_value = value; } + MakeArg(long value) { + // 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. + if (sizeof(long) == sizeof(int)) { + type = INT; + int_value = static_cast(value); + } else { + type = LONG_LONG; + long_long_value = value; + } + } + MakeArg(unsigned long value) { + if (sizeof(unsigned long) == sizeof(unsigned)) { + type = UINT; + uint_value = static_cast(value); + } else { + type = ULONG_LONG; + ulong_long_value = value; + } + } + MakeArg(LongLong value) { type = LONG_LONG; long_long_value = value; } + MakeArg(ULongLong value) { type = ULONG_LONG; ulong_long_value = value; } + MakeArg(float value) { type = DOUBLE; double_value = value; } + MakeArg(double value) { type = DOUBLE; double_value = value; } + MakeArg(long double value) { type = LONG_DOUBLE; long_double_value = value; } + MakeArg(signed char value) { type = CHAR; int_value = value; } + MakeArg(unsigned char value) { type = CHAR; int_value = value; } + MakeArg(char value) { type = CHAR; int_value = value; } + MakeArg(wchar_t value) { + type = CHAR; + int_value = internal::CharTraits::convert(value); + } + + MakeArg(char *value) { set_string(value); } + MakeArg(const char *value) { set_string(value); } + MakeArg(const std::string &value) { set_string(value); } + MakeArg(StringRef value) { set_string(value); } + + MakeArg(wchar_t *value) { set_string(value); } + MakeArg(const wchar_t *value) { set_string(value); } + MakeArg(const std::wstring &value) { set_string(value); } + MakeArg(WStringRef value) { set_string(value); } + + MakeArg(void *value) { type = POINTER; pointer_value = value; } + MakeArg(const void *value) { type = POINTER; pointer_value = value; } + + template + MakeArg(const T &value) { + type = CUSTOM; + custom.value = &value; + custom.format = &format_custom_arg; + } +}; + +#define FMT_DISPATCH(call) static_cast(this)->call + +// An argument visitor. +// To use ArgVisitor define a subclass that implements some or all of the +// visit methods with the same signatures as the methods in ArgVisitor, +// for example, visit_int(int). +// Specify the subclass name as the Impl template parameter. Then calling +// ArgVisitor::visit for some argument will dispatch to a visit method +// specific to the argument type. For example, if the argument type is +// double then visit_double(double) method of a subclass will be called. +// If the subclass doesn't contain a method with this signature, then +// a corresponding method of ArgVisitor will be called. +// +// Example: +// class MyArgVisitor : public ArgVisitor { +// public: +// void visit_int(int value) { print("{}", value); } +// void visit_double(double value) { print("{}", value ); } +// }; +// +// ArgVisitor uses the curiously recurring template pattern: +// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern +template +class ArgVisitor { + public: + Result visit_unhandled_arg() { return Result(); } + + Result visit_int(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_long_long(LongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_any_int(LongLong) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit_uint(unsigned value) { + return FMT_DISPATCH(visit_any_uint(value)); + } + Result visit_ulong_long(ULongLong value) { + return FMT_DISPATCH(visit_any_uint(value)); + } + Result visit_any_uint(ULongLong) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit_double(double) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_long_double(long double) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_char(int) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_string(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_wstring(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_pointer(const void *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_custom(Arg::CustomValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit(const Arg &arg) { + switch (arg.type) { + default: + assert(false); + // Fall through. + case Arg::INT: + return FMT_DISPATCH(visit_int(arg.int_value)); + case Arg::UINT: + return FMT_DISPATCH(visit_uint(arg.uint_value)); + case Arg::LONG_LONG: + return FMT_DISPATCH(visit_long_long(arg.long_long_value)); + case Arg::ULONG_LONG: + return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); + case Arg::DOUBLE: + return FMT_DISPATCH(visit_double(arg.double_value)); + case Arg::LONG_DOUBLE: + return FMT_DISPATCH(visit_long_double(arg.long_double_value)); + case Arg::CHAR: + return FMT_DISPATCH(visit_char(arg.int_value)); + case Arg::STRING: + return FMT_DISPATCH(visit_string(arg.string)); + case Arg::WSTRING: + return FMT_DISPATCH(visit_wstring(arg.wstring)); + case Arg::POINTER: + return FMT_DISPATCH(visit_pointer(arg.pointer_value)); + case Arg::CUSTOM: + return FMT_DISPATCH(visit_custom(arg.custom)); + } + } +}; + +class RuntimeError : public std::runtime_error { + protected: + RuntimeError() : std::runtime_error("") {} +}; + +template +class ArgFormatter; +} // namespace internal + +/** + An argument list. + */ +class ArgList { + private: + const internal::Arg *args_; + std::size_t size_; + + public: + ArgList() : size_(0) {} + ArgList(const internal::Arg *args, std::size_t size) + : args_(args), size_(size) {} + + /** + Returns the list size (the number of arguments). + */ + std::size_t size() const { return size_; } + + /** + Returns the argument at specified index. + */ + const internal::Arg &operator[](std::size_t index) const { + return args_[index]; + } +}; + +struct FormatSpec; + +// A formatter. +template +class BasicFormatter { +private: + BasicWriter &writer_; + ArgList args_; + int next_arg_index_; + const Char *start_; + internal::FormatErrorReporter report_error_; + + // Parses argument index and returns an argument with this index. + const internal::Arg &ParseArgIndex(const Char *&s); + + void CheckSign(const Char *&s, const internal::Arg &arg); + +public: + explicit BasicFormatter(BasicWriter &w) : writer_(w) {} + + BasicWriter &writer() { return writer_; } + + void Format(BasicStringRef format_str, const ArgList &args); + + const Char *format(const Char *format_str, const internal::Arg &arg); +}; + +namespace internal { +// Printf format string parser. +template +class PrintfParser { + private: + ArgList args_; + int next_arg_index_; + + void ParseFlags(FormatSpec &spec, const Char *&s); + + // Parses argument index, flags and width and returns the parsed + // argument index. + unsigned ParseHeader(const Char *&s, FormatSpec &spec, const char *&error); + + const internal::Arg &HandleArgIndex(unsigned arg_index, const char *&error); + + public: + void Format(BasicWriter &writer, + BasicStringRef format, const ArgList &args); +}; +} // namespace internal + +enum Alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum { SIGN_FLAG = 1, PLUS_FLAG = 2, HASH_FLAG = 4 }; + +// An empty format specifier. +struct EmptySpec {}; + +// A type specifier. +template +struct TypeSpec : EmptySpec { + Alignment align() const { return ALIGN_DEFAULT; } + unsigned width() const { return 0; } + int precision() const { return -1; } + + bool sign_flag() const { return false; } + bool plus_flag() const { return false; } + bool hash_flag() const { return false; } + + char type() const { return TYPE; } + char fill() const { return ' '; } +}; + +// A width specifier. +struct WidthSpec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of WidthSpec and its subclasses. + wchar_t fill_; + + WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} + + unsigned width() const { return width_; } + wchar_t fill() const { return fill_; } +}; + +// An alignment specifier. +struct AlignSpec : WidthSpec { + Alignment align_; + + AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) + : WidthSpec(width, fill), align_(align) {} + + Alignment align() const { return align_; } + + int precision() const { return -1; } +}; + +// An alignment and type specifier. +template +struct AlignTypeSpec : AlignSpec { + AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} + + bool sign_flag() const { return false; } + bool plus_flag() const { return false; } + bool hash_flag() const { return false; } + + char type() const { return TYPE; } +}; + +// A full format specifier. +struct FormatSpec : AlignSpec { + unsigned flags_; + int precision_; + char type_; + + FormatSpec( + unsigned width = 0, char type = 0, wchar_t fill = ' ') + : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} + + bool sign_flag() const { return (flags_ & SIGN_FLAG) != 0; } + bool plus_flag() const { return (flags_ & PLUS_FLAG) != 0; } + bool hash_flag() const { return (flags_ & HASH_FLAG) != 0; } + + int precision() const { return precision_; } + + char type() const { return type_; } +}; + +// An integer format specifier. +template , typename Char = char> +class IntFormatSpec : public SpecT { + private: + T value_; + + public: + IntFormatSpec(T value, const SpecT &spec = SpecT()) + : SpecT(spec), value_(value) {} + + T value() const { return value_; } +}; + +// A string format specifier. +template +class StrFormatSpec : public AlignSpec { + private: + const T *str_; + + public: + StrFormatSpec(const T *str, unsigned width, wchar_t fill) + : AlignSpec(width, fill), str_(str) {} + + const T *str() const { return str_; } +}; + +/** + Returns an integer format specifier to format the value in base 2. + */ +IntFormatSpec > bin(int value); + +/** + Returns an integer format specifier to format the value in base 8. + */ +IntFormatSpec > oct(int value); + +/** + Returns an integer format specifier to format the value in base 16 using + lower-case letters for the digits above 9. + */ +IntFormatSpec > hex(int value); + +/** + Returns an integer formatter format specifier to format in base 16 using + upper-case letters for the digits above 9. + */ +IntFormatSpec > hexu(int value); + +/** + \rst + Returns an integer format specifier to pad the formatted argument with the + fill character to the specified width using the default (right) numeric + alignment. + + **Example**:: + + Writer out; + out << pad(hex(0xcafe), 8, '0'); + // out.str() == "0000cafe" + + \endrst + */ +template +IntFormatSpec, Char> pad( + int value, unsigned width, Char fill = ' '); + +#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ +inline IntFormatSpec > bin(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'b'>()); \ +} \ + \ +inline IntFormatSpec > oct(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'o'>()); \ +} \ + \ +inline IntFormatSpec > hex(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'x'>()); \ +} \ + \ +inline IntFormatSpec > hexu(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'X'>()); \ +} \ + \ +template \ +inline IntFormatSpec > pad( \ + IntFormatSpec > f, unsigned width) { \ + return IntFormatSpec >( \ + f.value(), AlignTypeSpec(width, ' ')); \ +} \ + \ +/* For compatibility with older compilers we provide two overloads for pad, */ \ +/* one that takes a fill character and one that doesn't. In the future this */ \ +/* can be replaced with one overload making the template argument Char */ \ +/* default to char (C++11). */ \ +template \ +inline IntFormatSpec, Char> pad( \ + IntFormatSpec, Char> f, \ + unsigned width, Char fill) { \ + return IntFormatSpec, Char>( \ + f.value(), AlignTypeSpec(width, fill)); \ +} \ + \ +inline IntFormatSpec > pad( \ + TYPE value, unsigned width) { \ + return IntFormatSpec >( \ + value, AlignTypeSpec<0>(width, ' ')); \ +} \ + \ +template \ +inline IntFormatSpec, Char> pad( \ + TYPE value, unsigned width, Char fill) { \ + return IntFormatSpec, Char>( \ + value, AlignTypeSpec<0>(width, fill)); \ +} + +FMT_DEFINE_INT_FORMATTERS(int) +FMT_DEFINE_INT_FORMATTERS(long) +FMT_DEFINE_INT_FORMATTERS(unsigned) +FMT_DEFINE_INT_FORMATTERS(unsigned long) +FMT_DEFINE_INT_FORMATTERS(LongLong) +FMT_DEFINE_INT_FORMATTERS(ULongLong) + +/** + \rst + Returns a string formatter that pads the formatted argument with the fill + character to the specified width using the default (left) string alignment. + + **Example**:: + + std::string s = str(Writer() << pad("abc", 8)); + // s == "abc " + + \endrst + */ +template +inline StrFormatSpec pad( + const Char *str, unsigned width, Char fill = ' ') { + return StrFormatSpec(str, width, fill); +} + +inline StrFormatSpec pad( + const wchar_t *str, unsigned width, char fill = ' ') { + return StrFormatSpec(str, width, fill); +} + +// Generates a comma-separated list with results of applying f to numbers 0..n-1. +# define FMT_GEN(n, f) FMT_GEN##n(f) +# define FMT_GEN1(f) f(0) +# define FMT_GEN2(f) FMT_GEN1(f), f(1) +# define FMT_GEN3(f) FMT_GEN2(f), f(2) +# define FMT_GEN4(f) FMT_GEN3(f), f(3) +# define FMT_GEN5(f) FMT_GEN4(f), f(4) +# define FMT_GEN6(f) FMT_GEN5(f), f(5) +# define FMT_GEN7(f) FMT_GEN6(f), f(6) +# define FMT_GEN8(f) FMT_GEN7(f), f(7) +# define FMT_GEN9(f) FMT_GEN8(f), f(8) +# define FMT_GEN10(f) FMT_GEN9(f), f(9) + +# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n +# define FMT_MAKE_ARG(n) const T##n &v##n +# define FMT_MAKE_REF_char(n) fmt::internal::MakeArg(v##n) +# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeArg(v##n) + +#if FMT_USE_VARIADIC_TEMPLATES +// Defines a variadic function returning void. +# define FMT_VARIADIC_VOID(func, arg_type) \ + template \ + void func(arg_type arg1, const Args & ... args) { \ + using fmt::internal::Arg; \ + const Arg arg_array[fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeArg(args)... \ + }; \ + func(arg1, ArgList(arg_array, sizeof...(Args))); \ + } + +// Defines a variadic constructor. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + template \ + ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ + using fmt::internal::Arg; \ + const Arg arg_array[fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeArg(args)... \ + }; \ + func(arg0, arg1, ArgList(arg_array, sizeof...(Args))); \ + } + +#else + +# define FMT_MAKE_REF(n) fmt::internal::MakeArg(v##n) +// Defines a wrapper for a function taking one argument of type arg_type +// and n additional arguments of arbitrary types. +# define FMT_WRAP1(func, arg_type, n) \ + template \ + inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Arg args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + } + +// Emulates a variadic function returning void on a pre-C++11 compiler. +# define FMT_VARIADIC_VOID(func, arg_type) \ + FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ + FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ + FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ + FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ + FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) + +# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ + template \ + ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Arg args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg0, arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + } + +// Emulates a variadic constructor on a pre-C++11 compiler. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) +#endif + +// Generates a comma-separated list with results of applying f to pairs +// (argument, index). +#define FMT_FOR_EACH1(f, x0) f(x0, 0) +#define FMT_FOR_EACH2(f, x0, x1) \ + FMT_FOR_EACH1(f, x0), f(x1, 1) +#define FMT_FOR_EACH3(f, x0, x1, x2) \ + FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) +#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ + FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) +#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ + FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) +#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ + FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) +#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ + FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) +#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ + FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) +#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ + FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) +#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ + FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) + +/** +An error returned by an operating system or a language runtime, +for example a file opening error. +*/ +class SystemError : public internal::RuntimeError { + private: + void init(int error_code, StringRef format_str, const ArgList &args); + + protected: + int error_code_; + + typedef char Char; // For FMT_VARIADIC_CTOR. + + SystemError() {} + + public: + /** + \rst + Constructs a :cpp:class:`fmt::SystemError` object with the description + of the form "**: **", where ** is the + formatted message and ** is the system message corresponding + to the error code. + *error_code* is a system error code as given by ``errno``. + \endrst + */ + SystemError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) + + int error_code() const { return error_code_; } +}; + +/** + \rst + This template provides operations for formatting and writing data into + a character stream. The output is stored in a memory buffer that grows + dynamically. + + You can use one of the following typedefs for common character types: + + +---------+----------------------+ + | Type | Definition | + +=========+======================+ + | Writer | BasicWriter | + +---------+----------------------+ + | WWriter | BasicWriter | + +---------+----------------------+ + + **Example**:: + + Writer out; + out << "The answer is " << 42 << "\n"; + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42 + (-3.140000, +3.140000) + + The output can be converted to an ``std::string`` with ``out.str()`` or + accessed as a C string with ``out.c_str()``. + \endrst + */ +template +class BasicWriter { + private: + // Output buffer. + mutable internal::Array buffer_; + + typedef typename internal::CharTraits::CharPtr CharPtr; + +#if _SECURE_SCL + static Char *GetBase(CharPtr p) { return p.base(); } +#else + static Char *GetBase(Char *p) { return p; } +#endif + + static CharPtr FillPadding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill); + + // Grows the buffer by n characters and returns a pointer to the newly + // allocated area. + CharPtr GrowBuffer(std::size_t n) { + std::size_t size = buffer_.size(); + buffer_.resize(size + n); + return internal::CheckPtr(&buffer_[size], n); + } + + // Prepare a buffer for integer formatting. + CharPtr PrepareBufferForInt(unsigned num_digits, + const EmptySpec &, const char *prefix, unsigned prefix_size) { + unsigned size = prefix_size + num_digits; + CharPtr p = GrowBuffer(size); + std::copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + + template + CharPtr PrepareBufferForInt(unsigned num_digits, + const Spec &spec, const char *prefix, unsigned prefix_size); + + // Formats an integer. + template + void FormatInt(T value, const Spec &spec); + + // Formats a floating-point number (double or long double). + template + void FormatDouble(T value, const FormatSpec &spec); + + // Writes a formatted string. + template + CharPtr write_str( + const StringChar *s, std::size_t size, const AlignSpec &spec); + + template + void write_str( + const internal::Arg::StringValue &str, const FormatSpec &spec); + + // This method is private to disallow writing a wide string to a + // char stream and vice versa. If you want to print a wide string + // as a pointer as std::ostream does, cast it to const void*. + // Do not implement! + void operator<<(typename internal::CharTraits::UnsupportedStrType); + + friend class internal::ArgFormatter; + friend class BasicFormatter; + friend class internal::PrintfParser; + + public: + /** + Constructs a ``BasicWriter`` object. + */ + BasicWriter() {} + +#if FMT_USE_RVALUE_REFERENCES + /** + Constructs a ``BasicWriter`` object moving the content of the other + object to it. + */ + BasicWriter(BasicWriter &&other) : buffer_(std::move(other.buffer_)) {} + + /** + Moves the content of the other ``BasicWriter`` object to this one. + */ + BasicWriter& operator=(BasicWriter &&other) { + assert(this != &other); + buffer_ = std::move(other.buffer_); + return *this; + } +#endif + + /** + Returns the total number of characters written. + */ + std::size_t size() const { return buffer_.size(); } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const Char *data() const { return &buffer_[0]; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const Char *c_str() const { + std::size_t size = buffer_.size(); + buffer_.reserve(size + 1); + buffer_[size] = '\0'; + return &buffer_[0]; + } + + /** + Returns the content of the output buffer as an `std::string`. + */ + std::basic_string str() const { + return std::basic_string(&buffer_[0], buffer_.size()); + } + + /** + \rst + Writes formatted data. + + *args* is an argument list representing arbitrary arguments. + + **Example**:: + + Writer out; + out.write("Current point:\n"); + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + Current point: + (-3.140000, +3.140000) + + The output can be accessed using :meth:`data`, :meth:`c_str` or :meth:`str` + methods. + + See also `Format String Syntax`_. + \endrst + */ + void write(BasicStringRef format, const ArgList &args) { + BasicFormatter(*this).Format(format, args); + } + FMT_VARIADIC_VOID(write, fmt::BasicStringRef) + + BasicWriter &operator<<(int value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(unsigned value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(long value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(unsigned long value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(LongLong value) { + return *this << IntFormatSpec(value); + } + + /** + Formats *value* and writes it to the stream. + */ + BasicWriter &operator<<(ULongLong value) { + return *this << IntFormatSpec(value); + } + + BasicWriter &operator<<(double value) { + FormatDouble(value, FormatSpec()); + return *this; + } + + /** + Formats *value* using the general format for floating-point numbers + (``'g'``) and writes it to the stream. + */ + BasicWriter &operator<<(long double value) { + FormatDouble(value, FormatSpec()); + return *this; + } + + /** + Writes a character to the stream. + */ + BasicWriter &operator<<(char value) { + *GrowBuffer(1) = value; + return *this; + } + + BasicWriter &operator<<(wchar_t value) { + *GrowBuffer(1) = internal::CharTraits::convert(value); + return *this; + } + + /** + Writes *value* to the stream. + */ + BasicWriter &operator<<(const fmt::BasicStringRef value) { + const Char *str = value.c_str(); + std::size_t size = value.size(); + std::copy(str, str + size, GrowBuffer(size)); + return *this; + } + + template + BasicWriter &operator<<(const IntFormatSpec &spec) { + internal::CharTraits::convert(FillChar()); + FormatInt(spec.value(), spec); + return *this; + } + + template + BasicWriter &operator<<(const StrFormatSpec &spec) { + const StringChar *s = spec.str(); + // TODO: error if fill is not convertible to Char + write_str(s, std::char_traits::length(s), spec); + return *this; + } + + void clear() { buffer_.clear(); } +}; + +template +template +typename BasicWriter::CharPtr BasicWriter::write_str( + const StringChar *s, std::size_t size, const AlignSpec &spec) { + CharPtr out = CharPtr(); + if (spec.width() > size) { + out = GrowBuffer(spec.width()); + Char fill = static_cast(spec.fill()); + if (spec.align() == ALIGN_RIGHT) { + std::fill_n(out, spec.width() - size, fill); + out += spec.width() - size; + } else if (spec.align() == ALIGN_CENTER) { + out = FillPadding(out, spec.width(), size, fill); + } else { + std::fill_n(out + size, spec.width() - size, fill); + } + } else { + out = GrowBuffer(size); + } + std::copy(s, s + size, out); + return out; +} + +template +template +typename fmt::BasicWriter::CharPtr + fmt::BasicWriter::PrepareBufferForInt( + unsigned num_digits, const Spec &spec, + const char *prefix, unsigned prefix_size) { + unsigned width = spec.width(); + Alignment align = spec.align(); + Char fill = static_cast(spec.fill()); + if (spec.precision() > static_cast(num_digits)) { + // Octal prefix '0' is counted as a digit, so ignore it if precision + // is specified. + if (prefix_size > 0 && prefix[prefix_size - 1] == '0') + --prefix_size; + unsigned number_size = prefix_size + spec.precision(); + AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); + if (number_size >= width) + return PrepareBufferForInt(num_digits, subspec, prefix, prefix_size); + buffer_.reserve(width); + unsigned fill_size = width - number_size; + if (align != ALIGN_LEFT) { + CharPtr p = GrowBuffer(fill_size); + std::fill(p, p + fill_size, fill); + } + CharPtr result = PrepareBufferForInt(num_digits, subspec, prefix, prefix_size); + if (align == ALIGN_LEFT) { + CharPtr p = GrowBuffer(fill_size); + std::fill(p, p + fill_size, fill); + } + return result; + } + unsigned size = prefix_size + num_digits; + if (width <= size) { + CharPtr p = GrowBuffer(size); + std::copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + CharPtr p = GrowBuffer(width); + CharPtr end = p + width; + if (align == ALIGN_LEFT) { + std::copy(prefix, prefix + prefix_size, p); + p += size; + std::fill(p, end, fill); + } else if (align == ALIGN_CENTER) { + p = FillPadding(p, width, size, fill); + std::copy(prefix, prefix + prefix_size, p); + p += size; + } else { + if (align == ALIGN_NUMERIC) { + if (prefix_size != 0) { + p = std::copy(prefix, prefix + prefix_size, p); + size -= prefix_size; + } + } else { + std::copy(prefix, prefix + prefix_size, end - size); + } + std::fill(p, end - size, fill); + p = end; + } + return p - 1; +} + +template +template +void BasicWriter::FormatInt(T value, const Spec &spec) { + unsigned prefix_size = 0; + typedef typename internal::IntTraits::MainType UnsignedType; + UnsignedType abs_value = value; + char prefix[4] = ""; + if (internal::IsNegative(value)) { + prefix[0] = '-'; + ++prefix_size; + abs_value = 0 - abs_value; + } else if (spec.sign_flag()) { + prefix[0] = spec.plus_flag() ? '+' : ' '; + ++prefix_size; + } + switch (spec.type()) { + case 0: case 'd': { + unsigned num_digits = internal::CountDigits(abs_value); + CharPtr p = PrepareBufferForInt( + num_digits, spec, prefix, prefix_size) + 1 - num_digits; + internal::FormatDecimal(GetBase(p), abs_value, num_digits); + break; + } + case 'x': case 'X': { + UnsignedType n = abs_value; + if (spec.hash_flag()) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 4) != 0); + Char *p = GetBase(PrepareBufferForInt( + num_digits, spec, prefix, prefix_size)); + n = abs_value; + const char *digits = spec.type() == 'x' ? + "0123456789abcdef" : "0123456789ABCDEF"; + do { + *p-- = digits[n & 0xf]; + } while ((n >>= 4) != 0); + break; + } + case 'b': case 'B': { + UnsignedType n = abs_value; + if (spec.hash_flag()) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 1) != 0); + Char *p = GetBase(PrepareBufferForInt(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = '0' + (n & 1); + } while ((n >>= 1) != 0); + break; + } + case 'o': { + UnsignedType n = abs_value; + if (spec.hash_flag()) + prefix[prefix_size++] = '0'; + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 3) != 0); + Char *p = GetBase(PrepareBufferForInt( + num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = '0' + (n & 7); + } while ((n >>= 3) != 0); + break; + } + default: + internal::ReportUnknownType(spec.type(), "integer"); + break; + } +} + +// Formats a value. +template +void format(BasicFormatter &f, const Char *format_str, const T &value) { + std::basic_ostringstream os; + os << value; + f.format(format_str, internal::MakeArg(os.str())); +} + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +void ReportSystemError(int error_code, StringRef message) FMT_NOEXCEPT(true); + +#ifdef _WIN32 + +/** + A Windows error. +*/ +class WindowsError : public SystemError { + private: + void init(int error_code, StringRef format_str, const ArgList &args); + + public: + /** + \rst + Constructs a :cpp:class:`fmt::WindowsError` object with the description + of the form "**: **", where ** is the + formatted message and ** is the system message corresponding + to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + \endrst + */ + WindowsError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) +}; + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +void ReportWinError(int error_code, StringRef message) FMT_NOEXCEPT(true); + +#endif + +enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; + +/** + Formats a string and prints it to stdout using ANSI escape sequences + to specify color (experimental). + Example: + PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; + */ +void print_colored(Color c, StringRef format, const ArgList &args); + +/** + \rst + Formats a string similarly to Python's `str.format + `__ function + and returns the result as a string. + + *format_str* is a format string that contains literal text and replacement + fields surrounded by braces ``{}``. The fields are replaced with formatted + arguments in the resulting string. + + *args* is an argument list representing arbitrary arguments. + + **Example**:: + + std::string message = format("The answer is {}", 42); + + See also `Format String Syntax`_. + \endrst +*/ +inline std::string format(StringRef format_str, const ArgList &args) { + Writer w; + w.write(format_str, args); + return w.str(); +} + +inline std::wstring format(WStringRef format, const ArgList &args) { + WWriter w; + w.write(format, args); + return w.str(); +} + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +void print(StringRef format, const ArgList &args); + +/** + \rst + Prints formatted data to a file. + + **Example**:: + + print(stderr, "Don't {}!", "panic"); + \endrst + */ +void print(std::FILE *f, StringRef format, const ArgList &args); + +/** + \rst + Prints formatted data to a stream. + + **Example**:: + + print(cerr, "Don't {}!", "panic"); + \endrst + */ +void print(std::ostream &os, StringRef format, const ArgList &args); + +template +void printf(BasicWriter &w, + BasicStringRef format, const ArgList &args) { + internal::PrintfParser().Format(w, format, args); +} + +inline std::string sprintf(StringRef format, const ArgList &args) { + Writer w; + printf(w, format, args); + return w.str(); +} + +void printf(StringRef format, const ArgList &args); + +/** + Fast integer formatter. + */ +class FormatInt { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; + mutable char buffer_[BUFFER_SIZE]; + char *str_; + + // Formats value in reverse and returns the number of digits. + char *FormatDecimal(ULongLong value) { + char *buffer_end = buffer_ + BUFFER_SIZE - 1; + 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. + unsigned index = (value % 100) * 2; + value /= 100; + *--buffer_end = internal::DIGITS[index + 1]; + *--buffer_end = internal::DIGITS[index]; + } + if (value < 10) { + *--buffer_end = static_cast('0' + value); + return buffer_end; + } + unsigned index = static_cast(value * 2); + *--buffer_end = internal::DIGITS[index + 1]; + *--buffer_end = internal::DIGITS[index]; + return buffer_end; + } + + void FormatSigned(LongLong value) { + ULongLong abs_value = value; + bool negative = value < 0; + if (negative) + abs_value = 0 - value; + str_ = FormatDecimal(abs_value); + if (negative) + *--str_ = '-'; + } + + public: + explicit FormatInt(int value) { FormatSigned(value); } + explicit FormatInt(long value) { FormatSigned(value); } + explicit FormatInt(LongLong value) { FormatSigned(value); } + explicit FormatInt(unsigned value) : str_(FormatDecimal(value)) {} + explicit FormatInt(unsigned long value) : str_(FormatDecimal(value)) {} + explicit FormatInt(ULongLong value) : str_(FormatDecimal(value)) {} + + /** + Returns the number of characters written to the output buffer. + */ + std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const char *data() const { return str_; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const char *c_str() const { + buffer_[BUFFER_SIZE - 1] = '\0'; + return str_; + } + + /** + Returns the content of the output buffer as an `std::string`. + */ + std::string str() const { return std::string(str_, size()); } +}; + +// Formats a decimal integer value writing into buffer and returns +// a pointer to the end of the formatted string. This function doesn't +// write a terminating null character. +template +inline void FormatDec(char *&buffer, T value) { + typename internal::IntTraits::MainType abs_value = value; + if (internal::IsNegative(value)) { + *buffer++ = '-'; + abs_value = 0 - abs_value; + } + if (abs_value < 100) { + if (abs_value < 10) { + *buffer++ = static_cast('0' + abs_value); + return; + } + unsigned index = static_cast(abs_value * 2); + *buffer++ = internal::DIGITS[index]; + *buffer++ = internal::DIGITS[index + 1]; + return; + } + unsigned num_digits = internal::CountDigits(abs_value); + internal::FormatDecimal(buffer, abs_value, num_digits); + buffer += num_digits; +} +} + +#if FMT_GCC_VERSION +// Use the system_header pragma to suppress warnings about variadic macros +// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't work. +// It is used at the end because we want to suppress as little warnings as +// possible. +# pragma GCC system_header +#endif + +// This is used to work around VC++ bugs in handling variadic macros. +#define FMT_EXPAND(args) args + +// Returns the number of arguments. +// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. +#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) +#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) +#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define FMT_CONCAT(a, b) a##b +#define FMT_FOR_EACH_(N, f, ...) \ + FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) +#define FMT_FOR_EACH(f, ...) \ + FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) + +#define FMT_ADD_ARG_NAME(type, index) type arg##index +#define FMT_GET_ARG_NAME(type, index) arg##index + +#if FMT_USE_VARIADIC_TEMPLATES +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + template \ + ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + const Args & ... args) { \ + using fmt::internal::Arg; \ + const Arg array[fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeArg(args)... \ + }; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ + fmt::ArgList(array, sizeof...(Args))); \ + } +#else +// Defines a wrapper for a function taking __VA_ARGS__ arguments +// and n additional arguments of arbitrary types. +# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ + template \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Arg args[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ + fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + } + +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ + } \ + FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) +#endif // FMT_USE_VARIADIC_TEMPLATES + +/** + \rst + Defines a variadic function with the specified return type, function name + and argument types passed as variable arguments to this macro. + + **Example**:: + + void print_error(const char *file, int line, const char *format, + const fmt::ArgList &args) { + fmt::print("{}: {}: ", file, line); + fmt::print(format, args); + } + FMT_VARIADIC(void, print_error, const char *, int, const char *) + \endrst + */ +#define FMT_VARIADIC(ReturnType, func, ...) \ + FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_VARIADIC_W(ReturnType, func, ...) \ + FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) + +namespace fmt { +FMT_VARIADIC(std::string, format, StringRef) +FMT_VARIADIC_W(std::wstring, format, WStringRef) +FMT_VARIADIC(void, print, StringRef) +FMT_VARIADIC(void, print, std::FILE *, StringRef) +FMT_VARIADIC(void, print, std::ostream &, StringRef) +FMT_VARIADIC(void, print_colored, Color, StringRef) +FMT_VARIADIC(std::string, sprintf, StringRef) +FMT_VARIADIC(void, printf, StringRef) +} + +// Restore warnings. +#if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic pop +#endif + +#endif // FMT_FORMAT_H_ diff --git a/thirdparty/strtk/strtk.hpp b/thirdparty/strtk/strtk.hpp new file mode 100644 index 000000000..2bfa70210 --- /dev/null +++ b/thirdparty/strtk/strtk.hpp @@ -0,0 +1,23653 @@ +/* + ***************************************************************** + * String Toolkit Library * + * * + * Author: Arash Partow (2002-2014) * + * URL: http://www.partow.net/programming/strtk/index.html * + * * + * Copyright notice: * + * Free use of the String Toolkit Library is permitted under the * + * guidelines and in accordance with the most current version of * + * the Common Public License. * + * http://www.opensource.org/licenses/cpl1.0.php * + * * + ***************************************************************** +*/ + + +#ifndef INCLUDE_STRTK_HPP +#define INCLUDE_STRTK_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef strtk_no_tr1_or_boost + #define strtk_enable_lexical_cast + #define strtk_enable_random + #define strtk_enable_regex +#endif + +#ifdef strtk_enable_lexical_cast + #include +#endif + +#ifdef strtk_enable_random + // Requires definition of a TR1 compatible random library header + //#include + #include +#endif + +#ifdef strtk_enable_regex + // Requires definition of a TR1 compatible regex library header + //#include + #include +#endif + + +namespace strtk +{ + + static const std::size_t one_kilobyte = 1024; + static const std::size_t one_megabyte = 1024 * one_kilobyte; + static const std::size_t one_gigabyte = 1024 * one_megabyte; + static const std::size_t magic_seed = 0xA5A5A5A5; + + template + inline std::size_t for_each_token(const std::string& buffer, + Tokenizer& tokenizer, + Function function) + { + std::size_t token_count = 0; + tokenizer.assign(buffer); + typename Tokenizer::iterator itr = tokenizer.begin(); + typename Tokenizer::const_iterator end = tokenizer.end(); + while (end != itr) + { + function(*itr); + ++itr; + ++token_count; + } + return token_count; + } + + template + inline std::size_t for_each_line(std::istream& stream, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + function(buffer); + ++line_count; + } + return line_count; + } + + template + inline std::size_t for_each_line_n(std::istream& stream, + const std::size_t& n, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + function(buffer); + if (n == ++line_count) + break; + } + return line_count; + } + + template + inline std::size_t for_each_line(const std::string& file_name, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (stream) + return for_each_line(stream,function,buffer_size); + else + return 0; + } + + template + inline std::size_t for_each_line_n(const std::string& file_name, + const std::size_t& n, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (stream) + return for_each_line_n(stream,n,function,buffer_size); + else + return 0; + } + + template + inline std::size_t for_each_line_conditional(std::istream& stream, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + if (!function(buffer)) + { + return line_count; + } + ++line_count; + } + return line_count; + } + + template + inline std::size_t for_each_line_n_conditional(std::istream& stream, + const std::size_t& n, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + if (!function(buffer)) + { + return line_count; + } + if (n == ++line_count) + break; + } + return line_count; + } + + template + inline std::size_t for_each_line_conditional(const std::string& file_name, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (stream) + return for_each_line_conditional(stream,function,buffer_size); + else + return 0; + } + + template + inline std::size_t for_each_line_n_conditional(const std::string& file_name, + const std::size_t& n, + Function function, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (stream) + return for_each_line_n_conditional(stream,n,function,buffer_size); + else + return 0; + } + + template + inline bool read_line_as_value(std::istream& stream, + T& t, + const std::size_t& buffer_size = one_kilobyte) + { + std::string buffer; + buffer.reserve(buffer_size); + if (!std::getline(stream,buffer)) + return false; + return string_to_type_converter(buffer,t); + } + + namespace details + { + struct not_supported_type_tag {}; + struct unsigned_type_tag {}; + struct signed_type_tag {}; + struct real_type_tag {}; + struct byte_type_tag {}; + struct bool_type_tag {}; + struct hex_number_type_tag {}; + struct hex_string_type_tag {}; + struct base64_type_tag {}; + struct ignore_token_type_tag {}; + struct stdstring_type_tag {}; + struct stdstring_range_type_tag {}; + struct value_type_tag {}; + struct sink_type_tag {}; + struct stl_seq_type_tag {}; + struct attribute_type_tag {}; + struct semantic_action_type_tag {}; + struct expect_type_tag {}; + struct like_type_tag {}; + struct inrange_type_tag {}; + struct trim_type_tag {}; + struct lcase_type_tag {}; + struct ucase_type_tag {}; + struct fillchararray_type_tag {}; + struct truncint_type_tag {}; + + template + struct supported_conversion_to_type + { + typedef not_supported_type_tag type; + }; + + template + struct supported_conversion_from_type + { + typedef not_supported_type_tag type; + }; + + template + struct enable_if {}; + + template + struct enable_if { typedef T type; }; + + template + struct supported_iterator_type + { + enum { value = false }; + }; + + template + struct is_valid_iterator + { + typedef typename details::enable_if::value,T>::type type; + }; + + template struct numeric; + template inline std::size_t type_length(const T&); + + struct no_t {}; + struct yes_t {}; + + template + struct is_pod + { + typedef no_t result_t; + enum { result = false }; + }; + + template + struct is_stl_container + { typedef no_t result_t; }; + + #define register_stl_container1(C) \ + template struct is_stl_container >{ typedef yes_t result_t; }; + + #define register_stl_container2(C) \ + template struct is_stl_container >{ typedef yes_t result_t; }; + + register_stl_container1(std::vector) + register_stl_container1(std::deque) + register_stl_container1(std::list) + register_stl_container1(std::queue) + register_stl_container1(std::stack) + register_stl_container2(std::set) + register_stl_container2(std::multiset) + register_stl_container2(std::priority_queue) + + #undef register_stl_container1 + #undef register_stl_container2 + + template + void convert_type_assert(){} + + } // namespace details + + template + inline bool string_to_type_converter(const Iterator begin, const Iterator end, T& t) + { + typedef typename details::is_valid_iterator::type itr_type; + typename details::supported_conversion_to_type::type type; + details::convert_type_assert(); + Iterator itr = begin; + return string_to_type_converter_impl(itr,end,t,type); + } + + template + inline bool string_to_type_converter(const std::pair& range, T& t) + { + return string_to_type_converter(range.first,range.second,t); + } + + template + inline T string_to_type_converter(const Iterator begin, const Iterator end) + { + typedef typename details::is_valid_iterator::type itr_type; + typename details::supported_conversion_to_type::type type; + details::convert_type_assert(); + T t; + Iterator itr = begin; + if (string_to_type_converter_impl(itr,end,t,type)) + return t; + else + throw std::invalid_argument("string_to_type_converter() - Failed to convert: " + + std::string(begin,end)); + } + + template + inline T string_to_type_converter(const std::pair& range) + { + return string_to_type_converter(range.first,range.second); + } + + template + inline bool string_to_type_converter(const std::string& s, T& t) + { + return string_to_type_converter(s.data(),s.data() + s.size(),t); + } + + template + inline T string_to_type_converter(const std::string& s) + { + return string_to_type_converter(s.data(),s.data() + s.size()); + } + + template + inline bool type_to_string(const T& t, std::string& s) + { + typename details::supported_conversion_from_type::type type; + return type_to_string_converter_impl(t,s,type); + } + + template + inline std::string type_to_string(const T& t) + { + std::string s; + if (type_to_string(t,s)) + return s; + else + throw std::invalid_argument("type_to_string() - Failed to convert type to string"); + } + + #define strtk_begin_register_string_to_type \ + namespace strtk { namespace details { \ + + #define strtk_end_register_string_to_type \ + }} \ + + #define strtk_string_to_type_begin(Type) \ + namespace strtk { namespace details { template \ + inline bool string_to_type_converter_impl(const Iterator& begin, const Iterator& end, \ + Type& t, details::not_supported_type_tag&) { \ + + #define strtk_string_to_type_end() \ + }}} \ + + template class Sequence> + inline std::size_t load_from_text_file(std::istream& stream, + Sequence& sequence, + const std::size_t& buffer_size = one_kilobyte) + { + if (!stream) return 0; + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + ++line_count; + sequence.push_back(string_to_type_converter(buffer)); + } + return line_count; + } + + template + inline std::size_t load_from_text_file(std::istream& stream, + std::set& set, + const std::size_t& buffer_size = one_kilobyte) + { + if (!stream) return 0; + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + ++line_count; + set.insert(string_to_type_converter(buffer)); + } + return line_count; + } + + template + inline std::size_t load_from_text_file(std::istream& stream, + std::multiset& multiset, + const std::size_t& buffer_size = one_kilobyte) + { + if (!stream) return 0; + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + ++line_count; + multiset.insert(string_to_type_converter(buffer)); + } + return line_count; + } + + template + inline std::size_t load_from_text_file(std::istream& stream, + std::queue& queue, + const std::size_t& buffer_size = one_kilobyte) + { + if (!stream) return 0; + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + ++line_count; + queue.push(string_to_type_converter(buffer)); + } + return line_count; + } + + template + inline std::size_t load_from_text_file(std::istream& stream, + std::stack& stack, + const std::size_t& buffer_size = one_kilobyte) + { + if (!stream) return 0; + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + ++line_count; + stack.push(string_to_type_converter(buffer)); + } + return line_count; + } + + template + inline std::size_t load_from_text_file(std::istream& stream, + std::priority_queue& priority_queue, + const std::size_t& buffer_size = one_kilobyte) + { + if (!stream) return 0; + std::string buffer; + buffer.reserve(buffer_size); + std::size_t line_count = 0; + while (std::getline(stream,buffer)) + { + ++line_count; + priority_queue.push(string_to_type_converter(buffer)); + } + return line_count; + } + + template class Sequence> + inline std::size_t load_from_text_file(const std::string& file_name, + Sequence& sequence, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return load_from_text_file(stream,sequence,buffer_size); + } + + template + inline std::size_t load_from_text_file(const std::string& file_name, + std::set& set, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return load_from_text_file(stream,set,buffer_size); + } + + template + inline std::size_t load_from_text_file(const std::string& file_name, + std::multiset& multiset, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return load_from_text_file(stream,multiset,buffer_size); + } + + template + inline std::size_t load_from_text_file(const std::string& file_name, + std::queue& queue, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return load_from_text_file(stream,queue,buffer_size); + } + + template + inline std::size_t load_from_text_file(const std::string& file_name, + std::stack& stack, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return load_from_text_file(stream,stack,buffer_size); + } + + template + inline std::size_t load_from_text_file(const std::string& file_name, + std::priority_queue& priority_queue, + const std::size_t& buffer_size = one_kilobyte) + { + std::ifstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return load_from_text_file(stream,priority_queue,buffer_size); + } + + template class Sequence> + inline std::size_t write_to_text_file(std::ostream& stream, + const Sequence& sequence, + const std::string& delimiter = "") + { + if (!stream) return 0; + + std::size_t count = 0; + typename Sequence::const_iterator itr = sequence.begin(); + typename Sequence::const_iterator end = sequence.end(); + + if (!delimiter.empty()) + { + while (end != itr) + { + stream << (*itr) << delimiter; + ++itr; + ++count; + } + } + else + { + while (end != itr) + { + stream << (*itr); + ++itr; + ++count; + } + } + return count; + } + + template + inline std::size_t write_to_text_file(std::ostream& stream, + const std::set& set, + const std::string& delimiter = "") + { + if (!stream) return 0; + + std::size_t count = 0; + typename std::set::const_iterator itr = set.begin(); + typename std::set::const_iterator end = set.end(); + + if (!delimiter.empty()) + { + while (end != itr) + { + stream << (*itr) << delimiter; + ++itr; + ++count; + } + } + else + { + while (end != itr) + { + stream << (*itr); + ++itr; + ++count; + } + } + return count; + } + + template + inline std::size_t write_to_text_file(std::ostream& stream, + const std::multiset& multiset, + const std::string& delimiter = "") + { + if (!stream) return 0; + + std::size_t count = 0; + typename std::multiset::const_iterator itr = multiset.begin(); + typename std::multiset::const_iterator end = multiset.end(); + + if (!delimiter.empty()) + { + while (end != itr) + { + stream << (*itr) << delimiter; + ++itr; + ++count; + } + } + else + { + while (end != itr) + { + stream << (*itr); + ++itr; + ++count; + } + } + return count; + } + + template class Sequence> + inline std::size_t write_to_text_file(const std::string& file_name, + const Sequence& sequence, + const std::string& delimiter = "") + { + std::ofstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return write_to_text_file(stream,sequence,delimiter); + } + + template + inline std::size_t write_to_text_file(const std::string& file_name, + const std::set& set, + const std::string& delimiter = "") + { + std::ofstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return write_to_text_file(stream,set,delimiter); + } + + template + inline std::size_t write_to_text_file(const std::string& file_name, + const std::multiset& multiset, + const std::string& delimiter = "") + { + std::ofstream stream(file_name.c_str()); + if (!stream) + return 0; + else + return write_to_text_file(stream,multiset,delimiter); + } + + template + inline void copy_n(InputIterator itr, std::size_t n, OutputIterator out) + { + while (n) + { + (*out) = (*itr); + ++itr; + ++out; + --n; + } + } + + template + inline void copy_if(Predicate predicate, + const InputIterator begin, const InputIterator end, + OutputIterator out) + { + InputIterator itr = begin; + while (end != itr) + { + if (predicate(*itr)) + { + *(out++) = (*itr); + } + ++itr; + } + } + + template + inline InputIterator copy_while(Predicate predicate, + const InputIterator begin, const InputIterator end, + OutputIterator out) + { + InputIterator itr = begin; + while (end != itr) + { + if (!predicate(*itr)) + return itr; + *(out++) = *(itr++); + } + return end; + } + + template + inline InputIterator copy_until(Predicate predicate, + const InputIterator begin, const InputIterator end, + OutputIterator out) + { + InputIterator itr = begin; + while (end != itr) + { + if (predicate(*itr)) + return itr; + *(out++) = *(itr++); + } + return end; + } + + template + inline void extract_unique(const InputIterator begin, const InputIterator end, + OutputIterator out) + { + typedef typename std::iterator_traits::value_type T; + std::vector buffer(begin,end); + std::sort(buffer.begin(),buffer.end()); + std::unique_copy(buffer.begin(),buffer.end(),out); + } + + template + inline bool range_only_contains(Predicate predicate, + const InputIterator begin, + const InputIterator end) + { + InputIterator itr = begin; + while (end != itr) + { + if (!predicate(*itr)) + { + return false; + } + ++itr; + } + return true; + } + + namespace range + { + template + class adapter + { + public: + + typedef T value_type; + typedef T* iterator; + typedef const iterator const_iterator; + + adapter(T* const begin, T* const end) + : begin_(begin), + end_(end) + {} + + adapter(const std::pair& r) + : begin_(r.first), + end_(r.second) + {} + + adapter(T* const begin, const std::size_t length) + : begin_(begin), + end_(begin_ + length) + {} + + inline iterator begin() const + { + return begin_; + } + + inline iterator end() const + { + return end_; + } + + inline std::size_t size() const + { + return std::distance(begin_,end_); + } + + inline operator std::string() const + { + return stringify(begin_,end_); + } + + inline const T& operator[](const std::size_t& index) const + { + return *(begin_ + index); + } + + inline T& operator[](const std::size_t& index) + { + return *(begin_ + index); + } + + private: + + template + static inline std::string stringify(Type*,Type*) + { + static std::string result = ""; + return result; + } + + static inline std::string stringify(const char* begin, const char* end) + { + return std::string(begin,end); + } + + iterator begin_; + iterator end_; + }; + + typedef adapter string; + typedef adapter ustring; + + template + inline adapter type(const T* begin, const T* end) + { + return adapter(begin,end); + } + + template + inline adapter type(const T (&t)[N]) + { + return adapter(t,N); + } + + static inline adapter type(const std::string& s) + { + return adapter(s.data(),s.size()); + } + + template class Sequence> + inline adapter::iterator> type(const Sequence& seq) + { + return adapter::iterator>(seq.begin(),seq.end()); + } + + inline std::string as_string(const adapter& a) + { + return std::string(a.begin(),a.end()); + } + + inline std::string as_string(const adapter& a) + { + return std::string(a.begin(),a.end()); + } + + } // namespace range + + template + struct single_delimiter_predicate + { + public: + + typedef T value_type; + + single_delimiter_predicate(const T& d) + : delimiter_(d) + {} + + inline bool operator()(const T& d) const + { + return delimiter_ == d; + } + + private: + + single_delimiter_predicate& operator=(const single_delimiter_predicate&); + const T delimiter_; + }; + + template + struct multiple_delimiter_predicate + { + public: + + typedef T value_type; + + multiple_delimiter_predicate(const T* d_begin, const T* d_end) + : length_(std::distance(d_begin,d_end)), + delimiter_((length_ <= sbo_buffer_size) ? sbo_buffer : new T[length_]), + delimiter_end_(delimiter_ + length_) + { + std::copy(d_begin,d_end, delimiter_); + } + + multiple_delimiter_predicate(const T d[], const std::size_t& length) + : length_(length), + delimiter_((length_ <= sbo_buffer_size) ? sbo_buffer : new T[length_]), + delimiter_end_(delimiter_ + length_) + { + std::copy(d,d + length, delimiter_); + } + + template + multiple_delimiter_predicate(const Iterator begin, const Iterator end) + : length_(std::distance(begin,end)), + delimiter_((length_ <= sbo_buffer_size) ? sbo_buffer : new T[length_]), + delimiter_end_(delimiter_ + length_) + { + //static_assert(T == std::iterator_traits::value_type); + std::copy(begin,end, delimiter_); + } + + template + multiple_delimiter_predicate(const range::adapter& r) + : length_(std::distance(r.begin(),r.end())), + delimiter_((length_ <= sbo_buffer_size) ? sbo_buffer : new T[length_]), + delimiter_end_(delimiter_ + length_) + { + //static_assert(T == std::iterator_traits::value_type); + std::copy(r.begin(),r.end(), delimiter_); + } + + ~multiple_delimiter_predicate() + { + if (length_ > sbo_buffer_size) + { + delete[] delimiter_; + } + } + + inline bool operator()(const T& d) const + { + return (std::find(delimiter_,delimiter_end_,d) != delimiter_end_); + } + + private: + + multiple_delimiter_predicate(const multiple_delimiter_predicate& mdp); + multiple_delimiter_predicate& operator=(const multiple_delimiter_predicate& mdp); + + std::size_t length_; + T* delimiter_; + T* delimiter_end_; + enum { sbo_buffer_size = 32 }; + T sbo_buffer[sbo_buffer_size]; + }; + + struct multiple_char_delimiter_predicate + { + public: + + template + multiple_char_delimiter_predicate(const Iterator begin, const Iterator end) + { + setup_delimiter_table(begin,end); + } + + multiple_char_delimiter_predicate(const std::string& s) + { + setup_delimiter_table(s.data(),s.data() + s.size()); + } + + inline bool operator()(const unsigned char& c) const + { + return (delimiter_table_[c]); + } + + inline bool operator()(const char& c) const + { + return operator()(static_cast(c)); + } + + private: + + static const std::size_t table_size = 256; + + template + inline void setup_delimiter_table(const Iterator begin, const Iterator end) + { + std::fill_n(delimiter_table_,table_size,false); + for (Iterator itr = begin; itr != end; ++itr) + { + delimiter_table_[static_cast(*itr)] = true; + } + } + + bool delimiter_table_[table_size]; + }; + + namespace details + { + template class Sequence> + struct index_remover_impl + { + typedef Sequence sequence_t; + index_remover_impl(const sequence_t& sequence) + : itr_(sequence.begin()), + end_(sequence.end()), + current_index_(0), + check_(true) + {} + + template + inline bool operator()(const T&) + { + if (check_) + { + if (current_index_++ == *itr_) + { + if (end_ == ++itr_) + { + check_ = false; + } + return true; + } + } + return false; + } + + typename sequence_t::const_iterator itr_; + typename sequence_t::const_iterator end_; + std::size_t current_index_; + bool check_; + }; + } + + template class Sequence> + inline details::index_remover_impl index_remover(const Sequence& sequence) + { + return details::index_remover_impl(sequence); + } + + template + inline std::size_t remove_inplace(Predicate predicate, + Iterator begin, + Iterator end) + { + Iterator itr1 = begin; + Iterator itr2 = begin; + std::size_t removal_count = 0; + while (end != itr1) + { + if (predicate(*itr1)) + { + ++itr1; + ++removal_count; + } + else + { + if (itr1 != itr2) + { + (*itr2) = (*itr1); + } + ++itr1; + ++itr2; + } + } + return removal_count; + } + + template + inline std::size_t remove_inplace(Predicate predicate, const range::adapter& r) + { + return remove_inplace(predicate,r.begin(),r.end()); + } + + template class Sequence> + inline std::size_t remove_inplace(Predicate predicate, Sequence& sequence) + { + const std::size_t removal_count = remove_inplace(predicate,sequence.begin(),sequence.end()); + sequence.resize(sequence.size() - removal_count); + return removal_count; + } + + inline void remove_inplace(const std::string::value_type c, std::string& s) + { + const std::size_t removal_count = remove_inplace(single_delimiter_predicate(c), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template + inline void remove_inplace(Predicate predicate, std::string& s) + { + const std::size_t removal_count = remove_inplace(predicate, + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template + inline std::size_t remove_consecutives_inplace(Predicate predicate, + Iterator begin, + Iterator end) + { + if (0 == std::distance(begin,end)) return 0; + Iterator itr1 = begin; + Iterator itr2 = begin; + typename std::iterator_traits::value_type prev = *begin; + std::size_t removal_count = 0; + ++itr1; + ++itr2; + while (end != itr1) + { + while ((end != itr1) && (!predicate(*itr1) || !predicate(prev))) + { + if (itr1 != itr2) + { + (*itr2) = (*itr1); + } + prev = (*itr1); + ++itr1; + ++itr2; + } + + while ((end != itr1) && predicate(*itr1)) + { + ++itr1; + ++removal_count; + } + } + + return removal_count; + } + + template + inline std::size_t remove_consecutives_inplace(Predicate predicate, const range::adapter& r) + { + return remove_consecutives_inplace(predicate,r.begin(),r.end()); + } + + inline void remove_consecutives_inplace(const std::string::value_type c, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_consecutives_inplace(single_delimiter_predicate(c), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline void remove_consecutives_inplace(const std::string& rem_chars, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_consecutives_inplace(multiple_char_delimiter_predicate(rem_chars), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + namespace details + { + #if (defined(__MINGW32_VERSION)) || \ + (defined(__CYGWIN__) || defined(__CYGWIN32__)) || \ + (defined(__APPLE__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)) || \ + (defined(_WIN32) && (_MSC_VER < 1400)) + inline std::size_t strnlength(const char* s, const std::size_t& n) + { + const char *end = reinterpret_cast(memchr(s, '\0', n)); + return end ? (size_t) (end - s) : n; + } + #else + inline std::size_t strnlength(const char* s, const std::size_t& n) + { + return strnlen(s,n); + } + #endif + } + + inline void remove_consecutives_inplace(const char* rem_chars, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_consecutives_inplace(multiple_char_delimiter_predicate( + rem_chars, + rem_chars + details::strnlength(rem_chars,256)), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template + inline void remove_consecutives_inplace(Predicate predicate, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_consecutives_inplace(predicate, + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template + inline std::size_t remove_consecutives_inplace(Iterator begin, Iterator end) + { + if (0 == std::distance(begin,end)) return 0; + + Iterator itr1 = begin; ++itr1; + Iterator itr2 = begin; ++itr2; + typename std::iterator_traits::value_type prev = *begin; + std::size_t removal_count = 0; + + while (end != itr1) + { + while ((end != itr1) && (prev != (*itr1))) + { + if (itr1 != itr2) + { + (*itr2) = (*itr1); + } + prev = (*itr1); + ++itr1; + ++itr2; + } + + while ((end != itr1) && (prev == (*itr1))) + { + ++itr1; + ++removal_count; + } + } + + return removal_count; + } + + template + inline std::size_t remove_consecutives_inplace(const range::adapter& r) + { + return remove_consecutives_inplace(r.begin(),r.end()); + } + + template class Sequence> + inline void remove_consecutives_inplace(Sequence& sequence) + { + const std::size_t removal_count = remove_consecutives_inplace(sequence.begin(),sequence.end()); + sequence.resize(sequence.size() - removal_count); + } + + inline void remove_consecutives_inplace(std::string& s) + { + std::size_t removal_count = remove_consecutives_inplace(const_cast(s.data()), + const_cast(s.data() + s.size())); + + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline std::string remove_duplicates(const std::string& str) + { + std::string::value_type table[0xFF]; + std::fill_n(table,0xFF,static_cast(0)); + std::string result; + result.reserve(str.size()); + for (std::size_t i = 0; i < str.size(); ++i) + { + const char c = str[i]; + if (0 == table[static_cast(c)]) + { + table[static_cast(c)] = 0x01; + result += c; + } + } + return result; + } + + inline std::string remove_duplicates_inplace(std::string& str) + { + return remove_duplicates(str); + } + + template + inline std::size_t remove_trailing(Predicate predicate, + Iterator begin, + Iterator end) + { + const std::size_t length = std::distance(begin,end); + if (0 == length) + return 0; + Iterator itr = begin + (length - 1); + std::size_t removal_count = 0; + + while ((begin != itr) && predicate(*itr)) + { + --itr; + ++removal_count; + } + + return removal_count; + } + + template + inline std::size_t remove_trailing(Predicate predicate, const range::adapter& r) + { + return remove_trailing(predicate,r.begin(),r.end()); + } + + inline void remove_trailing(const std::string::value_type c, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_trailing(single_delimiter_predicate(c), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline void remove_trailing(const std::string& rem_chars, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_trailing(multiple_char_delimiter_predicate(rem_chars), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline void remove_trailing(const char* rem_chars, std::string& s) + { + const std::size_t removal_count = remove_trailing(multiple_char_delimiter_predicate( + rem_chars, + rem_chars + details::strnlength(rem_chars,256)), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template + inline void remove_trailing(Predicate predicate, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_trailing(predicate, + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template + inline std::size_t remove_leading(Predicate predicate, + Iterator begin, + Iterator end) + { + const std::size_t length = std::distance(begin,end); + if (0 == length) + return 0; + Iterator itr = begin; + std::size_t removal_count = 0; + + while ((end != itr) && predicate(*itr)) + { + ++itr; + ++removal_count; + } + + std::copy(itr,end,begin); + return removal_count; + } + + template + inline std::size_t remove_leading(Predicate predicate, const range::adapter& r) + { + return remove_leading(predicate,r.begin(),r.end()); + } + + inline void remove_leading(const std::string::value_type c, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_leading(single_delimiter_predicate(c), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline void remove_leading(const std::string& rem_chars, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_leading(multiple_char_delimiter_predicate(rem_chars), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline void remove_leading(const char* rem_chars, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_leading(multiple_char_delimiter_predicate( + rem_chars, + rem_chars + details::strnlength(rem_chars,256)), + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + inline void remove_leading_trailing(const std::string& rem_chars, std::string& s) + { + remove_leading(rem_chars,s); + remove_trailing(rem_chars,s); + } + + template + inline void remove_leading(Predicate predicate, std::string& s) + { + if (s.empty()) return; + const std::size_t removal_count = remove_leading(predicate, + const_cast(s.data()), + const_cast(s.data() + s.size())); + if (removal_count > 0) + { + s.resize(s.size() - removal_count); + } + } + + template class Sequence> + void remove_empty_strings(Sequence& seq) + { + struct is_empty { static inline bool check(const std::string& s) { return s.empty(); } }; + seq.erase(std::remove_if(seq.begin(),seq.end(),is_empty::check),seq.end()); + } + + template + void remove_empty_strings(std::list& l) + { + struct is_empty { static inline bool check(const std::string& s) { return s.empty(); } }; + l.remove_if(is_empty::check); + } + + template + void remove_empty_strings(std::set& set) + { + struct is_empty { static inline bool check(const std::string& s) { return s.empty(); } }; + typename std::set::iterator itr = set.begin(); + while (set.end() != itr) + { + if ((*itr).empty()) + set.erase(itr++); + else + ++itr; + } + } + + template + void remove_empty_strings(std::multiset& set) + { + struct is_empty { static inline bool check(const std::string& s) { return s.empty(); } }; + typename std::multiset::iterator itr = set.begin(); + while (set.end() != itr) + { + if ((*itr).empty()) + set.erase(itr++); + else + ++itr; + } + } + + template + inline void replace(const typename std::iterator_traits::value_type& c1, + const typename std::iterator_traits::value_type& c2, + const Iterator begin, + const Iterator end) + { + for (Iterator itr = begin; end != itr; ++itr) + { + if (c1 == (*itr)) + { + (*itr) = c2; + } + } + } + + inline void replace(const std::string::value_type& c0, + const std::string::value_type& c1, + std::string& s) + { + replace(c0,c1,const_cast(s.data()),const_cast(s.data() + s.size())); + } + + template + inline void replace(const T& c1, const T& c2, const range::adapter& r) + { + replace(c1,c2,r.begin(),r.end()); + } + + inline void replace_pattern(const std::string& s, // input + const std::string& p, // pattern + const std::string& r, // replacement + std::string& n) + { + if (p.empty() || (p == r)) + { + n.assign(s); + return; + } + + const std::size_t p_size = p.size(); + const std::size_t r_size = r.size(); + int inc = static_cast(r_size) - static_cast(p_size); + std::size_t pos = 0; + std::vector delta_list; + delta_list.reserve(std::min(32,(s.size() / p_size) + 1)); + + while (std::string::npos != (pos = s.find(p,pos))) + { + delta_list.push_back(pos); + pos += p_size; + } + + if (delta_list.empty()) + { + n.assign(s); + return; + } + + n.resize(delta_list.size() * inc + s.size(), 0x00); + char* n_itr = const_cast(n.data()); + const char* s_end = s.data() + s.size(); + const char* s_itr = s.data(); + const char* r_begin = r.data(); + const char* r_end = r.data() + r_size; + const std::size_t delta_list_size = delta_list.size(); + std::size_t i = 0; + std::size_t delta = delta_list[0]; + + for ( ; ; ) + { + std::copy(s_itr, s_itr + delta, n_itr); + s_itr += p_size + delta; + n_itr += delta; + std::copy(r_begin, r_end, n_itr); + n_itr += r_size; + if (++i >= delta_list_size) + break; + delta = delta_list[i] - (delta_list[i - 1] + p_size); + } + + if (s_end != s_itr) + { + std::copy(s_itr, s_end, n_itr); + } + } + + template + inline std::size_t replace_pattern(const InputIterator s_begin, const InputIterator s_end, // input + const InputIterator p_begin, const InputIterator p_end, // pattern + const InputIterator r_begin, const InputIterator r_end, // replacement + OutputIterator out) + { + InputIterator s_itr = s_begin; + InputIterator r_itr = r_begin; + InputIterator p_itr = p_begin; + + const std::size_t p_size = std::distance(p_begin,p_end); + const std::size_t r_size = std::distance(r_begin,r_end); + + if ((0 == p_size) || ((p_size == r_size) && std::equal(p_begin,p_end,r_begin))) + { + std::copy(s_begin,s_end,out); + return std::distance(s_begin,s_end); + } + + std::size_t pos = 0; + std::size_t prev_pos = 0; + std::size_t count = 0; + std::size_t new_size = std::distance(s_begin,s_end); + int inc = r_size - p_size; + + InputIterator temp_s_itr = s_itr; + + while (s_end != s_itr) + { + /* + Need to replace the following search code with + Knuth-Pratt-Morris or Boyer-Moore string search + algorithms. + */ + bool found = true; + p_itr = p_begin; + temp_s_itr = s_itr; + + while ((p_end != p_itr) && (s_end != temp_s_itr)) + { + if (*(temp_s_itr++) != *(p_itr++)) + { + found = false; + break; + } + } + + if (found && (p_itr == p_end)) + { + ++count; + new_size += inc; + s_itr = temp_s_itr; + } + else + ++s_itr; + } + + s_itr = s_begin; + p_itr = p_begin; + + pos = 0; + prev_pos = 0; + + temp_s_itr = s_itr; + + while (0 < count) + { + p_itr = p_begin; + bool found = true; + InputIterator pattern_start = temp_s_itr; + + while ((p_end != p_itr) && (s_end != temp_s_itr)) + { + if (*(temp_s_itr++) != *(p_itr++)) + { + found = false; + temp_s_itr = pattern_start; + ++temp_s_itr; + break; + } + } + + if (!found || (p_itr != p_end)) continue; + + pos = std::distance(s_begin,temp_s_itr) - p_size; + int diff = pos - prev_pos; + + std::copy(s_itr,s_itr + diff, out); + s_itr = temp_s_itr; + std::copy(r_itr,r_end, out); + + pos += p_size; + prev_pos = pos; + --count; + } + + std::copy(s_itr,s_end,out); + + return new_size; + } + + inline void remove_pattern(const std::string& s, + const std::string& p, + std::string& n) + { + static const std::string r(""); + replace_pattern(s,p,r,n); + } + + inline void sort(std::string& s) + { + std::sort(s.begin(),s.end()); + } + + template + inline bool match(const Iterator pattern_begin, + const Iterator pattern_end, + const Iterator data_begin, + const Iterator data_end, + const typename std::iterator_traits::value_type& zero_or_more, + const typename std::iterator_traits::value_type& zero_or_one) + { + /* + Credits: Adapted from code by Jack Handy (2001) + */ + if (0 == std::distance(data_begin,data_end)) return false; + + Iterator d_itr = data_begin; + Iterator p_itr = pattern_begin; + Iterator c_itr = data_begin; + Iterator m_itr = data_begin; + + while ((data_end != d_itr) && (zero_or_more != (*p_itr))) + { + if (((*p_itr) != (*d_itr)) && (zero_or_one != (*p_itr))) + { + return false; + } + ++p_itr; + ++d_itr; + } + + while (data_end != d_itr) + { + if (zero_or_more == (*p_itr)) + { + if (pattern_end == (++p_itr)) + { + return true; + } + m_itr = p_itr; + c_itr = d_itr; + ++c_itr; + } + else if (((*p_itr) == (*d_itr)) || (zero_or_one == (*p_itr))) + { + ++p_itr; + ++d_itr; + } + else + { + p_itr = m_itr; + d_itr = c_itr++; + } + } + + while ((p_itr != pattern_end) && (zero_or_more == (*p_itr))) ++p_itr; + + return (p_itr == pattern_end); + } + + inline bool match(const std::string& wild_card, + const std::string& str) + { + /* + * : Zero or more match + ? : Zero or one match + */ + return match(wild_card.data(), + wild_card.data() + wild_card.size(), + str.data(), + str.data() + str.size(), + '*', + '?'); + } + + inline bool imatch_char(const char c1, const char c2) + { + return std::toupper(c1) == std::toupper(c2); + } + + template + inline bool imatch(const InputIterator begin1, const InputIterator end1, + const InputIterator begin2, const InputIterator end2) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (std::distance(begin1,end1) != std::distance(begin2,end2)) + { + return false; + } + + InputIterator itr1 = begin1; + InputIterator itr2 = begin2; + + while (end1 != itr1) + { + //if (std::toupper(*itr1, std::locale::classic()) != std::toupper(*it2, std::locale::classic())) + if (std::toupper(*itr1) != std::toupper(*itr2)) + { + return false; + } + ++itr1; + ++itr2; + } + + return true; + } + + template + inline bool imatch(const range::adapter& r1, const range::adapter& r2) + { + return imatch(r1.begin(),r1.end(),r2.begin(),r2.end()); + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + return imatch(s1.data(), + s1.data() + s1.size(), + s2.data(), + s2.data() + s2.size()); + } + + template + inline Iterator imatch(const std::string& s, const Iterator begin, const Iterator end) + { + for (const std::string* itr = begin; end != itr; ++itr) + { + if (imatch(s,*itr)) + { + return itr; + } + } + return end; + } + + template class Sequence> + inline bool imatch(const std::string& s, const Sequence& sequence) + { + return (sequence.end() != imatch(s,sequence.begin(),sequence.end())); + } + + template + inline bool imatch(const std::string& s, const std::set& set) + { + return imatch(s,set.begin(),set.end()); + } + + template + inline bool imatch(const std::string& s, const std::multiset& multiset) + { + return imatch(s,multiset.begin(),multiset.end()); + } + + template + inline std::size_t find_all(const Iterator pattern_begin, + const Iterator pattern_end, + const Iterator begin, + const Iterator end, + OutputIterator out) + { + Iterator itr = begin; + const std::size_t pattern_length = std::distance(pattern_begin,pattern_end); + std::size_t match_count = 0; + while (end != (itr = std::search(itr, end, pattern_begin, pattern_end))) + { + (*out) = std::make_pair(itr,itr + pattern_length); + itr += pattern_length; + ++out; + ++match_count; + } + return match_count; + } + + template class Sequence> + inline std::size_t find_all(const Iterator pattern_begin, + const Iterator pattern_end, + const Iterator begin, + const Iterator end, + Sequence& seq) + { + return find_all(pattern_begin,pattern_end,begin,end,std::back_inserter(seq)); + } + + inline std::size_t ifind(const std::string& pattern, const std::string& data) + { + if (pattern.size() > data.size()) + return std::string::npos; + const char* result_itr = std::search(data.data(),data.data() + data.size(), + pattern.data(), pattern.data() + pattern.size(), + imatch_char); + if ((data.data() + data.size()) == result_itr) + return std::string::npos; + else + return std::distance(data.data(),result_itr); + } + + template + inline std::size_t ifind_all(const Iterator pattern_begin, + const Iterator pattern_end, + const Iterator begin, + const Iterator end, + OutputIterator out) + { + Iterator itr = begin; + const std::size_t pattern_length = std::distance(pattern_begin,pattern_end); + std::size_t match_count = 0; + + while (end != (itr = std::search(itr, end, pattern_begin, pattern_end, imatch_char))) + { + (*out) = std::make_pair(itr,itr + pattern_length); + itr += pattern_length; + ++out; + ++match_count; + } + + return match_count; + } + + template + inline std::size_t find_all(const std::string& pattern, + const std::string& data, + OutputIterator out) + { + return find_all(pattern.data(), pattern.data() + pattern.size(), + data.data(), data.data() + data.size(), + out); + } + + template class Sequence> + inline std::size_t find_all(const std::string& pattern, + const std::string& data, + Sequence& seq) + { + return find_all(pattern,data,std::back_inserter(seq)); + } + + template + inline std::size_t ifind_all(const std::string& pattern, + const std::string& data, + OutputIterator out) + { + return ifind_all(pattern.data(), pattern.data() + pattern.size(), + data.data(), data.data() + data.size(), + out); + } + + template class Sequence> + inline std::size_t ifind_all(const std::string& pattern, + const std::string& data, + Sequence& seq) + { + return ifind_all(pattern,data,std::back_inserter(seq)); + } + + template + inline bool begins_with(const InputIterator pattern_begin, + const InputIterator pattern_end, + const InputIterator begin, + const InputIterator end) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (std::distance(pattern_begin,pattern_end) <= std::distance(begin,end)) + { + return std::equal(pattern_begin,pattern_end,begin); + } + else + return false; + } + + inline bool begins_with(const std::string& pattern, const std::string& data) + { + if (pattern.size() <= data.size()) + { + return begins_with(pattern.data(), + pattern.data() + pattern.size(), + data.data(), + data.data() + data.size()); + } + else + return false; + } + + template + inline bool ibegins_with(const InputIterator pattern_begin, + const InputIterator pattern_end, + const InputIterator begin, + const InputIterator end) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (std::distance(pattern_begin,pattern_end) <= std::distance(begin,end)) + { + return std::equal(pattern_begin,pattern_end,begin,imatch_char); + } + else + return false; + } + + inline bool ibegins_with(const std::string& pattern, const std::string& data) + { + if (pattern.size() <= data.size()) + { + return ibegins_with(pattern.data(), + pattern.data() + pattern.size(), + data.data(), + data.data() + data.size()); + } + else + return false; + } + + template + inline bool ends_with(const InputIterator pattern_begin, + const InputIterator pattern_end, + const InputIterator begin, + const InputIterator end) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + const std::size_t pattern_length = std::distance(pattern_begin,pattern_end); + const std::size_t data_length = std::distance(begin,end); + if (pattern_length <= data_length) + { + return std::equal(pattern_begin, + pattern_end, + begin + (data_length - pattern_length)); + } + else + return false; + } + + inline bool ends_with(const std::string& pattern, const std::string& data) + { + if (pattern.size() <= data.size()) + { + return ends_with(pattern.data(), + pattern.data() + pattern.size(), + data.data(), + data.data() + data.size()); + } + else + return false; + } + + template + inline bool iends_with(const InputIterator pattern_begin, + const InputIterator pattern_end, + const InputIterator begin, + const InputIterator end) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + const std::size_t pattern_length = std::distance(pattern_begin,pattern_end); + const std::size_t data_length = std::distance(begin,end); + if (pattern_length <= data_length) + { + return std::equal(pattern_begin, + pattern_end, + begin + (data_length - pattern_length), + imatch_char); + } + else + return false; + } + + inline bool iends_with(const std::string& pattern, const std::string& data) + { + if (pattern.size() <= data.size()) + { + return iends_with(pattern.data(), + pattern.data() + pattern.size(), + data.data(), + data.data() + data.size()); + } + else + return false; + } + + inline std::size_t index_of(const std::string& pattern, const std::string& data) + { + if (pattern.empty()) + return std::string::npos; + else if (data.empty()) + return std::string::npos; + else if (pattern.size() > data.size()) + return std::string::npos; + const char* itr = std::search(data.data(), + data.data() + data.size(), + pattern.data(), + pattern.data() + pattern.size()); + return ((data.data() + data.size()) == itr) ? std::string::npos : std::distance(data.data(),itr); + } + + namespace tokenize_options + { + typedef std::size_t type; + enum + { + default_mode = 0, + compress_delimiters = 1, + include_1st_delimiter = 2, + include_all_delimiters = 4 + }; + + static inline bool perform_compress_delimiters(const type& split_opt) + { + return compress_delimiters == (split_opt & compress_delimiters); + } + + static inline bool perform_include_1st_delimiter(const type& split_opt) + { + return include_1st_delimiter == (split_opt & include_1st_delimiter); + } + + static inline bool perform_include_all_delimiters(const type& split_opt) + { + return include_all_delimiters == (split_opt & include_all_delimiters); + } + + } // namespace tokenize_options + + template + class tokenizer + { + private: + + template > + class tokenizer_iterator : public std::iterator + { + protected: + + typedef Iterator iterator; + typedef const iterator const_iterator; + typedef typename std::pair range_type; + + public: + + explicit inline tokenizer_iterator(const iterator begin, + const iterator end, + const Predicate& predicate, + const tokenize_options::type tokenize_option = tokenize_options::default_mode) + : predicate_(predicate), + end_(end), + range_(begin,begin), + current_token_(end,end), + compress_delimiters_(tokenize_options::perform_compress_delimiters(tokenize_option)), + include_1st_delimiter_(tokenize_options::perform_include_1st_delimiter(tokenize_option)), + include_all_delimiters_(tokenize_options::perform_include_all_delimiters(tokenize_option)), + include_delimiters_(include_1st_delimiter_ || include_all_delimiters_), + last_token_done_(false) + { + if (end != begin) + { + this->operator++(); + } + } + + inline tokenizer_iterator& operator++() + { + if (last_token_done_) + { + range_.first = range_.second; + return (*this); + } + else if (end_ != range_.second) + { + range_.first = range_.second; + } + + while (end_ != range_.second) + { + if (predicate_(*(range_.second))) + { + if (include_delimiters_) + { + if (include_1st_delimiter_) + ++range_.second; + else if (include_all_delimiters_) + while ((end_ != range_.second) && predicate_(*(range_.second))) ++range_.second; + current_token_ = range_; + if ((!include_all_delimiters_) && compress_delimiters_) + while ((end_ != range_.second) && predicate_(*(range_.second))) ++range_.second; + } + else + { + current_token_ = range_; + if (compress_delimiters_) + while ((end_ != (++range_.second)) && predicate_(*(range_.second))) ; + else + ++range_.second; + } + return (*this); + } + else + ++range_.second; + } + + if (range_.first != range_.second) + { + current_token_.second = range_.second; + if (!last_token_done_) + { + if (predicate_(*(range_.second - 1))) + current_token_.first = range_.second; + else + current_token_.first = range_.first; + last_token_done_ = true; + } + else + range_.first = range_.second; + } + + return (*this); + } + + inline tokenizer_iterator operator++(int) + { + tokenizer_iterator tmp = (*this); + this->operator++(); + return tmp; + } + + inline tokenizer_iterator& operator+=(const int inc) + { + if (inc > 0) + { + for (int i = 0; i < inc; ++i, ++(*this)) ; + } + return (*this); + } + + inline T operator*() const + { + return current_token_; + } + + inline std::string as_string() const + { + return std::string(current_token_.first,current_token_.second); + } + + inline bool operator==(const tokenizer_iterator& itr) const + { + return (range_ == itr.range_) && (end_ == itr.end_); + } + + inline bool operator!=(const tokenizer_iterator& itr) const + { + return (range_ != itr.range_) || (end_ != itr.end_); + } + + inline tokenizer_iterator& operator=(const tokenizer_iterator& itr) + { + if (this != &itr) + { + range_ = itr.range_; + current_token_ = itr.current_token_; + end_ = itr.end_; + compress_delimiters_ = itr.compress_delimiters_; + include_1st_delimiter_ = itr.include_1st_delimiter_; + include_all_delimiters_ = itr.include_all_delimiters_; + include_delimiters_ = itr.include_delimiters_; + last_token_done_ = itr.last_token_done_; + } + return (*this); + } + + inline std::string remaining() const + { + return std::string(current_token_.first,end_); + } + + protected: + + const Predicate& predicate_; + iterator end_; + range_type range_; + range_type current_token_; + bool compress_delimiters_; + bool include_1st_delimiter_; + bool include_all_delimiters_; + bool include_delimiters_; + bool last_token_done_; + }; + + public: + + typedef typename std::iterator_traits::value_type value_type; + typedef DelimiterPredicate predicate; + typedef tokenizer_iterator iterator; + typedef const iterator const_iterator; + typedef iterator& iterator_ref; + typedef const_iterator& const_iterator_ref; + + inline tokenizer(const Iterator begin, + const Iterator end, + const DelimiterPredicate& predicate, + const tokenize_options::type tokenize_options = tokenize_options::default_mode) + : tokenize_options_(tokenize_options), + predicate_(predicate), + begin_(begin), + end_(end), + begin_itr_(begin_,end_,predicate_,tokenize_options_), + end_itr_(end_,end_,predicate_,tokenize_options_) + {} + + inline tokenizer(const std::string& s, + const DelimiterPredicate& predicate, + const tokenize_options::type tokenize_options = tokenize_options::default_mode) + : tokenize_options_(tokenize_options), + predicate_(predicate), + begin_(s.data()), + end_(s.data() + s.size()), + begin_itr_(begin_,end_,predicate_,tokenize_options_), + end_itr_(end_,end_,predicate_,tokenize_options_) + {} + + inline tokenizer& operator=(const tokenizer& t) + { + if (this != &t) + { + begin_ = t.begin_; + end_ = t.end_; + end_itr_ = t.end_itr_; + begin_itr_ = t.begin_itr_; + tokenize_options_ = t.tokenize_options_; + } + return (*this); + } + + inline void assign(const std::string& s) const + { + assign(s.data(),s.data() + s.size()); + } + + inline void assign(const std::string& s) + { + assign(s.data(),s.data() + s.size()); + } + + inline void assign(const Iterator begin, const Iterator end) + { + begin_ = begin; + end_ = end; + begin_itr_ = iterator(begin_,end_,predicate_,tokenize_options_); + end_itr_ = iterator(end_,end_,predicate_,tokenize_options_); + } + + inline const_iterator_ref begin() const + { + return begin_itr_; + } + + inline const_iterator_ref end() const + { + return end_itr_; + } + + private: + + tokenize_options::type tokenize_options_; + const DelimiterPredicate& predicate_; + Iterator begin_; + Iterator end_; + iterator begin_itr_; + iterator end_itr_; + }; + + namespace std_string + { + template > + struct tokenizer + { + typedef DelimiterPredicate predicate_type; + typedef const std::string::value_type* string_iterator_type; + typedef strtk::tokenizer type; + typedef strtk::tokenizer md_type; + typedef std::pair iterator_type; + }; + + typedef tokenizer<>::iterator_type iterator_type; + typedef tokenizer<>::iterator_type range_t; + + typedef std::vector token_vector_type; + typedef std::deque token_deque_type; + typedef std::list token_list_type; + + } // namespace std_string + + template + class range_to_type_back_inserter_iterator : public std::iterator + { + public: + + typedef typename Sequence::value_type value_type; + + explicit inline range_to_type_back_inserter_iterator(Sequence& sequence) + : sequence_(sequence) + {} + + range_to_type_back_inserter_iterator(const range_to_type_back_inserter_iterator& it) + : sequence_(it.sequence_) + {} + + inline range_to_type_back_inserter_iterator& operator=(const range_to_type_back_inserter_iterator& it) + { + if (this != &it) + { + this->sequence_ = it.sequence_; + } + return (*this); + } + + template + inline range_to_type_back_inserter_iterator& operator=(const std::pair& r) + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + sequence_.push_back(t); + return (*this); + } + + inline range_to_type_back_inserter_iterator& operator=(const std::string& s) + { + value_type t; + if (string_to_type_converter(s.data(),s.data() + s.size(),t)) + sequence_.push_back(t); + return (*this); + } + + template + inline void operator()(const std::pair& r) const + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + sequence_.push_back(t); + } + + template + inline void operator()(const Iterator begin, const Iterator end) + { + sequence_.push_back(string_to_type_converter(begin,end)); + } + + inline range_to_type_back_inserter_iterator& operator*() + { + return (*this); + } + + inline range_to_type_back_inserter_iterator& operator++() + { + return (*this); + } + + inline range_to_type_back_inserter_iterator operator++(int) + { + return (*this); + } + + private: + + Sequence& sequence_; + }; + + template + inline range_to_type_back_inserter_iterator range_to_type_back_inserter(Sequence& sequence) + { + return (range_to_type_back_inserter_iterator(sequence)); + } + + template + class range_to_type_inserter_iterator : public std::iterator + { + public: + + typedef typename Set::value_type value_type; + + explicit inline range_to_type_inserter_iterator(Set& set) + : set_(set) + {} + + range_to_type_inserter_iterator(const range_to_type_inserter_iterator& it) + : set_(it.set_) + {} + + inline range_to_type_inserter_iterator& operator=(const range_to_type_inserter_iterator& it) + { + if (this != &it) + { + this->set_ = it.set_; + } + return (*this); + } + + template + inline range_to_type_inserter_iterator& operator=(const std::pair& r) + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + set_.insert(t); + return (*this); + } + + template + inline void operator()(const std::pair& r) + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + set_.insert(t); + } + + inline range_to_type_inserter_iterator& operator*() + { + return (*this); + } + + inline range_to_type_inserter_iterator& operator++() + { + return (*this); + } + + inline range_to_type_inserter_iterator operator++(int) + { + return (*this); + } + + private: + + Set& set_; + }; + + template + inline range_to_type_inserter_iterator range_to_type_inserter(Set& set) + { + return (range_to_type_inserter_iterator(set)); + } + + template + class range_to_type_push_inserter_iterator : public std::iterator + { + public: + + typedef typename Container::value_type value_type; + + explicit inline range_to_type_push_inserter_iterator(Container& container) + : container_(container) + {} + + range_to_type_push_inserter_iterator(const range_to_type_push_inserter_iterator& it) + : container_(it.container_) + {} + + inline range_to_type_push_inserter_iterator& operator=(const range_to_type_push_inserter_iterator& it) + { + if (this != &it) + { + this->container_ = it.container_; + } + return (*this); + } + + template + inline range_to_type_push_inserter_iterator& operator=(const std::pair& r) + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + container_.push(t); + return (*this); + } + + template + inline void operator()(const std::pair& r) + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + container_.push(t); + } + + inline range_to_type_push_inserter_iterator& operator*() + { + return (*this); + } + + inline range_to_type_push_inserter_iterator& operator++() + { + return (*this); + } + + inline range_to_type_push_inserter_iterator operator++(int) + { + return (*this); + } + + private: + + Container& container_; + }; + + template + inline range_to_type_push_inserter_iterator range_to_type_push_inserter(Container& container) + { + return (range_to_type_push_inserter_iterator(container)); + } + + template + class back_inserter_with_valuetype_iterator : public std::iterator + { + public: + + explicit inline back_inserter_with_valuetype_iterator(Sequence& sequence) + : sequence_(sequence) + {} + + back_inserter_with_valuetype_iterator(const back_inserter_with_valuetype_iterator& it) + : sequence_(it.sequence_) + {} + + inline back_inserter_with_valuetype_iterator& operator=(const back_inserter_with_valuetype_iterator& it) + { + if (this != &it) + { + this->sequence_ = it.sequence_; + } + return (*this); + } + + inline back_inserter_with_valuetype_iterator& operator=(const typename Sequence::value_type& v) + { + sequence_.push_back(v); + return (*this); + } + + inline void operator()(const typename Sequence::value_type& v) + { + sequence_.push_back(v); + } + + inline back_inserter_with_valuetype_iterator& operator*() + { + return (*this); + } + + inline back_inserter_with_valuetype_iterator& operator++() + { + return (*this); + } + + inline back_inserter_with_valuetype_iterator operator++(int) + { + return (*this); + } + + private: + + Sequence& sequence_; + }; + + template + inline back_inserter_with_valuetype_iterator back_inserter_with_valuetype(Sequence& sequence_) + { + return (back_inserter_with_valuetype_iterator(sequence_)); + } + + template + class inserter_with_valuetype_iterator : public std::iterator + { + public: + + explicit inline inserter_with_valuetype_iterator(Set& set) + : set_(set) + {} + + inserter_with_valuetype_iterator(const inserter_with_valuetype_iterator& itr) + : set_(itr.set_) + {} + + inline inserter_with_valuetype_iterator& operator=(const inserter_with_valuetype_iterator& itr) + { + if (this != &itr) + { + this->set_ = itr.set_; + } + return (*this); + } + + inline inserter_with_valuetype_iterator& operator=(const typename Set::value_type& v) + { + set_.insert(v); + return (*this); + } + + inline void operator()(const typename Set::value_type& v) + { + set_.insert(v); + } + + inline inserter_with_valuetype_iterator& operator*() + { + return (*this); + } + + inline inserter_with_valuetype_iterator& operator++() + { + return (*this); + } + + inline inserter_with_valuetype_iterator operator++(int) + { + return (*this); + } + + private: + + Set& set_; + }; + + template + inline inserter_with_valuetype_iterator inserter_with_valuetype(Set& set_) + { + return (inserter_with_valuetype_iterator(set_)); + } + + template + class push_inserter_iterator : public std::iterator + { + public: + + explicit inline push_inserter_iterator(Container& container) + : container_(container) + {} + + inline push_inserter_iterator& operator=(const push_inserter_iterator& itr) + { + if (this != &itr) + { + this->container_ = itr.container_; + } + return (*this); + } + + inline push_inserter_iterator& operator=(typename Container::const_reference v) + { + container_.push(v); + return (*this); + } + + inline push_inserter_iterator& operator*() + { + return (*this); + } + + inline push_inserter_iterator& operator++() + { + return (*this); + } + + inline push_inserter_iterator operator++(int) + { + return (*this); + } + + private: + + Container& container_; + }; + + template + inline push_inserter_iterator push_inserter(Container& c) + { + return push_inserter_iterator(c); + } + + template + class range_to_ptr_type_iterator : public std::iterator + { + public: + + typedef T value_type; + + explicit inline range_to_ptr_type_iterator(T* pointer, std::size_t& insert_count) + : pointer_(pointer), + insert_count_(insert_count) + {} + + range_to_ptr_type_iterator(const range_to_ptr_type_iterator& it) + : pointer_(it.pointer_) + {} + + inline range_to_ptr_type_iterator& operator=(const range_to_ptr_type_iterator& it) + { + if (this != &it) + { + this->pointer_ = it.pointer_; + } + return (*this); + } + + template + inline range_to_ptr_type_iterator& operator=(const std::pair& r) + { + value_type t = value_type(); + if (string_to_type_converter(r.first,r.second,t)) + { + (*pointer_) = t; + ++pointer_; + ++insert_count_; + } + return (*this); + } + + inline range_to_ptr_type_iterator& operator=(const std::string& s) + { + value_type t = value_type(); + if (string_to_type_converter(s.data(),s.data() + s.size(),t)) + { + (*pointer_) = t; + ++pointer_; + ++insert_count_; + } + return (*this); + } + + template + inline void operator()(const std::pair& r) const + { + value_type t; + if (string_to_type_converter(r.first,r.second,t)) + { + (*pointer_) = t; + ++pointer_; + ++insert_count_; + } + } + + template + inline void operator()(const Iterator begin, const Iterator end) + { + (*pointer_) = string_to_type_converter(begin,end); + ++pointer_; + ++insert_count_; + } + + inline range_to_ptr_type_iterator& operator*() + { + return (*this); + } + + inline range_to_ptr_type_iterator& operator++() + { + return (*this); + } + + inline range_to_ptr_type_iterator operator++(int) + { + return (*this); + } + + private: + + T* pointer_; + std::size_t& insert_count_; + }; + + template + inline range_to_ptr_type_iterator range_to_ptr_type(T* pointer, std::size_t& insert_count) + { + return (range_to_ptr_type_iterator(pointer,insert_count)); + } + + template + inline range_to_ptr_type_iterator range_to_ptr_type(T* pointer) + { + static std::size_t insert_count = 0; + return (range_to_ptr_type_iterator(pointer,insert_count)); + } + + template + class counting_back_inserter_iterator : public std::iterator + { + public: + + explicit inline counting_back_inserter_iterator(std::size_t& counter) + : counter_(counter) + {} + + counting_back_inserter_iterator(const counting_back_inserter_iterator& itr) + : counter_(itr.counter_) + {} + + inline counting_back_inserter_iterator& operator=(const counting_back_inserter_iterator& itr) + { + if (this != &itr) + { + this->counter_ = itr.counter_; + } + return (*this); + } + + inline counting_back_inserter_iterator& operator=(const T&) + { + ++counter_; + return (*this); + } + + inline void operator()(const T&) + { + ++counter_; + } + + inline counting_back_inserter_iterator& operator*() + { + return (*this); + } + + inline counting_back_inserter_iterator& operator++() + { + return (*this); + } + + inline counting_back_inserter_iterator operator++(int) + { + return (*this); + } + + private: + + std::size_t& counter_; + }; + + template + inline counting_back_inserter_iterator counting_back_inserter(std::size_t& counter_) + { + return (counting_back_inserter_iterator(counter_)); + } + + template + class functional_inserter_iterator : public std::iterator + { + public: + + explicit inline functional_inserter_iterator(Function function) + : function_(function) + {} + + functional_inserter_iterator(const functional_inserter_iterator& it) + : function_(it.function_) + {} + + inline functional_inserter_iterator& operator=(const functional_inserter_iterator& it) + { + if (this != &it) + { + this->function_ = it.function_; + } + return (*this); + } + + template + inline functional_inserter_iterator& operator=(const T& t) + { + function_(t); + return (*this); + } + + template + inline void operator()(const T& t) + { + function_(t); + } + + inline functional_inserter_iterator& operator*() + { + return (*this); + } + + inline functional_inserter_iterator& operator++() + { + return (*this); + } + + inline functional_inserter_iterator operator++(int) + { + return (*this); + } + + private: + + Function function_; + }; + + template + inline functional_inserter_iterator functional_inserter(Function function) + { + return (functional_inserter_iterator(function)); + } + + namespace split_options + { + typedef std::size_t type; + enum + { + default_mode = 0, + compress_delimiters = 1, + include_1st_delimiter = 2, + include_all_delimiters = 4 + }; + + static inline bool perform_compress_delimiters(const type& split_opt) + { + return compress_delimiters == (split_opt & compress_delimiters); + } + + static inline bool perform_include_1st_delimiter(const type& split_opt) + { + return include_1st_delimiter == (split_opt & include_1st_delimiter); + } + + static inline bool perform_include_all_delimiters(const type& split_opt) + { + return include_all_delimiters == (split_opt & include_all_delimiters); + } + + } // namespace split_options + + namespace details + { + template + inline std::size_t split_compress_delimiters(const DelimiterPredicate& delimiter, + const Iterator begin, + const Iterator end, + OutputIterator out) + { + std::size_t token_count = 0; + std::pair range(begin,begin); + + while (end != range.second) + { + if (delimiter(*range.second)) + { + (*out) = range; + ++out; + while ((end != ++range.second) && delimiter(*range.second)); + range.first = range.second; + if (end != range.second) + ++range.second; + ++token_count; + } + else + ++range.second; + } + + if ((range.first != range.second) || delimiter(*(range.second - 1))) + { + (*out) = range; + ++out; + ++token_count; + } + + return token_count; + } + } + + template + inline std::size_t split(const DelimiterPredicate& delimiter, + const Iterator begin, + const Iterator end, + OutputIterator out, + const split_options::type split_option = split_options::default_mode) + { + if (begin == end) return 0; + const bool compress_delimiters = split_options::perform_compress_delimiters(split_option); + const bool include_1st_delimiter = split_options::perform_include_1st_delimiter(split_option); + const bool include_all_delimiters = (!include_1st_delimiter) && split_options::perform_include_all_delimiters(split_option); + const bool include_delimiters = include_1st_delimiter || include_all_delimiters; + + if (compress_delimiters && (!include_delimiters)) + { + return details::split_compress_delimiters(delimiter,begin,end,out); + } + + std::size_t token_count = 0; + std::pair range(begin,begin); + + while (end != range.second) + { + if (delimiter(*range.second)) + { + if (include_delimiters) + { + if (include_1st_delimiter) + ++range.second; + else if (include_all_delimiters) + while ((end != range.second) && delimiter(*range.second)) ++range.second; + (*out) = range; + ++out; + if ((!include_all_delimiters) && compress_delimiters) + while ((end != range.second) && delimiter(*range.second)) ++range.second; + } + else + { + (*out) = range; + ++out; + ++range.second; + } + ++token_count; + range.first = range.second; + } + else + ++range.second; + } + + if ((range.first != range.second) || delimiter(*(range.second - 1))) + { + (*out) = range; + ++out; + ++token_count; + } + + return token_count; + } + + template + inline std::size_t split(const DelimiterPredicate& delimiter, + const std::pair& range, + OutputIterator out, + const split_options::type split_option = split_options::default_mode) + { + return split(delimiter, + range.first,range.second, + out, + split_option); + } + + template + inline std::size_t split(const char* delimiters, + const std::pair& range, + OutputIterator out, + const split_options::type split_option = split_options::default_mode) + { + if (1 == details::strnlength(delimiters,256)) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + out, + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + out, + split_option); + } + + template + inline std::size_t split(const std::string& delimiters, + const std::pair& range, + OutputIterator out, + const split_options::type split_option = split_options::default_mode) + { + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + out, + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + out, + split_option); + } + + template + inline std::size_t split(const char* delimiters, + const std::string& str, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + if (1 == details::strnlength(delimiters,256)) + return split(single_delimiter_predicate(delimiters[0]), + str.data(), str.data() + str.size(), + out, + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + str.data(), str.data() + str.size(), + out, + split_option); + } + + template + inline std::size_t split(const std::string& delimiters, + const std::string& str, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + str.data(), str.data() + str.size(), + out, + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + str.data(), str.data() + str.size(), + out, + split_option); + } + + template + inline std::size_t split(const std::string::value_type delimiter, + const std::string& str, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + return split(single_delimiter_predicate(delimiter), + str.data(), str.data() + str.size(), + out, + split_option); + } + + template class Sequence> + inline std::size_t split(const char* delimiters, + const std::string& str, + Sequence,Allocator>& sequence, + const split_options::type& split_option = split_options::default_mode) + { + if (1 == details::strnlength(delimiters,256)) + return split(single_delimiter_predicate(delimiters[0]), + str.data(), str.data() + str.size(), + std::back_inserter(sequence), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + str.data(), str.data() + str.size(), + std::back_inserter(sequence), + split_option); + } + + template class Sequence> + inline std::size_t split(const std::string& delimiters, + const std::string& str, + Sequence,Allocator>& sequence, + const split_options::type& split_option = split_options::default_mode) + { + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + str.data(), str.data() + str.size(), + std::back_inserter(sequence), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + str.data(), str.data() + str.size(), + std::back_inserter(sequence), + split_option); + } + + template + inline std::size_t split(const DelimiterPredicate& delimiter, + const std::string& str, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + return split(delimiter, + str.data(), str.data() + str.size(), + out, + split_option); + } + + template + inline std::size_t split_n(const DelimiterPredicate& delimiter, + const Iterator begin, + const Iterator end, + const std::size_t& token_count, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + if (0 == token_count) return 0; + if (begin == end) return 0; + std::size_t match_count = 0; + std::pair range(begin,begin); + const bool compress_delimiters = split_options::perform_compress_delimiters(split_option); + const bool include_1st_delimiter = split_options::perform_include_1st_delimiter(split_option); + const bool include_all_delimiters = (!include_1st_delimiter) && split_options::perform_include_all_delimiters(split_option); + const bool include_delimiters = include_1st_delimiter || include_all_delimiters; + + while (end != range.second) + { + if (delimiter(*range.second)) + { + if (include_delimiters) + { + ++range.second; + (*out) = range; + ++out; + if (++match_count >= token_count) + return match_count; + if (compress_delimiters) + while ((end != range.second) && delimiter(*range.second)) ++range.second; + } + else + { + (*out) = range; + ++out; + if (++match_count >= token_count) + return match_count; + if (compress_delimiters) + while ((end != (++range.second)) && delimiter(*range.second)) ; + else + ++range.second; + } + range.first = range.second; + } + else + ++range.second; + } + + if ((range.first != range.second) || delimiter(*(range.second - 1))) + { + (*out) = range; + ++out; + ++match_count; + } + + return match_count; + } + + template + inline std::size_t split_n(const char* delimiters, + const std::string& str, + const std::size_t& token_count, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + return split_n(multiple_char_delimiter_predicate(delimiters), + str.data(), str.data() + str.size(), + token_count, + out, + split_option); + } + + template + inline std::size_t split_n(const std::string& delimiters, + const std::string& str, + const std::size_t& token_count, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + if (1 == delimiters.size()) + return split_n(single_delimiter_predicate(delimiters[0]), + str.data(), str.data() + str.size(), + token_count, + out, + split_option); + else + return split_n(multiple_char_delimiter_predicate(delimiters), + str.data(), str.data() + str.size(), + token_count, + out, + split_option); + } + + template + inline std::size_t split_n(const std::string& delimiters, + const InputIterator begin, + const InputIterator end, + const std::size_t& token_count, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + token_count, + out, + split_option); + else + return split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + token_count, + out, + split_option); + } + + template + inline std::size_t split_n(const std::string::value_type delimiter, + const std::string& str, + const std::size_t& token_count, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + return split_n(single_delimiter_predicate(delimiter), + str.data(),str.data() + str.size(), + token_count, + out, + split_option); + } + + template + inline std::size_t split_n(const DelimiterPredicate& delimiter, + const std::string& str, + const std::size_t& token_count, + OutputIterator out, + const split_options::type& split_option = split_options::default_mode) + { + return split_n(delimiter, + str.data(),str.data() + str.size(), + token_count, + out, + split_option); + } + + #ifdef strtk_enable_regex + + static const std::string uri_expression ("((https?|ftp)\\://((\\[?(\\d{1,3}\\.){3}\\d{1,3}\\]?)|(([-a-zA-Z0-9]+\\.)+[a-zA-Z]{2,4}))(\\:\\d+)?(/[-a-zA-Z0-9._?,+&%$#=~\\\\]+)*/?)"); + static const std::string email_expression ("([\\w\\-\\.]+)@((\\[([0-9]{1,3}\\.){3}[0-9]{1,3}\\])|(([\\w\\-]+\\.)+)([a-zA-Z]{2,4}))"); + static const std::string ip_expression ("(([0-2]*[0-9]+[0-9]+)\\.([0-2]*[0-9]+[0-9]+)\\.([0-2]*[0-9]+[0-9]+)\\.([0-2]*[0-9]+[0-9]+))"); + static const std::string ieee754_expression ("([-+]?((\\.[0-9]+|[0-9]+\\.[0-9]+)([eE][-+][0-9]+)?|[0-9]+))"); + + namespace regex_match_mode + { + enum type + { + match_all = 0, + match_1 = 1, + match_2 = 2, + match_3 = 3, + match_4 = 4, + match_5 = 5, + match_6 = 6, + match_7 = 7, + match_8 = 8, + match_9 = 9 + }; + } + + template + inline std::size_t split_regex(const boost::regex& delimiter_expression, + const InputIterator begin, + const InputIterator end, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + boost::regex_iterator itr(begin,end,delimiter_expression); + boost::regex_iterator itr_end; + std::pair range(begin,begin); + std::size_t match_count = 0; + while (itr_end != itr) + { + range.first = (*itr)[mode].first; + range.second = (*itr)[mode].second; + (*out) = range; + ++out; + ++itr; + ++match_count; + } + return match_count; + } + + template + inline std::size_t split_regex(const std::string& delimiter_expression, + const InputIterator begin, + const InputIterator end, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + const boost::regex regex_expression(delimiter_expression); + return split_regex(regex_expression, + begin,end, + out, + mode); + } + + template + inline std::size_t split_regex(const std::string& delimiter_expression, + const std::string& text, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + return split_regex(delimiter_expression, + text.begin(),text.end(), + out, + mode); + } + + template + inline std::size_t split_regex(const boost::regex& delimiter_expression, + const std::string& text, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + return split_regex(delimiter_expression, + text.begin(),text.end(), + out, + mode); + } + + template + inline std::size_t split_regex_n(const boost::regex& delimiter_expression, + const InputIterator begin, + const InputIterator end, + const std::size_t& token_count, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + boost::sregex_iterator itr(begin,end,delimiter_expression); + const boost::sregex_iterator itr_end; + std::pair range(begin,begin); + std::size_t match_count = 0; + while (itr_end != itr) + { + range.first = (*itr)[mode].first; + range.second = (*itr)[mode].second; + (*out) = range; + ++out; + ++itr; + if (++match_count >= token_count) + return match_count; + } + return match_count; + } + + template + inline std::size_t split_regex_n(const std::string& delimiter_expression, + const InputIterator begin, + const InputIterator end, + const std::size_t& token_count, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + const boost::regex regex_expression(delimiter_expression); + return split_regex_n(regex_expression, + begin,end, + token_count, + out, + mode); + } + + template + inline std::size_t split_regex_n(const std::string& delimiter_expression, + const std::string& text, + const std::size_t& token_count, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + return split_regex_n(delimiter_expression, + text.begin(),text.end(), + token_count, + out, + mode); + } + + template + inline std::size_t split_regex_n(const boost::regex& delimiter_expression, + const std::string& text, + const std::size_t& token_count, + OutputIterator out, + const regex_match_mode::type mode = regex_match_mode::match_all) + { + return split_regex_n(delimiter_expression, + text.begin(),text.end(), + token_count, + out, + mode); + } + + #endif // strtk_enable_regex + + template + class offset_predicate + { + public: + + offset_predicate(const int offset_list[], const bool rotate = false) + : rotate_(rotate), + current_index_(0) + { + std::copy(offset_list, offset_list + offset_list_size, offset_list_); + offset_list_[offset_list_size] = 0; + } + + inline bool operator!() const + { + return (0 == offset_list_size); + } + + inline void reset() const + { + current_index_ = 0; + } + + inline std::size_t size() const + { + return offset_list_size; + } + + inline int next() const + { + int result = offset_list_[current_index_++]; + if (rotate_ && (current_index_ >= offset_list_size)) + { + current_index_ = 0; + } + return result; + } + + private: + + bool rotate_; + mutable std::size_t current_index_; + int offset_list_[offset_list_size + 1]; + }; + + inline offset_predicate<12> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const int& v7, const int& v8, const int& v9, + const int& v10, const int& v11, const int& v12, + const bool& rotate = false) + { + const int offset_list[12] = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 }; + return offset_predicate<12>(offset_list,rotate); + } + + inline offset_predicate<11> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const int& v7, const int& v8, const int& v9, + const int& v10, const int& v11, + const bool& rotate = false) + { + const int offset_list[11] = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 }; + return offset_predicate<11>(offset_list,rotate); + } + + inline offset_predicate<10> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const int& v7, const int& v8, const int& v9, + const int& v10, const bool& rotate = false) + { + const int offset_list[10] = { v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 }; + return offset_predicate<10>(offset_list,rotate); + } + + inline offset_predicate<9> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const int& v7, const int& v8, const int& v9, + const bool& rotate = false) + { + const int offset_list[9] = { v1, v2, v3, v4, v5, v6, v7, v8, v9 }; + return offset_predicate<9>(offset_list,rotate); + } + + inline offset_predicate<8> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const int& v7, const int& v8, const bool& rotate = false) + { + const int offset_list[8] = { v1, v2, v3, v4, v5, v6, v7, v8 }; + return offset_predicate<8>(offset_list,rotate); + } + + inline offset_predicate<7> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const int& v7, const bool& rotate = false) + { + const int offset_list[7] = { v1, v2, v3, v4, v5, v6, v7 }; + return offset_predicate<7>(offset_list,rotate); + } + + inline offset_predicate<6> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const int& v6, + const bool& rotate = false) + { + const int offset_list[6] = { v1, v2, v3, v4, v5, v6 }; + return offset_predicate<6>(offset_list,rotate); + } + + inline offset_predicate<5> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const int& v5, const bool& rotate = false) + { + const int offset_list[5] = { v1, v2, v3, v4, v5 }; + return offset_predicate<5>(offset_list,rotate); + } + + inline offset_predicate<4> offsets(const int& v1, const int& v2, const int& v3, + const int& v4, const bool& rotate = false) + { + const int offset_list[4] = { v1, v2, v3, v4 }; + return offset_predicate<4>(offset_list,rotate); + } + + inline offset_predicate<3> offsets(const int& v1, const int& v2, const int& v3, + const bool& rotate = false) + { + const int offset_list[3] = { v1, v2, v3 }; + return offset_predicate<3>(offset_list,rotate); + } + + inline offset_predicate<2> offsets(const int& v1, const int& v2, const bool& rotate = false) + { + const int offset_list[2] = { v1, v2 }; + return offset_predicate<2>(offset_list,rotate); + } + + inline offset_predicate<1> offsets(const int& v1, + const bool& rotate = false) + { + const int offset_list[1] = { v1 }; + return offset_predicate<1>(offset_list,rotate); + } + + template + inline std::size_t offset_splitter(const InputIterator begin, + const InputIterator end, + const OffsetPredicate& offset, + OutputIterator out) + { + std::size_t length = 0; + if (0 == (length = std::distance(begin,end))) return 0; + std::pair range(begin,begin); + std::size_t match_count = 0; + int offset_length = 0; + std::size_t increment_amount = 0; + while ((end != range.second) && (0 < (offset_length = offset.next()))) + { + increment_amount = std::min(length,offset_length); + range.first = range.second; + range.second += increment_amount; + length -= increment_amount; + (*out) = range; + ++out; + ++match_count; + } + return match_count; + } + + template + inline std::size_t offset_splitter(const std::string& str, + const OffsetPredicate& offset, + OutputIterator out) + { + return offset_splitter(str.data(),str.data() + str.size(),offset,out); + } + + template + inline bool split_pair(const InputIterator begin, + const InputIterator end, + const Predicate& delimiter, + OutputPair& v1, + OutputPair& v2) + { + if (0 == std::distance(begin,end)) return false; + + InputIterator itr = begin; + + while (end != itr) + { + if (delimiter(*itr)) + { + v1 = std::make_pair(begin,itr); + ++itr; + if (0 != std::distance(itr,end)) + { + v2 = std::make_pair(itr,end); + return true; + } + else + return false; + } + else + ++itr; + } + + return false; + } + + inline bool split_pair(const std::string::value_type delimiter, + const std::string& str, + std::pair& v1, + std::pair& v2) + { + return split_pair(str.data(), + str.data() + str.size(), + single_delimiter_predicate(delimiter), + v1, + v2); + } + + template + inline bool split_pair(const DelimiterPredicate& delimiter, + const std::string& str, + std::pair& v1, + std::pair& v2) + { + return split_pair(str.data(), + str.data() + str.size(), + delimiter, + v1, + v2); + } + + template + inline std::size_t for_each_token(const std::string& buffer, + const std::string& delimiters, + Function function) + { + return split(delimiters, + buffer, + strtk::functional_inserter(function)); + } + + template + inline std::size_t for_each_token(const std::string& buffer, + const char* delimiters, + Function function) + { + return split(delimiters, + buffer, + strtk::functional_inserter(function)); + } + + template + inline std::size_t count_consecutive_duplicates(const InputIterator begin, const InputIterator end) + { + if (std::distance(begin,end) < 2) return 0; + InputIterator prev = begin; + InputIterator itr = begin; + std::size_t count = 0; + while (end != ++itr) + { + if ((*prev) == (*itr)) + ++count; + else + prev = itr; + } + return count; + } + + template class Sequence> + inline T min_of_cont(const Sequence& sequence) + { + return (*std::min_element(sequence.begin(),sequence.end())); + } + + template + inline T min_of_cont(const std::set& set) + { + return (*set.begin()); + } + + template + inline T min_of_cont(const std::multiset& multiset) + { + return (*multiset.begin()); + } + + template class Sequence> + inline T max_of_cont(const Sequence& sequence) + { + return (*std::max_element(sequence.begin(),sequence.end())); + } + + template + inline T max_of_cont(const std::set& set) + { + return (*set.rbegin()); + } + + template + inline T max_of_cont(const std::multiset& multiset) + { + return (*multiset.rbegin()); + } + + template + inline void min_max_of_range(const InputIterator begin, const InputIterator end, + typename std::iterator_traits::value_type& min_value, + typename std::iterator_traits::value_type& max_value) + { + min_value = *begin; + max_value = *begin; + InputIterator itr = begin; + while (end != ++itr) + { + if (*itr < min_value) + min_value = (*itr); + else if (*itr > max_value) + max_value = (*itr); + } + } + + template class Sequence> + inline void min_max_of_cont(const Sequence& sequence, + T& min_value, + T& max_value) + { + min_max_of_range(sequence.begin(),sequence.end(), + min_value, + max_value); + } + + template + inline void min_max_of_cont(const std::set& set, + T& min_value, + T& max_value) + { + min_value = (*set.begin()); + max_value = (*set.rbegin()); + } + + template + inline void min_max_of_cont(const std::multiset& multiset, + T& min_value, + T& max_value) + { + min_value = (*multiset.begin()); + max_value = (*multiset.rbegin()); + } + + template + inline void lexicographically_canonicalize(Iterator begin, Iterator end) + { + typedef typename std::iterator_traits::value_type type; + typedef typename std::pair iter_type; + typedef typename std::list itr_list_type; + itr_list_type itr_list; + + type smallest = (*std::min_element(begin,end)); + + for (Iterator itr = begin; itr != end; ++itr) + { + if (*itr == smallest) itr_list.push_back(std::make_pair(itr,itr)); + } + + while (itr_list.size() > 1) + { + typename itr_list_type::iterator itr = itr_list.begin(); + while (itr_list.end() != itr) + { + ++(*itr).first; + if (end == (*itr).first) + itr = itr_list.erase(itr); + else + ++itr; + } + + smallest = *(*itr_list.begin()).first; + + for (itr = (++itr_list.begin()); itr != itr_list.end(); ++itr) + { + if (*(*itr).first < smallest) + { + smallest = *(*itr).first; + } + } + + itr = itr_list.begin(); + while (itr_list.end() != itr) + { + if (*(*itr).first != smallest) + itr = itr_list.erase(itr); + else + ++itr; + } + + itr = itr_list.begin(); + while (itr_list.end() != itr) + { + if (end == (*itr).first) + itr = itr_list.erase(itr); + else + ++itr; + } + + } + + std::rotate(begin,(*itr_list.begin()).second,end); + } + + inline void lexicographically_canonicalize(std::string& str) + { + lexicographically_canonicalize(const_cast(str.data()), + const_cast(str.data() + str.size())); + } + + template class Sequence> + inline void lexicographically_canonicalize(Sequence& sequence) + { + lexicographically_canonicalize(sequence.begin(),sequence.end()); + } + + inline const char* first_non_repeated_char(const char* begin, const char* end) + { + static const std::size_t lut_size = 256; + unsigned long long int lut[lut_size]; + + std::fill_n(lut,lut_size,std::numeric_limits::max()); + + static const unsigned long long int not_yet_encountered = std::numeric_limits::max(); + static const unsigned long long int repeated = not_yet_encountered - 1; + + const char* itr = begin; + unsigned long long int position = 0; + while (end != itr) + { + unsigned long long int& element = lut[static_cast(*itr)]; + if (not_yet_encountered == element) + { + element = position; + } + else if (element < repeated) + { + element = repeated; + } + ++itr; + ++position; + } + + position = repeated; + + for (std::size_t i = 0; i < lut_size; ++i) + { + if (lut[i] < position) + position = lut[i]; + } + + return (repeated != position) ? (begin + position) : end; + } + + inline const unsigned char* first_non_repeated_char(const unsigned char* begin, const unsigned char* end) + { + char * b = reinterpret_cast(const_cast(begin)); + char * e = reinterpret_cast(const_cast(end)); + return const_cast(reinterpret_cast(const_cast(first_non_repeated_char(b,e)))); + } + + inline std::size_t first_non_repeated_char(const std::string& str) + { + if (str.empty()) + return static_cast(std::string::npos); + const char* itr = first_non_repeated_char(str.data(),str.data() + str.size()); + if ((str.data() + str.size()) != itr) + return static_cast(itr - str.data()); + else + return static_cast(std::string::npos); + } + + inline void convert_bin_to_hex(const unsigned char* begin, const unsigned char* end, unsigned char* out) + { + static const unsigned short hex_lut[] = + { + 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, + 0x3830, 0x3930, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 0x4630, + 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, + 0x3831, 0x3931, 0x4131, 0x4231, 0x4331, 0x4431, 0x4531, 0x4631, + 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, + 0x3832, 0x3932, 0x4132, 0x4232, 0x4332, 0x4432, 0x4532, 0x4632, + 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, + 0x3833, 0x3933, 0x4133, 0x4233, 0x4333, 0x4433, 0x4533, 0x4633, + 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, + 0x3834, 0x3934, 0x4134, 0x4234, 0x4334, 0x4434, 0x4534, 0x4634, + 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, + 0x3835, 0x3935, 0x4135, 0x4235, 0x4335, 0x4435, 0x4535, 0x4635, + 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, + 0x3836, 0x3936, 0x4136, 0x4236, 0x4336, 0x4436, 0x4536, 0x4636, + 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, + 0x3837, 0x3937, 0x4137, 0x4237, 0x4337, 0x4437, 0x4537, 0x4637, + 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, + 0x3838, 0x3938, 0x4138, 0x4238, 0x4338, 0x4438, 0x4538, 0x4638, + 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, + 0x3839, 0x3939, 0x4139, 0x4239, 0x4339, 0x4439, 0x4539, 0x4639, + 0x3041, 0x3141, 0x3241, 0x3341, 0x3441, 0x3541, 0x3641, 0x3741, + 0x3841, 0x3941, 0x4141, 0x4241, 0x4341, 0x4441, 0x4541, 0x4641, + 0x3042, 0x3142, 0x3242, 0x3342, 0x3442, 0x3542, 0x3642, 0x3742, + 0x3842, 0x3942, 0x4142, 0x4242, 0x4342, 0x4442, 0x4542, 0x4642, + 0x3043, 0x3143, 0x3243, 0x3343, 0x3443, 0x3543, 0x3643, 0x3743, + 0x3843, 0x3943, 0x4143, 0x4243, 0x4343, 0x4443, 0x4543, 0x4643, + 0x3044, 0x3144, 0x3244, 0x3344, 0x3444, 0x3544, 0x3644, 0x3744, + 0x3844, 0x3944, 0x4144, 0x4244, 0x4344, 0x4444, 0x4544, 0x4644, + 0x3045, 0x3145, 0x3245, 0x3345, 0x3445, 0x3545, 0x3645, 0x3745, + 0x3845, 0x3945, 0x4145, 0x4245, 0x4345, 0x4445, 0x4545, 0x4645, + 0x3046, 0x3146, 0x3246, 0x3346, 0x3446, 0x3546, 0x3646, 0x3746, + 0x3846, 0x3946, 0x4146, 0x4246, 0x4346, 0x4446, 0x4546, 0x4646 + }; + + for (const unsigned char* itr = begin; end != itr; ++itr) + { + *reinterpret_cast(out) = hex_lut[(*itr)]; + out += sizeof(unsigned short); + } + } + + inline void convert_bin_to_hex(const char* begin, const char* end, char* out) + { + convert_bin_to_hex(reinterpret_cast(begin), + reinterpret_cast(end), + reinterpret_cast(out)); + } + + inline void convert_bin_to_hex(const std::pair& r, unsigned char* out) + { + convert_bin_to_hex(r.first,r.second,out); + } + + inline void convert_bin_to_hex(const std::pair& r, unsigned char* out) + { + convert_bin_to_hex(r.first,r.second,out); + } + + inline void convert_bin_to_hex(const std::pair& r, char* out) + { + convert_bin_to_hex(r.first,r.second,out); + } + + inline void convert_bin_to_hex(const std::string& binary_data, std::string& output) + { + output.resize(binary_data.size() * 2); + convert_bin_to_hex(binary_data.data(), + binary_data.data() + binary_data.size(), + const_cast(output.data())); + } + + inline std::string convert_bin_to_hex(const std::string& binary_data) + { + std::string output; + convert_bin_to_hex(binary_data,output); + return output; + } + + inline bool convert_hex_to_bin(const unsigned char* begin, const unsigned char* end, unsigned char* out) + { + const std::size_t length = std::distance(begin,end); + if (0 == length) + return false; + else if (1 == (length % 2)) + return false; + static const unsigned char hex_to_bin[] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 - 0x07 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x08 - 0x0F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 - 0x17 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x18 - 0x1F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 - 0x27 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x28 - 0x2F + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37 + 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x38 - 0x3F + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x40 - 0x47 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x48 - 0x4F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 - 0x57 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 - 0x5F + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, // 0x60 - 0x67 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 - 0x6F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 - 0x77 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 - 0x7F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 - 0x87 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 - 0x8F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 - 0x97 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 - 0x9F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA0 - 0xA7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xA8 - 0xAF + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB0 - 0xB7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xB8 - 0xBF + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC0 - 0xC7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xC8 - 0xCF + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD0 - 0xD7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xD8 - 0xDF + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE0 - 0xE7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xE8 - 0xEF + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xF0 - 0xF7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0xF8 - 0xFF + }; + + const unsigned char* itr = begin; + while (end != itr) + { + *reinterpret_cast(out) = static_cast(hex_to_bin[itr[0]] << 4 | hex_to_bin[itr[1]]); + ++out; + itr += 2; + } + return true; + } + + inline bool convert_hex_to_bin(const char* begin, const char* end, char* out) + { + return convert_hex_to_bin(reinterpret_cast(begin), + reinterpret_cast(end), + reinterpret_cast(out)); + } + + inline bool convert_hex_to_bin(const std::pair& r, unsigned char* out) + { + return convert_hex_to_bin(r.first,r.second,out); + } + + inline bool convert_hex_to_bin(const std::pair& r, unsigned char* out) + { + return convert_hex_to_bin(r.first,r.second,out); + } + + inline bool convert_hex_to_bin(const std::pair& r, char* out) + { + return convert_hex_to_bin(r.first,r.second,out); + } + + inline bool convert_hex_to_bin(const std::pair& r, char* out) + { + return convert_hex_to_bin(r.first,r.second,out); + } + + inline bool convert_hex_to_bin(const std::string& hex_data, std::string& output) + { + if (hex_data.empty() || (1 == (hex_data.size() % 2))) + return false; + output.resize(hex_data.size() >> 1); + return convert_hex_to_bin(hex_data.data(), + hex_data.data() + hex_data.size(), + const_cast(output.data())); + } + + inline std::size_t convert_bin_to_base64(const unsigned char* begin, const unsigned char* end, unsigned char* out) + { + static const unsigned char bin_to_base64 [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + const std::size_t length = std::distance(begin,end); + std::size_t rounds = length / 3; + const unsigned char* itr = begin; + for (std::size_t i = 0; i < rounds; ++i) + { + unsigned int block = *(itr++) << 16; + block |= *(itr++) << 8; + block |= *(itr++) ; + *(out++) = bin_to_base64[( block >> 18 ) & 0x3F]; + *(out++) = bin_to_base64[( block >> 12 ) & 0x3F]; + *(out++) = bin_to_base64[( block >> 6 ) & 0x3F]; + *(out++) = bin_to_base64[( block ) & 0x3F]; + } + + if ((rounds = (length % 3)) > 0) + { + switch (rounds) + { + case 1 : { + unsigned int block = (unsigned char) (*itr) << 16; + *(out++) = bin_to_base64[( block >> 18 ) & 0x3F]; + *(out++) = bin_to_base64[( block >> 12 ) & 0x3F]; + *(out++) = '='; + *(out++) = '='; + } + break; + + case 2 : { + unsigned int block = *(itr++) << 16; + block |= *(itr++) << 8; + *(out++) = bin_to_base64[( block >> 18 ) & 0x3F]; + *(out++) = bin_to_base64[( block >> 12 ) & 0x3F]; + *(out++) = bin_to_base64[( block >> 6 ) & 0x3F]; + *(out++) = '='; + } + break; + } + } + return static_cast((length / 3) * 4) + ((length % 3) > 0 ? 4 : 0); + } + + inline std::size_t convert_bin_to_base64(const char* begin, const char* end, char* out) + { + return convert_bin_to_base64(reinterpret_cast(begin), + reinterpret_cast(end), + reinterpret_cast(out)); + } + + inline void convert_bin_to_base64(const std::string& binary_data, std::string& output) + { + output.resize(std::max(4,binary_data.size() << 1)); + std::size_t resize = convert_bin_to_base64(binary_data.data(), + binary_data.data() + binary_data.size(), + const_cast(output.data())); + output.resize(resize); + } + + inline std::size_t convert_base64_to_bin(const unsigned char* begin, const unsigned char* end, unsigned char* out) + { + static const unsigned char base64_to_bin[] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x00 - 0x07 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x08 - 0x0F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10 - 0x17 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x18 - 0x1F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20 - 0x27 + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, // 0x28 - 0x2F + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30 - 0x37 + 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x38 - 0x3F + 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40 - 0x47 + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48 - 0x4F + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50 - 0x57 + 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x58 - 0x5F + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60 - 0x67 + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68 - 0x6F + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70 - 0x77 + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x78 - 0x7F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x80 - 0x87 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x88 - 0x8F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x90 - 0x97 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x98 - 0x9F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA0 - 0xA7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA8 - 0xAF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB0 - 0xB7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB8 - 0xBF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC0 - 0xC7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC8 - 0xCF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD0 - 0xD7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD8 - 0xDF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0 - 0xE7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE8 - 0xEF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xF0 - 0xF7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 0xF8 - 0xFF + }; + + const unsigned char* end_itr = end; + + if ('=' == *(end - 2)) + end_itr = end - 2; + else if ('=' == *(end - 1)) + end_itr = end - 1; + + const std::size_t length = std::distance(begin,end_itr); + const std::size_t rounds = length / 4; + const unsigned char* itr = begin; + + for (std::size_t i = 0; i < rounds; ++i) + { + unsigned int block = base64_to_bin[*(itr++)] << 18; + block |= base64_to_bin[*(itr++)] << 12; + block |= base64_to_bin[*(itr++)] << 6; + block |= base64_to_bin[*(itr++)]; + + *(out++) = static_cast(( block >> 16 ) & 0xFF); + *(out++) = static_cast(( block >> 8 ) & 0xFF); + *(out++) = static_cast(( block ) & 0xFF); + } + + const std::size_t remainder = (length % 4); + if (remainder > 0) + { + switch (remainder) + { + case 2 : { + unsigned int block = base64_to_bin[*(itr++)] << 18; + block |= base64_to_bin[*(itr++)] << 12; + (*out) = static_cast(( block >> 16 ) & 0xFF); + } + break; + + case 3 : { + unsigned int block = base64_to_bin[*(itr++)] << 18; + block |= base64_to_bin[*(itr++)] << 12; + block |= base64_to_bin[*(itr++)] << 6; + *(out++) = static_cast(( block >> 16 ) & 0xFF); + *(out ) = static_cast(( block >> 8 ) & 0xFF); + } + break; + } + } + + return static_cast((3 * length) / 4); + } + + inline std::size_t convert_base64_to_bin(const char* begin, const char* end, char* out) + { + return convert_base64_to_bin(reinterpret_cast(begin), + reinterpret_cast(end), + reinterpret_cast(out)); + } + + inline void convert_base64_to_bin(const std::string& binary_data, std::string& output) + { + output.resize(binary_data.size()); + std::size_t resize = convert_base64_to_bin(binary_data.data(), + binary_data.data() + binary_data.size(), + const_cast(output.data())); + output.resize(resize); + } + + inline void convert_to_printable_chars(unsigned char* begin, unsigned char* end) + { + static const unsigned char printable_char_table[] = + { + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x00 - 0x07 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x08 - 0x0F + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x10 - 0x17 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x18 - 0x1F + 0x2E, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // 0x20 - 0x27 + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 0x28 - 0x2F + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // 0x30 - 0x37 + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 0x38 - 0x3F + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, // 0x40 - 0x47 + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 0x48 - 0x4F + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, // 0x50 - 0x57 + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // 0x58 - 0x5F + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // 0x60 - 0x67 + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 0x68 - 0x6F + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 0x70 - 0x77 + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x2E, // 0x78 - 0x7F + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x80 - 0x87 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x88 - 0x8F + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x90 - 0x97 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0x98 - 0x9F + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xA0 - 0xA7 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xA8 - 0xAF + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xB0 - 0xB7 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xB8 - 0xBF + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xC0 - 0xC7 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xC8 - 0xCF + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xD0 - 0xD7 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xD8 - 0xDF + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xE0 - 0xE7 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xE8 - 0xEF + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, // 0xF0 - 0xF7 + 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E // 0xF8 - 0xFF + }; + unsigned char* itr = begin; + while (end != itr) + { + (*itr) = printable_char_table[static_cast((*itr))]; + ++itr; + } + } + + inline void convert_to_printable_chars(char* begin, char* end) + { + convert_to_printable_chars(reinterpret_cast(begin), + reinterpret_cast(end)); + } + + inline void convert_to_printable_chars(std::string& str) + { + convert_to_printable_chars(reinterpret_cast(const_cast(str.data())), + reinterpret_cast(const_cast(str.data() + str.size()))); + } + + inline void convert_to_uppercase(unsigned char* begin, unsigned char* end) + { + std::transform(begin,end,begin,::toupper); + /* + unsigned char* itr = begin; + while (end != itr) + { + //(*itr) = std::toupper((*itr), std::locale::classic()); + (*itr) = static_cast(::toupper(static_cast(*itr))); + ++itr; + } + */ + } + + inline void convert_to_uppercase(char* begin, char* end) + { + convert_to_uppercase(reinterpret_cast(begin), + reinterpret_cast(end)); + } + + inline void convert_to_uppercase(std::string& str) + { + convert_to_uppercase(reinterpret_cast(const_cast(str.data())), + reinterpret_cast(const_cast(str.data() + str.size()))); + } + + inline void convert_to_lowercase(unsigned char* begin, unsigned char* end) + { + std::transform(begin,end,begin,::tolower); + /* + unsigned char* itr = begin; + while (end != itr) + { + //(*itr) = std::tolower((*itr), std::locale::classic()); + (*itr) = static_cast(::tolower(static_cast(*itr))); + ++itr; + } + */ + } + + inline void convert_to_lowercase(char* begin, char* end) + { + convert_to_lowercase(reinterpret_cast(begin), + reinterpret_cast(end)); + } + + inline void convert_to_lowercase(const char* begin, const char* end) + { + convert_to_lowercase(const_cast(begin),const_cast(end)); + } + + inline void convert_to_lowercase(std::string& str) + { + convert_to_lowercase(reinterpret_cast(const_cast(str.data())), + reinterpret_cast(const_cast(str.data() + str.size()))); + } + + inline std::string as_lowercase(const std::string& str) + { + std::string result = str; + convert_to_lowercase(result); + return result; + } + + inline std::string as_uppercase(const std::string& str) + { + std::string result = str; + convert_to_uppercase(result); + return result; + } + + inline bool twoway_bitwise_interleave(const unsigned char* begin1, const unsigned char* end1, + const unsigned char* begin2, const unsigned char* end2, + unsigned char* out) + { + if (std::distance(begin1,end1) != std::distance(begin2,end2)) + { + return false; + } + + static const std::size_t interleave_table_size = 256; + static const unsigned short interleave_table[interleave_table_size] = + { + 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, // 0x00 - 0x07 + 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, // 0x08 - 0x0F + 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, // 0x10 - 0x17 + 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, // 0x18 - 0x1F + 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, // 0x20 - 0x27 + 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, // 0x28 - 0x2F + 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, // 0x30 - 0x37 + 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, // 0x38 - 0x3F + 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, // 0x40 - 0x47 + 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, // 0x48 - 0x4F + 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, // 0x50 - 0x57 + 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, // 0x58 - 0x5F + 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, // 0x60 - 0x67 + 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, // 0x68 - 0x6F + 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, // 0x70 - 0x77 + 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, // 0x78 - 0x7F + 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, // 0x80 - 0x87 + 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, // 0x88 - 0x8F + 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, // 0x90 - 0x97 + 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, // 0x98 - 0x9F + 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, // 0xA0 - 0xA7 + 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, // 0xA8 - 0xAF + 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, // 0xB0 - 0xB7 + 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, // 0xB8 - 0xBF + 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, // 0xC0 - 0xC7 + 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, // 0xC8 - 0xCF + 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, // 0xD0 - 0xD7 + 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, // 0xD8 - 0xDF + 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, // 0xE0 - 0xE7 + 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, // 0xE8 - 0xEF + 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, // 0xF0 - 0xF7 + 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 // 0xF8 - 0xFF + }; + + const unsigned char* itr1 = begin1; + const unsigned char* itr2 = begin2; + while (end1 != itr1) + { + *(reinterpret_cast(out)) = (interleave_table[*(itr2++)] << 1); + *(reinterpret_cast(out)) |= interleave_table[*(itr1++)]; + out += 2; + } + return true; + } + + inline bool twoway_bitwise_interleave(const char* begin1, const char* end1, + const char* begin2, const char* end2, + char* out) + { + return twoway_bitwise_interleave(reinterpret_cast(begin1), + reinterpret_cast(end1), + reinterpret_cast(begin2), + reinterpret_cast(end2), + reinterpret_cast(out)); + } + + inline bool twoway_bitwise_interleave(const std::string& str1, + const std::string& str2, + std::string& out) + { + if (str1.size() != str2.size()) + { + return false; + } + out.resize(str1.size()); + return twoway_bitwise_interleave(str1.data(),str1.data() + str1.size(), + str2.data(),str2.data() + str2.size(), + const_cast(out.data())); + } + + template + struct interleave_ary; + + template<> struct interleave_ary { typedef unsigned short type; }; + template<> struct interleave_ary { typedef unsigned int type; }; + template<> struct interleave_ary { typedef unsigned long long int type; }; + + template + inline void create_nway_interleave_table(typename interleave_ary::type table[256]) + { + typedef typename interleave_ary::type type; + const type diff = static_cast(n - 1); + for (type i = static_cast(0); i < static_cast(256); ++i) + { + table[i] = 0x00; + for (type j = static_cast(0); j < static_cast(8); ++j) + { + table[i] |= (i & (1 << j)) << (j * diff); + } + } + } + + namespace bitwise_operation { enum type { eAND, eOR, eXOR }; } + + inline void bitwise_transform(const bitwise_operation::type& operation, + const unsigned char* begin1, const unsigned char* end1, + const unsigned char* begin2, + unsigned char* out) + { + const unsigned char* itr1 = begin1; + const unsigned char* itr2 = begin2; + + switch (operation) + { + case bitwise_operation::eAND : while (itr1 != end1) { *(out++) = *(itr1++) & *(itr2++); } return; + case bitwise_operation::eOR : while (itr1 != end1) { *(out++) = *(itr1++) | *(itr2++); } return; + case bitwise_operation::eXOR : while (itr1 != end1) { *(out++) = *(itr1++) ^ *(itr2++); } return; + } + } + + inline void bitwise_transform(const bitwise_operation::type& operation, + const char* begin1, const char* end1, + const char* begin2, + char* out) + { + bitwise_transform(operation, + reinterpret_cast(begin1), + reinterpret_cast(end1), + reinterpret_cast(begin2), + reinterpret_cast(out)); + } + + inline void bitwise_transform(const bitwise_operation::type& operation, + const std::string& str1, + const std::string& str2, + std::string& out) + { + if (str1.size() != str2.size()) return; + out.resize(str1.size()); + bitwise_transform(operation, + str1.data(),str1.data() + str1.size(), + str2.data(), + const_cast(out.data())); + } + + inline std::size_t high_bit_count(const unsigned char c) + { + static const std::size_t high_bits_in_char[256] = + { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 + }; + return high_bits_in_char[c]; + } + + inline std::size_t high_bit_count(const unsigned short& s) + { + const unsigned char* ptr = reinterpret_cast(&s); + return high_bit_count(*(ptr + 0)) + high_bit_count(*(ptr + 1)); + } + + inline std::size_t high_bit_count(const unsigned int& i) + { + const unsigned char* ptr = reinterpret_cast(&i); + return high_bit_count(*(ptr + 0)) + high_bit_count(*(ptr + 1)) + + high_bit_count(*(ptr + 2)) + high_bit_count(*(ptr + 3)); + } + + inline std::size_t high_bit_count(const long long int& ll) + { + const unsigned char* ptr = reinterpret_cast(&ll); + return high_bit_count(*(ptr + 0)) + high_bit_count(*(ptr + 1)) + + high_bit_count(*(ptr + 2)) + high_bit_count(*(ptr + 3)) + + high_bit_count(*(ptr + 4)) + high_bit_count(*(ptr + 5)) + + high_bit_count(*(ptr + 6)) + high_bit_count(*(ptr + 7)); + } + + inline std::size_t high_bit_count(const unsigned char* begin, const unsigned char* end) + { + std::size_t count = 0; + const unsigned char* itr = begin; + while (end != itr) + { + count += high_bit_count(*itr++); + } + return count; + } + + inline std::size_t high_bit_count(const char* begin, const char* end) + { + return high_bit_count(reinterpret_cast(begin), + reinterpret_cast(end)); + + } + + inline std::size_t high_bit_count(const std::string& str) + { + return high_bit_count(str.data(),str.data() + str.size()); + } + + inline bool bit_state(const std::size_t& index, const unsigned char* ptr) + { + static const unsigned char bit_mask[] = + { + 0x01, //00000001 + 0x02, //00000010 + 0x04, //00000100 + 0x08, //00001000 + 0x10, //00010000 + 0x20, //00100000 + 0x40, //01000000 + 0x80 //10000000 + }; + return (0 != (ptr[(index >> 3)] & bit_mask[index & 7])); + } + + inline void set_bit_high(const std::size_t& index, unsigned char* const ptr) + { + static const unsigned char bit_mask[] = + { + 0x01, //00000001 + 0x02, //00000010 + 0x04, //00000100 + 0x08, //00001000 + 0x10, //00010000 + 0x20, //00100000 + 0x40, //01000000 + 0x80 //10000000 + }; + ptr[(index >> 3)] |= bit_mask[index & 7]; + } + + inline void set_bit_low(const std::size_t& index, unsigned char* const ptr) + { + static const unsigned char bit_mask[] = + { + 0xFE, //11111110 + 0xFD, //11111101 + 0xFB, //11111011 + 0xF7, //11110111 + 0xEF, //11101111 + 0xDF, //11011111 + 0xBF, //10111111 + 0x7F //01111111 + }; + ptr[(index >> 3)] &= bit_mask[index & 7]; + } + + inline std::size_t hamming_distance(const unsigned char* begin1, const unsigned char* end1, + const unsigned char* begin2, const unsigned char* end2) + { + if (std::distance(begin1,end1) != std::distance(begin2,end2)) + { + return std::numeric_limits::max(); + } + + std::size_t distance = 0; + const unsigned char* itr1 = begin1; + const unsigned char* itr2 = begin2; + + while (end1 != itr1) + { + distance += high_bit_count(static_cast(((*itr1++) ^ (*itr2++)) & 0xFF)); + } + + return distance; + } + + inline std::size_t hamming_distance(const char* begin1, const char* end1, + const char* begin2, const char* end2) + { + return hamming_distance(reinterpret_cast(begin1), + reinterpret_cast(end1), + reinterpret_cast(begin2), + reinterpret_cast(end2)); + } + + inline std::size_t hamming_distance(const std::string& str1, const std::string& str2) + { + return hamming_distance(str1.data(), str1.data() + str1.size(), + str2.data(), str2.data() + str2.size()); + } + + template + inline std::size_t hamming_distance_elementwise(const Iterator begin1, const Iterator end1, + const Iterator begin2, const Iterator end2) + { + if (std::distance(begin1,end1) != std::distance(begin2,end2)) + { + return std::numeric_limits::max(); + } + + std::size_t distance = 0; + Iterator itr1 = begin1; + Iterator itr2 = begin2; + + while (end1 != itr1) + { + if ((*itr1) != (*itr2)) + ++distance; + } + + return distance; + } + + inline std::size_t hamming_distance_elementwise(const std::string& str1, const std::string& str2) + { + return hamming_distance_elementwise(str1.data(), str1.data() + str1.size(), + str2.data(), str2.data() + str2.size()); + } + + class token_grid + { + public: + + typedef const unsigned char* iterator_t; + typedef unsigned int index_t; + typedef std::pair range_t; + typedef std::deque token_list_t; + typedef std::pair row_index_range_t; + typedef std::deque row_index_t; + typedef std::pair row_range_t; + typedef std::pair col_range_t; + + private: + + struct store + { + store() + : max_column(0) + {} + + token_list_t token_list; + row_index_t row_index; + std::size_t max_column; + + inline void clear() + { + token_list.clear(); + row_index.clear(); + } + + inline range_t operator()(const std::size_t& col, const std::size_t& row) const + { + if (row < row_index.size()) + { + const row_index_range_t& r = row_index[row]; + if (col < (r.second - r.first + 1)) + return *(token_list.begin() + (r.first + col)); + else + return null_range(); + } + else + return null_range(); + } + + inline bool remove_row(const std::size_t& row) + { + if (row >= row_index.size()) return false; + row_index_range_t& r = row_index[row]; + std::size_t number_of_tokens = r.second - r.first + 1; + token_list_t::iterator remove_begin = token_list.begin() + r.first; + token_list_t::iterator remove_end = token_list.begin() + r.first + number_of_tokens; + token_list.erase(remove_begin,remove_end); + row_index.erase(row_index.begin() + row); + for (std::size_t i = row; i < row_index.size(); ++i) + { + row_index_range_t& r = row_index[i]; + r.first -= static_cast(number_of_tokens); + r.second -= static_cast(number_of_tokens); + } + return true; + } + + inline std::size_t token_count(const row_index_range_t& r) const + { + return (r.second - r.first + 1); + } + + inline std::size_t token_count(const std::size_t& index) const + { + return token_count(row_index[index]); + } + + inline bool remove_row_range(const std::size_t& r0, const std::size_t& r1) + { + if (r0 > r1) + return false; + else if (r0 >= row_index.size()) + return false; + else if (r1 >= row_index.size()) + return false; + std::size_t number_of_tokens = 0; + for (std::size_t i = r0; i <= r1; ++i) + { + row_index_range_t& r = row_index[i]; + number_of_tokens += token_count(r); + } + row_index_range_t rr0 = row_index[r0]; + token_list_t::iterator remove_begin = token_list.begin() + rr0.first; + token_list_t::iterator remove_end = token_list.begin() + rr0.first + number_of_tokens; + token_list.erase(remove_begin,remove_end); + row_index.erase(row_index.begin() + r0,row_index.begin() + r0 + (r1 - r0 + 1)); + for (std::size_t i = r0; i < row_index.size(); ++i) + { + row_index_range_t& r = row_index[i]; + r.first -= static_cast(number_of_tokens); + r.second -= static_cast(number_of_tokens); + } + return true; + } + + struct remove_column_impl + { + std::size_t column; + std::size_t counter; + std::size_t remainder; + std::size_t current_row; + + inline void update(store& idx) + { + current_row++; + while (current_row < idx.row_index.size()) + { + std::size_t number_of_tokens = idx.token_count(current_row); + if (number_of_tokens > column) + break; + counter += number_of_tokens; + ++current_row; + } + if (current_row < idx.row_index.size()) + { + counter += column + remainder; + row_index_range_t& r = idx.row_index[current_row]; + remainder = (r.second - r.first) - column; + } + else + counter = std::numeric_limits::max(); + } + + inline void process(store& idx) + { + token_list_t::iterator itr1 = idx.token_list.begin(); + token_list_t::iterator itr2 = idx.token_list.begin(); + token_list_t::iterator end = idx.token_list.end(); + counter = 0; + remainder = 0; + current_row = static_cast(-1); + update(idx); + while (end != itr1) + { + while ((end != itr1) && (0 != counter)) + { + if (itr1 != itr2) + { + (*itr2) = (*itr1); + } + ++itr1; + ++itr2; + --counter; + } + if (0 == counter) + { + update(idx); + ++itr1; + } + } + std::size_t remove_count = 0; + idx.max_column = std::numeric_limits::min(); + for (std::size_t i = 0; i < idx.row_index.size(); ++i) + { + row_index_range_t& r = idx.row_index[i]; + std::size_t token_count = (r.second - r.first + 1); + r.first -= static_cast(remove_count); + if (token_count > column) + { + ++remove_count; + } + r.second -= static_cast(remove_count); + token_count = (r.second - r.first + 1); + if (token_count > idx.max_column) + idx.max_column = token_count; + } + idx.token_list.resize(idx.token_list.size() - remove_count); + } + }; + + inline bool remove_column(const std::size_t& column) + { + if (column >= max_column) return false; + remove_column_impl rc; + rc.column = column; + rc.process(*this); + return true; + } + + inline static range_t null_range() + { + static const range_t null_range_ = range_t(reinterpret_cast(0), + reinterpret_cast(0)); + return null_range_; + } + + }; + + template + struct row_processor + { + row_processor(store& idx, + DelimiterPredicate& tp, + const split_options::type split_mode = split_options::compress_delimiters) + : idx_(idx), + row_start_index_(0), + row_end_index_(0), + token_predicate_(tp), + split_mode_(split_mode) + { + idx_.max_column = std::numeric_limits::min(); + } + + inline void operator()(const range_t& range) + { + if (0 == std::distance(range.first,range.second)) + return; + row_start_index_ = static_cast(idx_.token_list.size()); + std::size_t token_count = split(token_predicate_, + range.first,range.second, + std::back_inserter(idx_.token_list), + split_mode_); + row_end_index_ = row_start_index_ + token_count - 1; + idx_.row_index.push_back(std::make_pair(row_start_index_,row_end_index_)); + if (token_count > idx_.max_column) + idx_.max_column = token_count; + } + + row_processor operator=(const row_processor&); + + store& idx_; + index_t row_start_index_; + index_t row_end_index_; + DelimiterPredicate& token_predicate_; + split_options::type split_mode_; + }; + + public: + + inline row_range_t range(std::size_t lower_bound, + std::size_t upper_bound = std::numeric_limits::max()) const + { + if (upper_bound == std::numeric_limits::max()) + { + upper_bound = dsv_index_.token_list.size(); + } + else if (upper_bound > dsv_index_.token_list.size()) + { + return row_range_t(std::numeric_limits::max(),std::numeric_limits::max()); + } + else if (lower_bound > upper_bound) + { + return row_range_t(std::numeric_limits::max(),std::numeric_limits::max()); + } + return row_range_t(lower_bound,upper_bound); + } + + struct options + { + options() + : row_split_option(split_options::compress_delimiters), + column_split_option(split_options::compress_delimiters), + row_delimiters("\n\r"), + column_delimiters(",|;\t "), + support_dquotes(false), + trim_dquotes(false) + {} + + options(split_options::type sro, + split_options::type sco, + const std::string& rd, + const std::string& cd, + const bool support_dq = false, + const bool trim_dq = false) + : row_split_option(sro), + column_split_option(sco), + row_delimiters(rd), + column_delimiters(cd), + support_dquotes(support_dq), + trim_dquotes(trim_dq) + {} + + inline options& set_column_split_option(const split_options::type& option) + { + column_split_option = option; + return *this; + } + + inline options& set_row_split_option(const split_options::type& option) + { + row_split_option = option; + return *this; + } + + inline options& set_column_delimiters(const std::string& delimiters) + { + column_delimiters = delimiters; + return *this; + } + + inline options& set_row_delimiters(const std::string& delimiters) + { + row_delimiters = delimiters; + return *this; + } + + split_options::type row_split_option; + split_options::type column_split_option; + std::string row_delimiters; + std::string column_delimiters; + bool support_dquotes; + bool trim_dquotes; + }; + + class row_type + { + private: + + typedef std::pair row_pair_type; + + public: + + row_type() + : index_(std::numeric_limits::max()), + size_(0) + {} + + row_type(const std::size_t& index, + const store& dsv_index) + : index_(index), + size_ (dsv_index.token_count(index)), + begin_(dsv_index.token_list.begin() + dsv_index.row_index[index].first) + {} + + inline bool is_null(const std::size_t& index) const + { + const range_t& range = *(begin_ + index); + return (0 == std::distance(range.first,range.second)); + } + + template + inline T operator[](const std::size_t& index) const + { + const range_t& range = *(begin_ + index); + return string_to_type_converter(range.first,range.second); + } + + template + inline T get(const std::size_t& index) const + { + return operator[](index); + } + + inline col_range_t all_columns() const + { + return col_range_t(0,static_cast(size())); + } + + inline range_t range() const + { + return range_t((*begin_).first,(*(begin_ + (size_ - 1))).second); + } + + inline range_t token(const std::size_t& index) const + { + return *(begin_ + index); + } + + inline std::size_t index() const + { + return index_; + } + + inline std::size_t size() const + { + return size_; + } + + inline std::size_t raw_length() const + { + std::size_t result = 0; + token_list_t::const_iterator itr = begin_; + for (std::size_t i = 0; i < size_; ++i, ++itr) + { + const range_t& range = (*itr); + result += std::distance(range.first,range.second); + } + return result; + } + + inline std::size_t raw_length(const std::size_t& column_index) const + { + const range_t& range = *(begin_ + column_index); + return std::distance(range.first,range.second); + } + + inline std::string as_string() const + { + std::string result; + result.reserve(std::distance(begin_->first,(begin_ + (size_ - 1))->second)); + token_list_t::const_iterator itr = begin_; + for (std::size_t i = 0; i < size_; ++i, ++itr) + { + const range_t& range = (*itr); + result.append(range.first,range.second); + } + return result; + } + + inline void as_string(std::string& out) const + { + out = as_string(); + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + const std::size_t& col4, const std::size_t& col5, + const std::size_t& col6, const std::size_t& col7, + const std::size_t& col8, const std::size_t& col9, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + if (!process(*(begin_ + col4),t4)) return false; + if (!process(*(begin_ + col5),t5)) return false; + if (!process(*(begin_ + col6),t6)) return false; + if (!process(*(begin_ + col7),t7)) return false; + if (!process(*(begin_ + col8),t8)) return false; + if (!process(*(begin_ + col9),t9)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + const std::size_t& col4, const std::size_t& col5, + const std::size_t& col6, const std::size_t& col7, + const std::size_t& col8, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + if (!process(*(begin_ + col4),t4)) return false; + if (!process(*(begin_ + col5),t5)) return false; + if (!process(*(begin_ + col6),t6)) return false; + if (!process(*(begin_ + col7),t7)) return false; + if (!process(*(begin_ + col8),t8)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + const std::size_t& col4, const std::size_t& col5, + const std::size_t& col6, const std::size_t& col7, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + if (!process(*(begin_ + col4),t4)) return false; + if (!process(*(begin_ + col5),t5)) return false; + if (!process(*(begin_ + col6),t6)) return false; + if (!process(*(begin_ + col7),t7)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + const std::size_t& col4, const std::size_t& col5, + const std::size_t& col6, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + if (!process(*(begin_ + col4),t4)) return false; + if (!process(*(begin_ + col5),t5)) return false; + if (!process(*(begin_ + col6),t6)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + const std::size_t& col4, const std::size_t& col5, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + if (!process(*(begin_ + col4),t4)) return false; + if (!process(*(begin_ + col5),t5)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + const std::size_t& col4, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + if (!process(*(begin_ + col4),t4)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, const std::size_t& col3, + T0& t0, T1& t1, T2& t2, T3& t3) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + if (!process(*(begin_ + col3),t3)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + const std::size_t& col2, + T0& t0, T1& t1, T2& t2) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + if (!process(*(begin_ + col2),t2)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col0, const std::size_t& col1, + T0& t0, T1& t1) const + { + if (!process(*(begin_ + col0),t0)) return false; + if (!process(*(begin_ + col1),t1)) return false; + return true; + } + + template + inline bool parse_with_index(const std::size_t& col, T& t) const + { + return process(*(begin_ + col),t); + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7, + T8& t8, T9& t9) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + if (!process(*(begin_ + 4),t4)) return false; + if (!process(*(begin_ + 5),t5)) return false; + if (!process(*(begin_ + 6),t6)) return false; + if (!process(*(begin_ + 7),t7)) return false; + if (!process(*(begin_ + 8),t8)) return false; + if (!process(*(begin_ + 9),t9)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7, + T8& t8) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + if (!process(*(begin_ + 4),t4)) return false; + if (!process(*(begin_ + 5),t5)) return false; + if (!process(*(begin_ + 6),t6)) return false; + if (!process(*(begin_ + 7),t7)) return false; + if (!process(*(begin_ + 8),t8)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + if (!process(*(begin_ + 4),t4)) return false; + if (!process(*(begin_ + 5),t5)) return false; + if (!process(*(begin_ + 6),t6)) return false; + if (!process(*(begin_ + 7),t7)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + if (!process(*(begin_ + 4),t4)) return false; + if (!process(*(begin_ + 5),t5)) return false; + if (!process(*(begin_ + 6),t6)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + if (!process(*(begin_ + 4),t4)) return false; + if (!process(*(begin_ + 5),t5)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3, T4& t4) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + if (!process(*(begin_ + 4),t4)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2, T3& t3) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + if (!process(*(begin_ + 3),t3)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1, T2& t2) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + if (!process(*(begin_ + 2),t2)) return false; + return true; + } + + template + inline bool parse(T0& t0, T1& t1) const + { + if (!process(*(begin_ + 0),t0)) return false; + if (!process(*(begin_ + 1),t1)) return false; + return true; + } + + template + inline bool parse(T0& t) const + { + return process(*begin_,t); + } + + template + inline void parse(OutputIterator out) const + { + token_list_t::const_iterator itr = begin_; + const token_list_t::const_iterator end = begin_ + size_; + while (end != itr) + { + const range_t& range = (*itr); + *(out++) = string_to_type_converter(range.first,range.second); + ++itr; + } + } + + bool validate_column_range(const col_range_t& range) const + { + if ((range.first > size()) || (range.second > size())) + return false; + else if (range.first > range.second) + return false; + else + return true; + } + + col_range_t range(const std::size_t& lower_bound, + const std::size_t& upper_bound = std::numeric_limits::max()) const + { + if (std::numeric_limits::max() != upper_bound) + return col_range_t(lower_bound,upper_bound); + else + return col_range_t(lower_bound,static_cast(size())); + } + + template class Sequence> + inline bool parse(const col_range_t& range, + Sequence& sequence) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = (begin_ + range.first); + token_list_t::const_iterator end = (begin_ + range.second); + T t; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,t)) + sequence.push_back(t); + else + return false; + ++itr; + } + return true; + } + + template + inline bool parse(const col_range_t& range, + std::set& set) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = (begin_ + range.first); + token_list_t::const_iterator end = (begin_ + range.second); + T t; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,t)) + set.insert(t); + else + return false; + ++itr; + } + return true; + } + + template + inline bool parse(const col_range_t& range, + std::multiset& multiset) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = (begin_ + range.first); + token_list_t::const_iterator end = (begin_ + range.second); + T t; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,t)) + multiset.insert(t); + else + return false; + ++itr; + } + return true; + } + + template + inline bool parse(const col_range_t& range, + std::queue& queue) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = (begin_ + range.first); + token_list_t::const_iterator end = (begin_ + range.second); + T t; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,t)) + queue.push(t); + else + return false; + ++itr; + } + return true; + } + + template + inline bool parse(const col_range_t& range, + std::stack& stack) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = (begin_ + range.first); + token_list_t::const_iterator end = (begin_ + range.second); + T t; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,t)) + stack.push(t); + else + return false; + ++itr; + } + return true; + } + + template + inline bool parse(const col_range_t& range, + std::priority_queue& priority_queue) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = (begin_ + range.first); + token_list_t::const_iterator end = (begin_ + range.second); + T t; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,t)) + priority_queue.push(t); + else + return false; + ++itr; + } + return true; + } + + template class Sequence> + inline bool parse(Sequence& sequence) const + { + return parse(range(0),sequence); + } + + template + inline bool parse(std::set& set) const + { + return parse(range(0),set); + } + + template + inline bool parse(std::multiset& multiset) const + { + return parse(range(0),multiset); + } + + template + inline bool parse(std::queue& queue) const + { + return parse(range(0),queue); + } + + template + inline bool parse(std::stack& stack) const + { + return parse(range(0),stack); + } + + template + inline bool parse(std::priority_queue& priority_queue) const + { + return parse(range(0),priority_queue); + } + + template class Sequence> + inline std::size_t parse_n(const std::size_t& n, Sequence& sequence) const + { + if (0 == n) return 0; + T t; + std::size_t count = 0; + token_list_t::const_iterator itr = begin_; + const token_list_t::const_iterator end = begin_ + size_; + while (end != itr) + { + const range_t& range = (*itr); + if (!string_to_type_converter(range.first,range.second,t)) + return false; + else + sequence.push_back(t); + if (n == (++count)) + break; + ++itr; + } + return count; + } + + template + inline void parse_checked(OutputIterator out) const + { + T value; + token_list_t::const_iterator itr = begin_; + const token_list_t::const_iterator end = begin_ + size_; + while (end != itr) + { + const range_t& range = (*itr); + if (string_to_type_converter(range.first,range.second,value)) + { + *(out++) = value; + } + ++itr; + } + } + + template class Sequence> + inline void parse_checked(Sequence& sequence) const + { + parse_checked(std::back_inserter(sequence)); + } + + template + inline void parse_checked(std::set& set) const + { + parse_checked(std::inserter(set,set.end())); + } + + template + inline void parse_checked(std::multiset& multiset) const + { + parse_checked(std::inserter(multiset,multiset.end())); + } + + template + inline void parse_checked(std::queue& queue) const + { + parse_checked(push_inserter(queue)); + } + + template + inline void parse_checked(std::stack& stack) const + { + parse_checked(push_inserter(stack)); + } + + template + inline void parse_checked(std::priority_queue& priority_queue) const + { + parse_checked(push_inserter(priority_queue)); + } + + template + inline std::size_t for_each_column(const col_range_t& range, Function f) const + { + if (!validate_column_range(range)) + return false; + token_list_t::const_iterator itr = begin_ + range.first; + token_list_t::const_iterator end = begin_ + range.second; + std::size_t col_count = 0; + while (end != itr) + { + const range_t& range = (*itr); + f(range); + ++itr; + ++col_count; + } + return col_count; + } + + template + inline std::size_t for_each_column(Function f) const + { + return for_each_column(all_columns(),f); + } + + private: + + template + inline bool process(const range_t& range, T& t) const + { + return string_to_type_converter(range.first,range.second,t); + } + + private: + + std::size_t index_; + std::size_t size_; + token_list_t::const_iterator begin_; + }; + + token_grid() + : file_name_(""), + buffer_(0), + buffer_size_(0), + min_column_count_(0), + max_column_count_(0), + load_from_file_(false), + state_(false) + {} + + token_grid(const std::string& file_name, + const token_grid::options& options) + : file_name_(file_name), + buffer_(0), + buffer_size_(0), + min_column_count_(0), + max_column_count_(0), + options_(options), + load_from_file_(true), + state_(load()) + {} + + token_grid(const unsigned char* input_buffer, + const std::size_t& input_buffer_size, + const token_grid::options& options) + : file_name_(""), + buffer_(const_cast(input_buffer)), + buffer_size_(input_buffer_size), + min_column_count_(0), + max_column_count_(0), + options_(options), + load_from_file_(false), + state_(load()) + {} + + token_grid(const char* input_buffer, + const std::size_t& input_buffer_size, + const token_grid::options& options) + : file_name_(""), + buffer_(reinterpret_cast(const_cast(input_buffer))), + buffer_size_(input_buffer_size), + min_column_count_(0), + max_column_count_(0), + options_(options), + load_from_file_(false), + state_(load()) + {} + + token_grid(const std::string& input_buffer, + const std::size_t& input_buffer_size, + const token_grid::options& options) + : file_name_(""), + buffer_(reinterpret_cast(const_cast(input_buffer.data()))), + buffer_size_(input_buffer_size), + min_column_count_(0), + max_column_count_(0), + options_(options), + load_from_file_(false), + state_(load()) + {} + + token_grid(const std::string& file_name, + const std::string& column_delimiters = ",|;\t", + const std::string& row_delimiters = "\n\r") + : file_name_(file_name), + buffer_(0), + buffer_size_(0), + min_column_count_(0), + max_column_count_(0), + options_(split_options::compress_delimiters, + split_options::compress_delimiters, + row_delimiters, + column_delimiters), + load_from_file_(true), + state_(load()) + {} + + token_grid(const unsigned char* input_buffer, + const std::size_t& input_buffer_size, + const std::string& column_delimiters = ",|;\t", + const std::string& row_delimiters = "\n\r") + : file_name_(""), + buffer_(const_cast(input_buffer)), + buffer_size_(input_buffer_size), + min_column_count_(0), + max_column_count_(0), + options_(split_options::compress_delimiters, + split_options::compress_delimiters, + row_delimiters, + column_delimiters), + load_from_file_(false), + state_(load()) + {} + + token_grid(const char* input_buffer, + const std::size_t& input_buffer_size, + const std::string& column_delimiters = ",|;\t", + const std::string& row_delimiters = "\n\r") + : file_name_(""), + buffer_(reinterpret_cast(const_cast(input_buffer))), + buffer_size_(input_buffer_size), + min_column_count_(0), + max_column_count_(0), + options_(split_options::compress_delimiters, + split_options::compress_delimiters, + row_delimiters, + column_delimiters), + load_from_file_(false), + state_(load()) + {} + + token_grid(const std::string& input_buffer, + const std::size_t& input_buffer_size, + const std::string& column_delimiters = ",;|\t ", + const std::string& row_delimiters = "\n\r") + : file_name_(""), + buffer_(reinterpret_cast(const_cast(input_buffer.data()))), + buffer_size_(input_buffer_size), + min_column_count_(0), + max_column_count_(0), + options_(split_options::compress_delimiters, + split_options::compress_delimiters, + row_delimiters, + column_delimiters), + load_from_file_(false), + state_(load()) + {} + + ~token_grid() + { + if ((load_from_file_) && (0 != buffer_)) + { + delete [] buffer_; + buffer_ = 0; + } + } + + inline bool operator!() const + { + return !state_; + } + + inline std::string source_file() const + { + return file_name_; + } + + inline std::size_t row_count() const + { + return dsv_index_.row_index.size(); + } + + inline std::size_t min_column_count() const + { + return min_column_count_; + } + + inline std::size_t max_column_count() const + { + return max_column_count_; + } + + inline range_t token(const unsigned int& row, const std::size_t& col) const + { + return dsv_index_(col,row); + } + + template + inline T get(const unsigned int& row, const std::size_t& col) + { + range_t r = token(row,col); + return string_to_type_converter(r.first,r.second); + } + + inline row_type row(const unsigned int& row_index) const + { + return row_type(row_index,dsv_index_); + } + + inline row_range_t all_rows() const + { + return row_range_t(0,static_cast(dsv_index_.row_index.size())); + } + + template + inline bool extract_column_checked(const row_range_t& row_range, + const std::size_t& index, + OutputIterator out) const + { + if (index > max_column_count_) + return false; + else if (row_range_invalid(row_range)) + return false; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& row = dsv_index_.row_index[i]; + if (index < dsv_index_.token_count(row)) + { + dsv_index_.token_list.begin() + (row.first + index); + process_token_checked(*(dsv_index_.token_list.begin() + (row.first + index)),out); + } + } + return true; + } + + template + inline bool extract_column_checked(const std::size_t& index, + OutputIterator out) const + { + return extract_column_checked(all_rows(),index,out); + } + + template class Sequence> + inline void extract_column_checked(const std::size_t& index, + Sequence& sequence) const + { + extract_column_checked(index,back_inserter_with_valuetype(sequence)); + } + + template + inline void extract_column_checked(const std::size_t& index, + std::set& set) const + { + extract_column_checked(index,inserter_with_valuetype(set)); + } + + template + inline void extract_column_checked(const std::size_t& index, + std::multiset& multiset) const + { + extract_column_checked(index,inserter_with_valuetype(multiset)); + } + + template + inline bool extract_column(const row_range_t& row_range, + const std::size_t& index, + OutputIterator out) const + { + + if (index > max_column_count_) + return false; + else if (row_range_invalid(row_range)) + return false; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& row = dsv_index_.row_index[i]; + if (index < dsv_index_.token_count(row)) + { + process_token(*(dsv_index_.token_list.begin() + (row.first + index)),out); + } + } + return true; + } + + template + inline bool extract_column(const std::size_t& index, + OutputIterator out) const + { + return extract_column(all_rows(),index,out); + } + + template + inline bool extract_column(const row_range_t& row_range, + const std::size_t& index0, + const std::size_t& index1, + OutputIterator0 out0, + OutputIterator1 out1) const + { + if ((index0 > max_column_count_) || + (index1 > max_column_count_)) + return false; + else if (row_range_invalid(row_range)) + return false; + std::size_t max_index = std::max(index0,index1); + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& row = dsv_index_.row_index[i]; + if (max_index < dsv_index_.token_count(row)) + { + process_token(*(dsv_index_.token_list.begin() + (row.first + index0)),out0); + process_token(*(dsv_index_.token_list.begin() + (row.first + index1)),out1); + } + } + return true; + } + + template + inline bool extract_column(const row_range_t& row_range, + const std::size_t& index0, + const std::size_t& index1, + const std::size_t& index2, + OutputIterator0 out0, + OutputIterator1 out1, + OutputIterator2 out2) const + { + if ((index0 > max_column_count_) || + (index1 > max_column_count_) || + (index2 > max_column_count_)) + return false; + else if (row_range_invalid(row_range)) + return false; + std::size_t max_index = std::max(index0,std::max(index1,index2)); + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& row = dsv_index_.row_index[i]; + if (max_index < dsv_index_.token_count(row)) + { + process_token(*(dsv_index_.token_list.begin() + (row.first + index0)),out0); + process_token(*(dsv_index_.token_list.begin() + (row.first + index1)),out1); + process_token(*(dsv_index_.token_list.begin() + (row.first + index2)),out2); + } + } + return true; + } + + template + inline bool extract_column(const row_range_t& row_range, + const std::size_t& index0, + const std::size_t& index1, + const std::size_t& index2, + const std::size_t& index3, + OutputIterator0 out0, + OutputIterator1 out1, + OutputIterator2 out2, + OutputIterator3 out3) const + { + if ((index0 > max_column_count_) || + (index1 > max_column_count_) || + (index2 > max_column_count_) || + (index3 > max_column_count_)) + return false; + else if (row_range_invalid(row_range)) + return false; + std::size_t max_index = std::max(std::max(index0,index1),std::max(index2,index3)); + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& row = dsv_index_.row_index[i]; + if (max_index < dsv_index_.token_count(row)) + { + process_token(*(dsv_index_.token_list.begin() + (row.first + index0)),out0); + process_token(*(dsv_index_.token_list.begin() + (row.first + index1)),out1); + process_token(*(dsv_index_.token_list.begin() + (row.first + index2)),out2); + process_token(*(dsv_index_.token_list.begin() + (row.first + index3)),out3); + } + } + return true; + } + + template + inline bool extract_column(const row_range_t& row_range, + const std::size_t& index0, + const std::size_t& index1, + const std::size_t& index2, + const std::size_t& index3, + const std::size_t& index4, + OutputIterator0 out0, + OutputIterator1 out1, + OutputIterator2 out2, + OutputIterator3 out3, + OutputIterator4 out4) const + { + if ((index0 > max_column_count_) || + (index1 > max_column_count_) || + (index2 > max_column_count_) || + (index3 > max_column_count_) || + (index4 > max_column_count_)) + return false; + else if (row_range_invalid(row_range)) + return false; + std::size_t max_index = std::max(index4,std::max(std::max(index0,index1),std::max(index2,index3))); + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& row = dsv_index_.row_index[i]; + if (max_index < dsv_index_.token_count(row)) + { + process_token(*(dsv_index_.token_list.begin() + (row.first + index0)),out0); + process_token(*(dsv_index_.token_list.begin() + (row.first + index1)),out1); + process_token(*(dsv_index_.token_list.begin() + (row.first + index2)),out2); + process_token(*(dsv_index_.token_list.begin() + (row.first + index3)),out3); + process_token(*(dsv_index_.token_list.begin() + (row.first + index4)),out4); + } + } + return true; + } + + inline void remove_row(const std::size_t& index) + { + if (index < dsv_index_.row_index.size()) + { + dsv_index_.remove_row(index); + } + } + + template + inline bool remove_row_if(const row_range_t& row_range, Predicate predicate) + { + if (row_range_invalid(row_range)) + return false; + std::size_t removed_token_count = 0; + std::deque remove_token_list; + std::deque remove_row_list; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + row_index_range_t& r = dsv_index_.row_index[i]; + std::size_t temp_r_first = r.first - removed_token_count; + row_type row(i,dsv_index_); + if (predicate(row)) + { + remove_row_list.push_back(i); + for (std::size_t j = r.first; j <= r.second; ++j) + { + remove_token_list.push_back(j); + } + removed_token_count += row.size(); + } + r.first = static_cast(temp_r_first); + r.second -= static_cast(removed_token_count); + } + for (std::size_t i = row_range.second; i < dsv_index_.row_index.size(); ++i) + { + row_index_range_t& r = dsv_index_.row_index[i]; + r.first -= static_cast(removed_token_count); + r.second -= static_cast(removed_token_count); + } + if (!remove_row_list.empty()) + { + remove_inplace(index_remover(remove_row_list),dsv_index_.row_index); + } + if (!remove_token_list.empty()) + { + remove_inplace(index_remover(remove_token_list),dsv_index_.token_list); + } + return true; + } + + template + inline bool remove_row_if(Predicate predicate) + { + return remove_row_if(all_rows(),predicate); + } + + template + inline std::size_t remove_token_if(const row_range_t& row_range, Predicate predicate) + { + if (row_range_invalid(row_range)) + return 0; + std::size_t removed_token_count = 0; + std::deque remove_token_list; + std::deque remove_row_list; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + row_index_range_t& r = dsv_index_.row_index[i]; + std::size_t temp_r_first = r.first - removed_token_count; + row_type row(i,dsv_index_); + for (std::size_t j = 0; j < row.size(); ++j) + { + if (predicate(row.token(j))) + { + remove_token_list.push_back(r.first + j); + ++removed_token_count; + } + } + r.first = static_cast(temp_r_first); + r.second -= static_cast(removed_token_count); + if (0 == dsv_index_.token_count(r)) + { + remove_row_list.push_back(i); + } + } + for (std::size_t i = row_range.second; i < dsv_index_.row_index.size(); ++i) + { + row_index_range_t& r = dsv_index_.row_index[i]; + r.first -= static_cast(removed_token_count); + r.second -= static_cast(removed_token_count); + } + if (!remove_row_list.empty()) + { + remove_inplace(index_remover(remove_row_list),dsv_index_.row_index); + } + if (!remove_token_list.empty()) + { + remove_inplace(index_remover(remove_token_list),dsv_index_.token_list); + } + if (!remove_token_list.empty()) + { + update_minmax_columns(); + } + return remove_token_list.size(); + } + + inline std::size_t remove_empty_tokens(const row_range_t& range) + { + return remove_token_if(range,is_empty_token()); + } + + inline std::size_t remove_empty_tokens() + { + return remove_empty_tokens(all_rows()); + } + + inline void enforce_column_count(const row_range_t& row_range, + const std::size_t& column_count) + { + if (row_range_invalid(row_range)) + return; + remove_row_if(insufficient_number_of_columns(column_count)); + min_column_count_ = column_count; + max_column_count_ = column_count; + } + + inline void enforce_column_count(const std::size_t& column_count) + { + enforce_column_count(all_rows(),column_count); + } + + inline void enforce_min_max_column_count(const row_range_t& row_range, + const std::size_t& min_column_count, + const std::size_t& max_column_count) + { + if (row_range_invalid(row_range)) + return; + remove_row_if(insufficient_number_of_minmax_columns(min_column_count,max_column_count)); + min_column_count_ = min_column_count; + max_column_count_ = max_column_count; + } + + inline void enforce_min_max_column_count(const std::size_t& min_column_count, + const std::size_t& max_column_count) + { + enforce_min_max_column_count(all_rows(),min_column_count,max_column_count); + } + + inline void clear(const bool force_delete_buffer = false) + { + if (load_from_file_ || force_delete_buffer) + delete[] buffer_; + buffer_ = 0; + buffer_size_ = 0; + dsv_index_.clear(); + min_column_count_ = 0; + max_column_count_ = 0; + state_ = false; + file_name_ = ""; + } + + inline std::size_t column_width(const std::size_t& col, + const row_range_t& row_range) const + { + if (col > max_column_count_) + return 0; + else if (row_range_invalid(row_range)) + return 0; + std::size_t result = 0; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& r = dsv_index_.row_index[i]; + if (col < dsv_index_.token_count(r)) + { + const range_t& range = *(dsv_index_.token_list.begin() + r.first + col); + result = std::max(std::distance(range.first,range.second),result); + } + } + return result; + } + + inline std::size_t column_width(const std::size_t& col) const + { + return column_width(col,all_rows()); + } + + template class Sequence> + inline void get_column_widths(Sequence& columns) + { + for (std::size_t c = 0; c < max_column_count(); ++c) + { + columns.push_back(column_width(c)); + } + } + + template class Sequence> + inline void get_column_widths(Sequence,Allocator>& columns) + { + for (std::size_t c = 0; c < max_column_count(); ++c) + { + columns.push_back(std::make_pair(c,column_width(c))); + } + } + + template + inline std::size_t accumulate_row(const std::size_t& row, T& result) const + { + if (row >= dsv_index_.row_index.size()) + return 0; + const row_index_range_t& r = dsv_index_.row_index[row]; + token_list_t::const_iterator itr = dsv_index_.token_list.begin() + r.first; + token_list_t::const_iterator end = dsv_index_.token_list.begin() + r.second + 1; + std::size_t process_count = 0; + T current_value = T(); + while (end != itr) + { + if (string_to_type_converter((*itr).first,(*itr).second,current_value)) + { + result += current_value; + ++process_count; + } + else + return 0; + ++itr; + } + return process_count; + } + + template + inline std::size_t accumulate_column(const std::size_t& col, + const row_range_t& row_range, + T& result) const + { + if (col > max_column_count_) + return 0; + else if (row_range_invalid(row_range)) + return 0; + std::size_t process_count = 0; + T current_value = T(); + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& r = dsv_index_.row_index[i]; + if (col < dsv_index_.token_count(r)) + { + const range_t& range = *(dsv_index_.token_list.begin() + r.first + col); + if (string_to_type_converter(range.first,range.second,current_value)) + result += current_value; + else + return 0; + } + ++process_count; + } + return process_count; + } + + template + inline std::size_t accumulate_column(const std::size_t& col, T& result) const + { + return accumulate_column(col,all_rows(),result); + } + + template + inline std::size_t accumulate_column(const std::size_t& col, + const row_range_t& row_range, + Predicate p, + T& result) const + { + if (col > max_column_count_) + return 0; + else if (row_range_invalid(row_range)) + return 0; + std::size_t process_count = 0; + T current_value = T(); + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& r = dsv_index_.row_index[i]; + if (col < dsv_index_.token_count(r)) + { + row_type row = row_type(i,dsv_index_); + if (p(row)) + { + const range_t& range = row.token(col); + if (string_to_type_converter(range.first,range.second,current_value)) + { + result += current_value; + ++process_count; + } + else + return 0; + } + } + + } + return process_count; + } + + template + inline std::size_t accumulate_column(const std::size_t& col, + Predicate p, + T& result) const + { + return accumulate_column(col,all_rows(),p,result); + } + + inline bool join_row(const std::size_t& row, + const std::string& delimiter, + std::string& result) + { + if (row >= dsv_index_.row_index.size()) + return false; + const row_index_range_t& r = dsv_index_.row_index[row]; + token_list_t::const_iterator itr = dsv_index_.token_list.begin() + r.first; + token_list_t::const_iterator end = dsv_index_.token_list.begin() + r.second + (row < (dsv_index_.row_index.size() - 1) ? 1 : 0); + result.reserve(delimiter.size() * dsv_index_.token_count(r) + std::distance(itr->first,end->second)); + bool appended = false; + while (end != itr) + { + if (!delimiter.empty() && appended) + result.append(delimiter); + appended = false; + if ((*itr).first != (*itr).second) + { + result.append((*itr).first,(*itr).second); + appended = true; + } + ++itr; + } + return true; + } + + template + inline bool join_row(const std::size_t& row, + Predicate predicate, + const std::string& delimiter, + std::string& result) + { + if (row >= dsv_index_.row_index.size()) + return false; + const row_index_range_t& r = dsv_index_.row_index[row]; + token_list_t::const_iterator itr = (dsv_index_.token_list.begin() + r.first); + token_list_t::const_iterator end = dsv_index_.token_list.begin() + r.second + (row < (dsv_index_.row_index.size() - 1) ? 1 : 0); + result.reserve(delimiter.size() * dsv_index_.token_count(r) + std::distance(itr->first,end->second)); + bool appended = false; + while (end != itr) + { + if (!delimiter.empty() && appended) + result.append(delimiter); + appended = false; + if ((*itr).first != (*itr).second) + { + if (predicate(*itr)) + { + result.append((*itr).first,(*itr).second); + appended = true; + } + } + ++itr; + } + return true; + } + + template + inline bool join_row(const std::size_t& row, + Predicate predicate, + const char* delimiter, + std::string& result) + { + return join_row(row,predicate,std::string(delimiter),result); + } + + inline bool join_column(const std::size_t& col, + const row_range_t& row_range, + const std::string& delimiter, + std::string& result) const + { + if (col > max_column_count_) + return false; + else if (row_range_invalid(row_range)) + return false; + bool appended = false; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& r = dsv_index_.row_index[i]; + if (col < dsv_index_.token_count(r)) + { + row_type row = row_type(i,dsv_index_); + const range_t& range = row.token(col); + if (!delimiter.empty() && appended) + result.append(delimiter); + appended = false; + if (range.first != range.second) + { + result.append(range.first,range.second); + appended = true; + } + } + } + return true; + } + + inline bool join_column(const std::size_t& col, + const std::string& delimiter, + std::string& result) const + { + return join_column(col,all_rows(),delimiter,result); + } + + template + inline bool join_column(const std::size_t& col, + const row_range_t& row_range, + Predicate predicate, + const std::string& delimiter, + std::string& result) const + { + if (col > max_column_count_) + return false; + else if (row_range_invalid(row_range)) + return false; + bool appended = false; + const std::size_t pre_end_index = row_range.second - 1; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + const row_index_range_t& r = dsv_index_.row_index[i]; + if (col < dsv_index_.token_count(r)) + { + row_type row = row_type(i,dsv_index_); + const range_t& range = row.token(col); + if (!delimiter.empty() && appended && (pre_end_index != i)) + result.append(delimiter); + appended = false; + if (range.first != range.second) + { + if (predicate(row)) + { + result.append(range.first,range.second); + appended = true; + } + } + } + } + return true; + } + + template + inline bool join_column(const std::size_t& col, + Predicate p, + const std::string& delimiter, + std::string& result) const + { + return join_column(col,all_rows(),p,delimiter,result); + } + + template + inline bool sequential_partition(const row_range_t& row_range, + TransitionPredicate p, + Function f) + { + if (row_range_invalid(row_range)) + return false; + row_range_t r(row_range.first,row_range.first); + for (row_range_t::first_type i = row_range.first; i < row_range.second; ++i) + { + if (p(row_type(i,dsv_index_))) + { + if (r.first != r.second) + { + r.second = i; + if (!f(*this,r)) + return false; + } + r.first = r.second; + } + else + r.second = i; + } + if (r.first != row_range.second) + { + r.second = row_range.second; + if (!f(*this,r)) + return false; + } + return true; + } + + template + inline bool sequential_partition(TransitionPredicate p, Function f) + { + return sequential_partition(all_rows(),p,f); + } + + static inline token_grid::options default_options() + { + return options(); + } + + template + inline std::size_t for_each_row(const row_range_t& row_range, Function f) const + { + if (row_range_invalid(row_range)) + return 0; + std::size_t row_count = 0; + for (std::size_t i = row_range.first; i < row_range.second; ++i) + { + f(row_type(i,dsv_index_)); + ++row_count; + } + return row_count; + } + + template + inline std::size_t for_each_row(Function f) const + { + return for_each_row(all_rows(),f); + } + + bool load(const std::string& file_name, + const token_grid::options& options) + { + file_name_ = file_name; + if ((load_from_file_) && (0 != buffer_)) + { + delete [] buffer_; + buffer_ = 0; + } + buffer_size_ = 0; + min_column_count_ = 0; + max_column_count_ = 0; + options_ = options; + load_from_file_ = true; + state_ = load(); + if (state_) + return true; + else + { + file_name_ = ""; + if ((load_from_file_) && (0 != buffer_)) + { + delete [] buffer_; + buffer_ = 0; + } + return false; + } + } + + bool load(unsigned char* buffer, + const std::size_t buffer_size, + const token_grid::options& options) + { + file_name_ = ""; + if ((load_from_file_) && (0 != buffer_)) + { + delete [] buffer_; + buffer_ = 0; + } + min_column_count_ = 0; + max_column_count_ = 0; + options_ = options; + load_from_file_ = false; + buffer_ = buffer; + buffer_size_ = buffer_size; + state_ = load(); + if (state_) + return true; + else + { + file_name_ = ""; + if ((load_from_file_) && (0 != buffer_)) + { + delete [] buffer_; + buffer_ = 0; + } + return false; + } + } + + private: + + token_grid(const token_grid& tg); + token_grid& operator=(const token_grid& tg); + + struct is_empty_token + { + inline bool operator()(const range_t& r) const + { + return r.first == r.second; + } + }; + + struct insufficient_number_of_columns + { + insufficient_number_of_columns(const std::size_t& noc) + : num_of_cols(noc) + {} + + inline bool operator()(const row_type& row) const + { + return (num_of_cols != row.size()); + } + + std::size_t num_of_cols; + }; + + struct insufficient_number_of_minmax_columns + { + insufficient_number_of_minmax_columns(const std::size_t& min_col, const std::size_t& max_col) + : min_column_count(min_col), + max_column_count(max_col) + {} + + inline bool operator()(const row_type& row) const + { + return (row.size() < min_column_count) || (max_column_count < row.size()); + } + + std::size_t min_column_count; + std::size_t max_column_count; + }; + + class double_quotes_predicate + { + public: + + double_quotes_predicate(const std::string& delimiters) + : in_bracket_range_(false), + mdp_(delimiters) + {} + + inline bool operator()(const unsigned char c) const + { + if ('"' == c) + { + in_bracket_range_ = !in_bracket_range_; + return false; + } + else if (in_bracket_range_) + return false; + else + return mdp_(c); + } + + inline void reset() + { + in_bracket_range_ = false; + } + + private: + + mutable bool in_bracket_range_; + mutable strtk::multiple_char_delimiter_predicate mdp_; + }; + + inline bool load() + { + if (load_from_file_ && !load_buffer_from_file()) + return false; + + dsv_index_.token_list.clear(); + dsv_index_.row_index.clear(); + + multiple_char_delimiter_predicate text_newline_predicate(options_.row_delimiters); + + if (!options_.support_dquotes) + { + multiple_char_delimiter_predicate token_predicate(options_.column_delimiters); + strtk::split(text_newline_predicate, + buffer_, buffer_ + buffer_size_, + strtk::functional_inserter( + row_processor(dsv_index_,token_predicate,options_.column_split_option)), + strtk::split_options::compress_delimiters); + } + else + { + double_quotes_predicate token_predicate_dblq(options_.column_delimiters); + strtk::split(text_newline_predicate, + buffer_, buffer_ + buffer_size_, + strtk::functional_inserter( + row_processor(dsv_index_,token_predicate_dblq,options_.column_split_option)), + strtk::split_options::compress_delimiters); + + if (options_.trim_dquotes) + { + for (std::size_t i = 0; i < dsv_index_.token_list.size(); ++i) + { + if ( + ((*(dsv_index_.token_list[i].first )) == '"') && + ((*(dsv_index_.token_list[i].second - 1)) == '"') + ) + { + ++dsv_index_.token_list[i].first; + --dsv_index_.token_list[i].second; + } + } + } + } + update_minmax_columns(); + return true; + } + + inline bool load_buffer_from_file() + { + std::ifstream stream(file_name_.c_str(),std::ios::binary); + if (!stream) + return false; + stream.seekg (0,std::ios::end); + buffer_size_ = static_cast(stream.tellg()); + if (0 == buffer_size_) + return false; + stream.seekg (0,std::ios::beg); + buffer_ = new unsigned char[buffer_size_]; + stream.read(reinterpret_cast(buffer_),static_cast(buffer_size_)); + stream.close(); + return true; + } + + template + inline void process_token(const range_t& range, OutputIterator out) const + { + typedef typename std::iterator_traits::value_type output_type; + (*out) = string_to_type_converter(range.first,range.second); + ++out; + } + + template + inline void process_token_checked(const range_t& range, OutputIterator out) const + { + typedef typename std::iterator_traits::value_type output_type; + output_type value; + if (string_to_type_converter(range.first,range.second,value)) + { + (*out) = value; + ++out; + } + } + + inline bool row_range_invalid(const row_range_t& row_range) const + { + if (row_range.first > dsv_index_.row_index.size()) + return true; + else if (row_range.second > dsv_index_.row_index.size()) + return true; + else if (row_range.first > row_range.second) + return true; + else + return false; + } + + inline void update_minmax_columns() + { + min_column_count_ = std::numeric_limits::max(); + max_column_count_ = std::numeric_limits::min(); + for (std::size_t i = 0; i < dsv_index_.row_index.size(); ++i) + { + const row_index_range_t& r = dsv_index_.row_index[i]; + const std::size_t number_of_tokens = dsv_index_.token_count(r); + if (number_of_tokens > max_column_count_) + max_column_count_ = number_of_tokens; + if (number_of_tokens < min_column_count_) + min_column_count_ = number_of_tokens; + } + } + + private: + + store dsv_index_; + std::string file_name_; + unsigned char* buffer_; + std::size_t buffer_size_; + std::size_t min_column_count_; + std::size_t max_column_count_; + options options_; + bool load_from_file_; + bool state_; + }; + + template + inline bool convert_string_range(const std::pair& range, T& t) + { + if (range.first == range.second) return false; + t = string_to_type_converter(std::string(range.first,range.second)); + return true; + } + + struct empty_range + { + public: + + template + inline bool operator()(const InputIterator begin, const InputIterator end) + { + return (0 == std::distance(begin,end)); + } + }; + + struct nonempty_range + { + public: + + template + inline bool operator()(const InputIterator begin, const InputIterator end) + { + return (0 != std::distance(begin,end)); + } + }; + + template + struct filter_non_empty_range + { + public: + + filter_non_empty_range(OutputIterator out) + : out_(out) + {} + + template + inline void operator() (const std::pair& range) + { + if (range.first != range.second) + { + *out_++ = range; + } + } + + private: + + OutputIterator out_; + }; + + template + struct filter_on_wildcard_match + { + public: + + filter_on_wildcard_match(const std::string& match_pattern, + OutputPredicate& predicate, + bool allow_through_on_match = true) + : allow_through_on_match_(allow_through_on_match), + match_pattern_(match_pattern), + predicate_(predicate) + {} + + template + inline void operator() (const std::pair& range) const + { + if (match(match_pattern_.begin(),match_pattern_.end(),range.first,range.second,'*','?') ^ allow_through_on_match_) + { + predicate_(range); + } + } + + inline void operator() (const std::string& s) const + { + if (match(match_pattern_,s) ^ allow_through_on_match_) + { + predicate_(s); + } + } + + private: + + filter_on_wildcard_match(const filter_on_wildcard_match& fom); + filter_on_wildcard_match& operator=(const filter_on_wildcard_match& fom); + + bool allow_through_on_match_; + std::string match_pattern_; + OutputPredicate& predicate_; + }; + + template + struct filter_on_match + { + public: + + filter_on_match(const std::string* begin, const std::string* end, + OutputPredicate predicate, + bool case_insensitive, + bool allow_through_on_match = true) + : case_insensitive_(case_insensitive), + allow_through_on_match_(allow_through_on_match), + begin_(begin), + end_(end), + predicate_(predicate) + {} + + template + inline void operator() (const std::pair& range) const + { + for (const std::string* itr = begin_; end_ != itr; ++itr) + { + if ((case_insensitive_ && + (imatch((*itr).data(),(*itr).data() + (*itr).size(),range.first,range.second))) || + (!case_insensitive_ && std::equal((*itr).begin(),(*itr).end(),range.first))) + { + if (allow_through_on_match_) + { + predicate_(range); + } + return; + } + } + + if (!allow_through_on_match_) + { + predicate_(range); + return; + } + } + + inline void operator() (const std::string& s) const + { + for (const std::string* itr = begin_; end_ != itr; ++itr) + { + if ((case_insensitive_ && + (imatch((*itr).begin(),(*itr).end(),s.begin(),s.end()))) || + (!case_insensitive_ && std::equal((*itr).begin(),(*itr).end(),s.begin()))) + { + if (allow_through_on_match_) + { + predicate_(s); + return; + } + } + } + + if (!allow_through_on_match_) + { + predicate_(s); + return; + } + } + + private: + + filter_on_match& operator=(const filter_on_match& fom); + + private: + + bool case_insensitive_; + bool allow_through_on_match_; + const std::string* begin_; + const std::string* end_; + OutputPredicate predicate_; + }; + + template + inline void skip_while_matching(Iterator& itr, + const Iterator& end, + const MatchPredicate& predicate) + { + while (end != itr) + { + if (predicate(*itr)) + ++itr; + else + break; + } + } + + template + struct size_equal_to + { + template + inline bool operator()(const Iterator begin, const Iterator end) const + { + return length == std::distance(begin,end); + } + + template + inline bool operator()(const std::pair& range) const + { + return length == std::distance(range.first,range.second); + } + + template class Sequence> + inline bool operator()(const Sequence& sequence) const + { + return length == sequence.size(); + } + + template + inline bool operator()(const std::set& set) const + { + return length == set.size(); + } + + template + inline bool operator()(const std::multiset& multiset) const + { + return length == multiset.size(); + } + + inline bool operator()(const std::string& str) const + { + return length == str.size(); + } + }; + + template + struct size_less_than + { + template + inline bool operator()(const Iterator begin, const Iterator end) const + { + return std::distance(begin,end) < static_cast::difference_type>(length); + } + + template + inline bool operator()(const std::pair& range) const + { + return std::distance(range.first,range.second) < static_cast::difference_type>(length); + } + + template class Sequence> + inline bool operator()(const Sequence& sequence) const + { + return sequence.size() < length; + } + + template + inline bool operator()(const std::set& set) const + { + return set.size() < length; + } + + template + inline bool operator()(const std::multiset& multiset) const + { + return multiset.size() < length; + } + + inline bool operator()(const std::string& str) const + { + return str.size() < length; + } + }; + + template + struct size_greater_than + { + template + inline bool operator()(const Iterator begin, const Iterator end) const + { + return std::distance(begin,end) > static_cast::difference_type>(length); + } + + template + inline bool operator()(const std::pair& range) const + { + return std::distance(range.first,range.second) > static_cast::difference_type>(length); + } + + template class Sequence> + inline bool operator()(const Sequence& sequence) const + { + return sequence.size() > length; + } + + template + inline bool operator()(const std::set& set) const + { + return set.size() > length; + } + + template + inline bool operator()(const std::multiset& multiset) const + { + return multiset.size() > length; + } + + inline bool operator()(const std::string& str) const + { + return str.size() > length; + } + }; + + struct size_is_even + { + template + inline bool operator()(const Iterator begin, const Iterator end) const + { + return 0 == (std::distance(begin,end) % 2); + } + + template + inline bool operator()(const std::pair& range) const + { + return 0 == (std::distance(range.first,range.second) % 2); + } + + template class Sequence> + inline bool operator()(const Sequence& sequence) const + { + return 0 == (sequence.size() % 2); + } + + template + inline bool operator()(const std::set& set) const + { + return 0 == (set.size() % 2); + } + + template + inline bool operator()(const std::multiset& multiset) const + { + return 0 == (multiset.size() % 2); + } + + inline bool operator()(const std::string& str) const + { + return 0 == (str.size() % 2); + } + }; + + struct size_is_odd + { + template + inline bool operator()(const Iterator begin, const Iterator end) const + { + return 0 != (std::distance(begin,end) % 2); + } + + template + inline bool operator()(const std::pair& range) const + { + return 0 != (std::distance(range.first,range.second) % 2); + } + + template class Sequence> + inline bool operator()(const Sequence& sequence) const + { + return 0 != (sequence.size() % 2); + } + + template + inline bool operator()(const std::set& set) const + { + return 0 != (set.size() % 2); + } + + template + inline bool operator()(const std::multiset& multiset) const + { + return 0 != (multiset.size() % 2); + } + + inline bool operator()(const std::string& str) const + { + return 0 != (str.size() % 2); + } + }; + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10, T11& t11, T12& t12) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 12; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second, t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t9)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t10)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t11)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t12)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10, T11& t11) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 11; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second, t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t9)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t10)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t11)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 10; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second, t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t9)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t10)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 9; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t9)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 8; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t8)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 7; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t7)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 6; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 5; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 4; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 3; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 2; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; + return true; + } + + template + inline bool parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + T& t) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + static const std::size_t token_count = 1; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + iterator_type token_list[token_count]; + const std::size_t parsed_token_count = split_n(delimiters, + begin,end, + token_count, + token_list, + split_options::compress_delimiters); + if (token_count > parsed_token_count) + return false; + iterator_type_ptr itr = token_list; + return string_to_type_converter((*itr).first,(*itr).second,t); + } + + template class Sequence> + inline std::size_t parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + begin,end, + range_to_type_back_inserter(sequence), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + begin, end, + range_to_type_back_inserter(sequence), + split_option); + } + + template + inline std::size_t parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + begin,end, + range_to_type_inserter(set), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + begin,end, + range_to_type_inserter(set), + split_option); + } + + template + inline std::size_t parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + begin,end, + range_to_type_inserter(multiset), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + begin,end, + range_to_type_inserter(multiset), + split_option); + } + + template + inline std::size_t parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + begin,end, + range_to_type_push_inserter(queue), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + begin,end, + range_to_type_push_inserter(queue), + split_option); + } + + template + inline std::size_t parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + begin,end, + range_to_type_push_inserter(stack), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + begin, end, + range_to_type_push_inserter(stack), + split_option); + } + + template + inline std::size_t parse(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + begin,end, + range_to_type_push_inserter(priority_queue), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + begin,end, + range_to_type_push_inserter(priority_queue), + split_option); + } + + template class Sequence> + inline std::size_t parse(const std::pair& range, + const std::string& delimiters, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + range_to_type_back_inserter(sequence), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + range_to_type_back_inserter(sequence), + split_option); + } + + template + inline std::size_t parse(const std::pair& range, + const std::string& delimiters, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + range_to_type_inserter(set), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + range_to_type_inserter(set), + split_option); + } + + template + inline std::size_t parse(const std::pair& range, + const std::string& delimiters, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + range_to_type_inserter(multiset), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + range_to_type_inserter(multiset), + split_option); + } + + template + inline std::size_t parse(const std::pair& range, + const std::string& delimiters, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + range_to_type_push_inserter(queue), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + range_to_type_push_inserter(queue), + split_option); + } + + template + inline std::size_t parse(const std::pair& range, + const std::string& delimiters, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + range_to_type_push_inserter(stack), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + range_to_type_push_inserter(stack), + split_option); + } + + template + inline std::size_t parse(const std::pair& range, + const std::string& delimiters, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + details::convert_type_assert(); + if (1 == delimiters.size()) + return split(single_delimiter_predicate(delimiters[0]), + range.first,range.second, + range_to_type_push_inserter(priority_queue), + split_option); + else + return split(multiple_char_delimiter_predicate(delimiters), + range.first,range.second, + range_to_type_push_inserter(priority_queue), + split_option); + } + + namespace details + { + class container_adder + { + private: + + class container_adder_base + { + public: + + typedef const char* itr_type; + + virtual ~container_adder_base(){} + + template + inline bool add(const InputIterator begin, const InputIterator end) const + { + return add_impl(begin,end); + } + + template + inline bool add(const std::pair& range) const + { + return add(range.first,range.second); + } + + protected: + + virtual bool add_impl(const itr_type begin, const itr_type end) const = 0; + + }; + + template class Sequence> + class sequence_adder_impl : public container_adder_base + { + public: + + typedef Sequence sequence_t; + + sequence_adder_impl(sequence_t& seq) + : sequence_(seq) + {} + + protected: + + bool add_impl(const itr_type begin, const itr_type end) const + { + T t; + if (!string_to_type_converter(begin,end,t)) return false; + sequence_.push_back(t); + return true; + } + + private: + + sequence_adder_impl operator=(const sequence_adder_impl&); + + sequence_t& sequence_; + }; + + template class Set> + class set_adder_impl : public container_adder_base + { + public: + + set_adder_impl(Set& set) + : set_(set) + {} + + bool add_impl(const itr_type begin, const itr_type end) const + { + T t; + if (!string_to_type_converter(begin,end,t)) return false; + set_.insert(t); + return true; + } + + private: + + set_adder_impl operator=(const set_adder_impl&); + + Set& set_; + }; + + template + class pq_adder_impl : public container_adder_base + { + public: + + pq_adder_impl(std::priority_queue& pq) + : pq_(pq) + {} + + bool add_impl(const itr_type begin, const itr_type end) const + { + T t; + if (!string_to_type_converter(begin,end,t)) return false; + pq_.push(t); + return true; + } + + private: + + pq_adder_impl operator=(const pq_adder_impl&); + + std::priority_queue& pq_; + }; + + template class SContainer> + class stack_queue_adder_impl : public container_adder_base + { + public: + + stack_queue_adder_impl(SContainer& container) + : container_(container) + {} + + bool add_impl(const itr_type begin, const itr_type end) const + { + T t; + if (!string_to_type_converter(begin,end,t)) return false; + container_.push(t); + return true; + } + + private: + + stack_queue_adder_impl operator=(const stack_queue_adder_impl&); + + SContainer& container_; + }; + + public: + + template + container_adder(std::vector& vec) + : container_adder_base_(new(buffer)sequence_adder_impl(vec)) + {} + + template + container_adder(std::deque& deq) + : container_adder_base_(new(buffer)sequence_adder_impl(deq)) + {} + + template + container_adder(std::list& list) + : container_adder_base_(new(buffer)sequence_adder_impl(list)) + {} + + template + container_adder(std::set& set) + : container_adder_base_(new(buffer)set_adder_impl(set)) + {} + + template + container_adder(std::multiset& multiset) + : container_adder_base_(new(buffer)set_adder_impl(multiset)) + {} + + template + container_adder(std::priority_queue& pq) + : container_adder_base_(new(buffer)pq_adder_impl(pq)) + {} + + template + container_adder(std::queue& queue) + : container_adder_base_(new(buffer)stack_queue_adder_impl(queue)) + {} + + template + container_adder(std::stack& stack) + : container_adder_base_(new(buffer)stack_queue_adder_impl(stack)) + {} + + template + inline bool add(InputIterator begin, InputIterator end) const + { + return container_adder_base_->add(begin,end); + } + + template + inline bool add(std::pair& range) const + { + return add(range.first,range.second); + } + + template + inline bool operator()(const InputIterator begin, const InputIterator end) + { + InputIterator itr = begin; + while (end != itr) + { + if (!add(*itr)) return false; + ++itr; + } + return true; + } + + private: + + mutable container_adder_base* container_adder_base_; + unsigned char buffer[64]; + }; + + template + struct ca_type { typedef T& type; }; + + template + struct ca_type { typedef details::container_adder type; }; + + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, + T8& t8, T9& t9, T10& t10, T11& t11, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 12) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second, t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t9)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t10)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t11)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, T10& t10, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 11) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second, t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second, t9)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t10)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 10) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t8)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t9)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 9) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t7)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t8)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 8) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t7)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 7) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t6)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 6) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t5)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 5) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t4)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 4) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t3)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, T2& t2, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 3) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + if (!string_to_type_converter((*itr).first,(*itr).second,t2)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template + inline bool parse(const InputIterator begin, const InputIterator end, + const std::string& delimiters, + T1& t1, + details::container_adder ca) + { + typedef typename details::is_valid_iterator::type itr_type; + typedef std::pair iterator_type; + typedef typename std::deque::iterator iterator_type_ptr; + details::convert_type_assert(); + std::deque token_list; + if (1 == delimiters.size()) + split(single_delimiter_predicate(delimiters[0]), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + else + split(multiple_char_delimiter_predicate(delimiters), + begin,end, + std::back_inserter(token_list), + split_options::compress_delimiters); + if (token_list.size() < 2) return false; + iterator_type_ptr itr = token_list.begin(); + if (!string_to_type_converter((*itr).first,(*itr).second,t1)) return false; ++itr; + return ca(itr,token_list.end()); + } + + template class Sequence> + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + const std::size_t original_size = sequence.size(); + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_type_back_inserter(sequence), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_type_back_inserter(sequence), + split_option); + return sequence.size() - original_size; + } + + template + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + const std::size_t original_size = set.size(); + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_type_inserter(set), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_type_inserter(set), + split_option); + return set.size() - original_size; + } + + template + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + const std::size_t original_size = multiset.size(); + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_type_inserter(multiset), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_type_inserter(multiset), + split_option); + return multiset.size() - original_size; + } + + template + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + const std::size_t original_size = queue.size(); + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_type_push_inserter(queue), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_type_push_inserter(queue), + split_option); + return queue.size() - original_size; + } + + template + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + const std::size_t original_size = stack.size(); + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_type_push_inserter(stack), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_type_push_inserter(stack), + split_option); + return stack.size() - original_size; + } + + template + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + const std::size_t original_size = priority_queue.size(); + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_type_push_inserter(priority_queue), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_type_push_inserter(priority_queue), + split_option); + return priority_queue.size() - original_size; + } + + template + inline std::size_t parse_n(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + T* out, + const split_options::type& split_option = split_options::compress_delimiters) + { + typedef typename details::is_valid_iterator::type itr_type; + std::size_t insert_count = 0; + details::convert_type_assert(); + if (1 == delimiters.size()) + split_n(single_delimiter_predicate(delimiters[0]), + begin,end, + n, + range_to_ptr_type(out,insert_count), + split_option); + else + split_n(multiple_char_delimiter_predicate(delimiters), + begin,end, + n, + range_to_ptr_type(out,insert_count), + split_option); + return insert_count; + } + + template class Sequence> + inline std::size_t parse_n(const std::pair& range, + const std::string& delimiters, + const std::size_t& n, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(range.first,range.second,delimiters,n,sequence,split_option); + } + + template + inline std::size_t parse_n(const std::pair& range, + const std::string& delimiters, + const std::size_t& n, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(range.first,range.second,delimiters,n,set,split_option); + } + + template + inline std::size_t parse_n(const std::pair& range, + const std::string& delimiters, + const std::size_t& n, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(range.first,range.second,delimiters,n,multiset,split_option); + } + + template + inline std::size_t parse_n(const std::pair& range, + const std::string& delimiters, + const std::size_t& n, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(range.first,range.second,delimiters,n,queue,split_option); + } + + template + inline std::size_t parse_n(const std::pair& range, + const std::string& delimiters, + const std::size_t& n, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(range.first,range.second,delimiters,n,stack,split_option); + } + + template + inline std::size_t parse_n(const std::pair& range, + const std::string& delimiters, + const std::size_t& n, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(range.first,range.second,delimiters,n,priority_queue,split_option); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10, T11& t11, T12& t12) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11, + typename details::ca_type::result_t>::type(t12)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10, T11& t11) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6,t7,t8,t9,t10, + typename details::ca_type::result_t>::type(t11)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6,t7,t8,t9, + typename details::ca_type::result_t>::type(t10)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6,t7,t8, + typename details::ca_type::result_t>::type(t9)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6,t7, + typename details::ca_type::result_t>::type(t8)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6, + typename details::ca_type::result_t>::type(t7)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5, + typename details::ca_type::result_t>::type(t6)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4, + typename details::ca_type::result_t>::type(t5)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3, + typename details::ca_type::result_t>::type(t4)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2, + typename details::ca_type::result_t>::type(t3)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T1& t1, T2& t2) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + t1, + typename details::ca_type::result_t>::type(t2)); + } + + template + inline bool parse(const std::string& data, + const std::string& delimiters, + T& t) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + typename details::ca_type::result_t>::type(t)); + } + + template class Sequence> + inline std::size_t parse(const std::string& data, + const std::string& delimiters, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + sequence, + split_option); + } + + template + inline std::size_t parse(const std::string& data, + const std::string& delimiters, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + set, + split_option); + } + + template + inline std::size_t parse(const std::string& data, + const std::string& delimiters, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + multiset, + split_option); + } + + template + inline std::size_t parse(const std::string& data, + const std::string& delimiters, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + queue, + split_option); + } + + template + inline std::size_t parse(const std::string& data, + const std::string& delimiters, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + stack, + split_option); + } + + template + inline std::size_t parse(const std::string& data, + const std::string& delimiters, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(data.data(), + data.data() + data.size(), + delimiters, + priority_queue, + split_option); + } + + template class Sequence> + inline std::size_t parse(const int& argc, char* argv[], + Sequence& sequence, + const bool break_on_fail = true) + { + T tmp; + for (int i = 0; i < argc; ++i) + { + if (!string_to_type_converter(std::string(argv[i]),tmp)) + { + if (break_on_fail) + return i; + else + continue; + } + sequence.push_back(tmp); + } + return argc; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9) + + { + if (9 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + if (!string_to_type_converter(std::string(argv[3]),t4)) return result; ++result; + if (!string_to_type_converter(std::string(argv[4]),t5)) return result; ++result; + if (!string_to_type_converter(std::string(argv[5]),t6)) return result; ++result; + if (!string_to_type_converter(std::string(argv[6]),t7)) return result; ++result; + if (!string_to_type_converter(std::string(argv[7]),t8)) return result; ++result; + if (!string_to_type_converter(std::string(argv[8]),t9)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + + { + if (8 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + if (!string_to_type_converter(std::string(argv[3]),t4)) return result; ++result; + if (!string_to_type_converter(std::string(argv[4]),t5)) return result; ++result; + if (!string_to_type_converter(std::string(argv[5]),t6)) return result; ++result; + if (!string_to_type_converter(std::string(argv[6]),t7)) return result; ++result; + if (!string_to_type_converter(std::string(argv[7]),t8)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7) + + { + if (7 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + if (!string_to_type_converter(std::string(argv[3]),t4)) return result; ++result; + if (!string_to_type_converter(std::string(argv[4]),t5)) return result; ++result; + if (!string_to_type_converter(std::string(argv[5]),t6)) return result; ++result; + if (!string_to_type_converter(std::string(argv[6]),t7)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6) + + { + if (6 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + if (!string_to_type_converter(std::string(argv[3]),t4)) return result; ++result; + if (!string_to_type_converter(std::string(argv[4]),t5)) return result; ++result; + if (!string_to_type_converter(std::string(argv[5]),t6)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) + { + if (5 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + if (!string_to_type_converter(std::string(argv[3]),t4)) return result; ++result; + if (!string_to_type_converter(std::string(argv[4]),t5)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3, T4& t4) + { + if (4 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + if (!string_to_type_converter(std::string(argv[3]),t4)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2, T3& t3) + { + if (3 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + if (!string_to_type_converter(std::string(argv[2]),t3)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1, T2& t2) + { + if (2 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + if (!string_to_type_converter(std::string(argv[1]),t2)) return result; ++result; + return result; + } + + template + inline std::size_t parse(const int& argc, char* argv[], + T1& t1) + { + if (1 != argc) return 0; + std::size_t result = 0; + if (!string_to_type_converter(std::string(argv[0]),t1)) return result; ++result; + return result; + } + + #define strtk_parse_begin(Type) \ + namespace strtk { \ + bool parse(const std::string& data, const std::string& delimiters, Type& t)\ + { return parse(data,delimiters \ + + #define strtk_parse_type(T) \ + ,t.T \ + + #define strtk_parse_hex_type(T) \ + ,t.T \ + + #define strtk_parse_ignore_token() \ + ,ignore_token() \ + + #define strtk_parse_end() \ + );}} \ + + template class Sequence> + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + sequence, + split_option); + } + + template + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + set, + split_option); + } + + template + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + multiset, + split_option); + } + + template + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + queue, + split_option); + } + + template + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + stack, + split_option); + } + + template + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + priority_queue, + split_option); + } + + template + inline std::size_t parse_n(const std::string& data, + const std::string& delimiters, + const std::size_t& n, + T* out, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + out, + split_option); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7, T8& t8, T9& t9, T10& t10, T11& t11, T12& t12) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6, + t7,t8,t9,t10,t11,t12); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7, T8& t8, T9& t9, T10& t10, T11& t11) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6, + t7,t8,t9,t10,t11); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7, T8& t8, T9& t9, T10& t10) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6, + t7,t8,t9,t10); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7, T8& t8, T9& t9) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6, + t7,t8,t9); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7, T8& t8) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6, + t7,t8); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6,t7); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5,t6); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4,t5); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3, T4& t4) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3,t4); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2, T3& t3) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2,t3); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1, T2& t2) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1,t2); + } + + template + inline bool parse_line(std::ifstream& stream, + const std::string& delimiters, + T1& t1) + { + if (!stream) + return false; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return false; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + t1); + } + + template class Sequence> + inline std::size_t parse_line(std::ifstream& stream, + const std::string& delimiters, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + sequence, + split_option); + } + + template + inline std::size_t parse_line(std::ifstream& stream, + const std::string& delimiters, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + set, + split_option); + } + + template + inline std::size_t parse_line(std::ifstream& stream, + const std::string& delimiters, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + multiset, + split_option); + } + + template + inline std::size_t parse_line(std::ifstream& stream, + const std::string& delimiters, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + queue, + split_option); + } + + template + inline std::size_t parse_line(std::ifstream& stream, + const std::string& delimiters, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + stack, + split_option); + } + + template + inline std::size_t parse_line(std::ifstream& stream, + const std::string& delimiters, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return false; + return strtk::parse(data.data(), + data.data() + data.size(), + delimiters, + priority_queue, + split_option); + } + + template class Sequence> + inline std::size_t parse_line_n(std::ifstream& stream, + const std::string& delimiters, + const std::size_t& n, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return 0; + return strtk::parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + sequence, + split_option); + } + + template + inline std::size_t parse_line_n(std::ifstream& stream, + const std::string& delimiters, + const std::size_t& n, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return 0; + return strtk::parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + set, + split_option); + } + + template + inline std::size_t parse_line_n(std::ifstream& stream, + const std::string& delimiters, + const std::size_t& n, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return 0; + return strtk::parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + multiset, + split_option); + } + + template + inline std::size_t parse_line_n(std::ifstream& stream, + const std::string& delimiters, + const std::size_t& n, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return 0; + return strtk::parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + queue, + split_option); + } + + template + inline std::size_t parse_line_n(std::ifstream& stream, + const std::string& delimiters, + const std::size_t& n, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return 0; + return strtk::parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + stack, + split_option); + } + + template + inline std::size_t parse_line_n(std::ifstream& stream, + const std::string& delimiters, + const std::size_t& n, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + + { + if (!stream) + return 0; + std::string data; + data.reserve(strtk::one_kilobyte); + if (!std::getline(stream,data)) + return 0; + if (data.empty() || delimiters.empty()) + return 0; + return strtk::parse_n(data.data(), + data.data() + data.size(), + delimiters, + n, + priority_queue, + split_option); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10, const T11& t11, const T12& t12) + { + output += type_to_string( t1); output += delimiter; + output += type_to_string( t2); output += delimiter; + output += type_to_string( t3); output += delimiter; + output += type_to_string( t4); output += delimiter; + output += type_to_string( t5); output += delimiter; + output += type_to_string( t6); output += delimiter; + output += type_to_string( t7); output += delimiter; + output += type_to_string( t8); output += delimiter; + output += type_to_string( t9); output += delimiter; + output += type_to_string(t10); output += delimiter; + output += type_to_string(t11); output += delimiter; + output += type_to_string(t12); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10, const T11& t11) + { + output += type_to_string( t1); output += delimiter; + output += type_to_string( t2); output += delimiter; + output += type_to_string( t3); output += delimiter; + output += type_to_string( t4); output += delimiter; + output += type_to_string( t5); output += delimiter; + output += type_to_string( t6); output += delimiter; + output += type_to_string( t7); output += delimiter; + output += type_to_string( t8); output += delimiter; + output += type_to_string( t9); output += delimiter; + output += type_to_string(t10); output += delimiter; + output += type_to_string(t11); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); output += delimiter; + output += type_to_string(t5); output += delimiter; + output += type_to_string(t6); output += delimiter; + output += type_to_string(t7); output += delimiter; + output += type_to_string(t8); output += delimiter; + output += type_to_string(t9); output += delimiter; + output += type_to_string(t10); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); output += delimiter; + output += type_to_string(t5); output += delimiter; + output += type_to_string(t6); output += delimiter; + output += type_to_string(t7); output += delimiter; + output += type_to_string(t8); output += delimiter; + output += type_to_string(t9); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); output += delimiter; + output += type_to_string(t5); output += delimiter; + output += type_to_string(t6); output += delimiter; + output += type_to_string(t7); output += delimiter; + output += type_to_string(t8); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); output += delimiter; + output += type_to_string(t5); output += delimiter; + output += type_to_string(t6); output += delimiter; + output += type_to_string(t7); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); output += delimiter; + output += type_to_string(t5); output += delimiter; + output += type_to_string(t6); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); output += delimiter; + output += type_to_string(t5); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); output += delimiter; + output += type_to_string(t4); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2, const T3& t3) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); output += delimiter; + output += type_to_string(t3); + } + + template + inline void construct(std::string& output, + const std::string& delimiter, + const T1& t1, const T2& t2) + { + output += type_to_string(t1); output += delimiter; + output += type_to_string(t2); + } + + template + inline void join(std::string& output, + const std::string& delimiter, + const InputIterator begin, + const InputIterator end) + { + InputIterator itr = begin; + while (end != itr) + { + output += type_to_string(*itr); + if (end == (++itr)) + break; + else + output += delimiter; + } + } + + template + inline void join(std::string& output, + const std::string& delimiter, + const std::pair& range) + { + InputIterator itr = range.first; + while (range.second != itr) + { + output += type_to_string(*itr); + if (range.second == (++itr)) + break; + else + output += delimiter; + } + } + + template class Sequence> + inline void join(std::string& output, + const std::string& delimiter, + const Sequence& sequence) + { + join(output,delimiter,sequence.begin(),sequence.end()); + } + + template + inline void join(std::string& output, + const std::string& delimiter, + const std::set& set) + { + join(output,delimiter,set.begin(),set.end()); + } + + template + inline void join(std::string& output, + const std::string& delimiter, + const std::multiset& multiset) + { + join(output,delimiter,multiset.begin(),multiset.end()); + } + + inline void join(std::string& output, + const std::string& delimiter, + int argc, char* argv[]) + { + for (int i = 0; i < argc; ++i) + { + output += argv[i]; + if (i < (argc - 1)) + output += delimiter; + } + } + + template + inline std::string join(const std::string& delimiter, + const InputIterator begin, + const InputIterator end) + { + std::string output; + output.reserve(one_kilobyte); + join(output,delimiter,begin,end); + return output; + } + + template + inline std::string join(const std::string& delimiter, + const std::pair& range) + { + std::string output; + output.reserve(one_kilobyte); + join(output,delimiter,range.first,range.second); + return output; + } + + template class Sequence> + inline std::string join(const std::string& delimiter, + const Sequence& sequence) + { + if (sequence.empty()) + return ""; + else + return join(delimiter,sequence.begin(),sequence.end()); + } + + template + inline std::string join(const std::string& delimiter, + const std::set& set) + { + if (set.empty()) + return ""; + else + return join(delimiter,set.begin(),set.end()); + } + + template + inline std::string join(const std::string& delimiter, + const std::multiset& multiset) + { + if (multiset.empty()) + return ""; + else + return join(delimiter,multiset.begin(),multiset.end()); + } + + inline std::string join(const std::string& delimiter, int argc, char* argv[]) + { + std::string result; + result.reserve(one_kilobyte); + join(result,delimiter,argc,argv); + return result; + } + + template + inline void join_if(std::string& output, + const std::string& delimiter, + Predicate predicate, + const InputIterator begin, + const InputIterator end) + { + InputIterator itr = begin; + bool first_time = true; + while (end != itr) + { + if (predicate(*itr)) + { + if (!first_time) + output += delimiter; + else + first_time = false; + output += type_to_string(*itr); + } + if (end == (++itr)) + break; + } + } + + template + inline void join_if(std::string& output, + const std::string& delimiter, + Predicate predicate, + const std::pair& range) + { + InputIterator itr = range.first; + bool first_time = true; + while (range.second != itr) + { + if (predicate(*itr)) + { + if (!first_time) + output += delimiter; + else + first_time = false; + output += type_to_string(*itr); + } + if (range.second == (++itr)) + break; + } + } + + template class Sequence> + inline void join_if(std::string& output, + const std::string& delimiter, + Predicate predicate, + const Sequence& sequence) + { + join_if(output,delimiter,predicate,sequence.begin(),sequence.end()); + } + + template + inline void join_if(std::string& output, + const std::string& delimiter, + Predicate predicate, + const std::set& set) + { + join_if(output,delimiter,predicate,set.begin(),set.end()); + } + + template + inline void join_if(std::string& output, + const std::string& delimiter, + Predicate predicate, + const std::multiset& multiset) + { + join_if(output,delimiter,predicate,multiset.begin(),multiset.end()); + } + + template + inline std::string join_if(const std::string& delimiter, + Predicate predicate, + const InputIterator begin, + const InputIterator end) + { + std::string output; + output.reserve(one_kilobyte); + join_if(output,delimiter,predicate,begin,end); + return output; + } + + template + inline std::string join_if(const std::string& delimiter, + Predicate predicate, + const std::pair& range) + { + std::string output; + output.reserve(one_kilobyte); + join_if(output,delimiter,predicate,range.first,range.second); + return output; + } + + template class Sequence> + inline std::string join_if(const std::string& delimiter, + Predicate predicate, + const Sequence& sequence) + { + return join(delimiter,predicate,sequence.begin(),sequence.end()); + } + + template + inline std::string join_if(const std::string& delimiter, + Predicate predicate, + const std::set& set) + { + return join_if(delimiter,predicate,set.begin(),set.end()); + } + + template + inline std::string join_if(const std::string& delimiter, + Predicate predicate, + const std::multiset& multiset) + { + return join_if(delimiter,predicate,multiset.begin(),multiset.end()); + } + + class build_string + { + public: + + build_string(const std::size_t& initial_size = 64) + { + data_.reserve(initial_size); + } + + template + inline build_string& operator << (const T& t) + { + data_ += type_to_string(t); + return (*this); + } + + inline build_string& operator << (const std::string& s) + { + data_ += s; + return (*this); + } + + inline std::string to_str() const + { + return data_; + } + + inline operator const char* () const + { + return data_.data(); + } + + private: + + std::string data_; + }; + + inline void replicate(const std::size_t& n, + const std::string& str, + std::string& output) + { + if (0 == n) return; + output.reserve(output.size() + (str.size() * n)); + for (std::size_t i = 0; i < n; ++i) + { + output.append(str); + } + } + + inline std::string replicate(const std::size_t& n, + const std::string& str) + { + std::string output; + replicate(n,str,output); + return output; + } + + inline void replicate_inplace(const std::size_t& n, + std::string& str) + { + std::string temp_str = str; + str.reserve(str.size() + (str.size() * n)); + + for (std::size_t i = 0; i < n; ++i) + { + str.append(temp_str); + } + } + + template + inline void bracketize(std::string& output, + const std::string& pre, + const std::string& post, + const InputIterator begin, + const InputIterator end) + { + InputIterator itr = begin; + std::string s; + s.reserve(one_kilobyte); + while (end != itr) + { + s.clear(); + s.append(pre); + s.append(type_to_string(*itr)); + s.append(post); + output.append(s); + ++itr; + } + } + + template class Sequence> + inline void bracketize(std::string& output, + const std::string& pre, + const std::string& post, + Sequence& sequence) + { + bracketize(output,pre,post,sequence.begin(),sequence.end()); + } + + template + inline void bracketize(std::string& output, + const std::string& pre, + const std::string& post, + std::set& set) + { + bracketize(output,pre,post,set.begin(),set.end()); + } + + template + inline void bracketize(std::string& output, + const std::string& pre, + const std::string& post, + std::multiset& multiset) + { + bracketize(output,pre,post,multiset.begin(),multiset.end()); + } + + template + inline std::string bracketize(const std::string& pre, + const std::string& post, + const InputIterator begin, + const InputIterator end) + { + std::string output; + output.reserve(one_kilobyte); + bracketize(output,pre,post,begin,end); + return output; + } + + template class Sequence> + inline std::string bracketize(const std::string& pre, + const std::string& post, + Sequence& sequence) + { + return bracketize(pre,post,sequence.begin(),sequence.end()); + } + + template + inline std::string bracketize(const std::string& pre, + const std::string& post, + std::set& set) + { + return bracketize(pre,post,set.begin(),set.end()); + } + + template + inline std::string bracketize(const std::string& pre, + const std::string& post, + std::multiset& multiset) + { + return bracketize(pre,post,multiset.begin(),multiset.end()); + } + + template + struct interval_inserter + { + typedef T type; + + interval_inserter(const std::size_t& interval, const T& t) + : count_(0), + interval_(interval), + t_(t) + {} + + inline bool operator()(const type&) + { + if (++count_ == interval_) + { + count_ = 0; + return true; + } + else + return false; + } + + inline T operator()() + { + return t_; + } + + private: + + std::size_t count_; + std::size_t interval_; + T t_; + }; + + template + inline std::size_t inserter(Inserter ins, + const InputIterator begin, const InputIterator end, + OutputIterator out) + { + std::size_t size = 0; + InputIterator itr = begin; + while (end != itr) + { + (*out) = (*itr); + ++out; + if (ins(*itr++)) + { + (*out) = ins(); + ++out; + size += 2; + } + else + ++size; + } + return size; + } + + template + inline void iota(Iterator begin, Iterator end, T value) + { + Iterator itr = begin; + while (end != itr) + { + (*itr) = value++; + ++itr; + } + } + + template + inline void iota(typename range::adapter& r, T value) + { + iota(r.begin(),r.end(),value); + } + + template class Sequence> + inline void iota(Sequence& sequence, std::size_t count, T value) + { + while (count) + { + sequence.push_back(value++); + --count; + } + } + + template + inline void iota(std::set& set, std::size_t count, T value) + { + while (count) + { + set.insert(value++); + --count; + } + } + + template + inline void iota(std::multiset& multiset, std::size_t count, T value) + { + while (count) + { + multiset.insert(value++); + --count; + } + } + + template + inline void iota(std::size_t count, T value, OutputIterator out) + { + while (count) + { + (*out) = value++; + ++out; + --count; + } + } + + template class Sequence> + inline void iota(Sequence& sequence, const T& value) + { + strtk::iota(sequence.begin(),sequence.end(),value); + } + + template + inline void iota(std::set& set, const T& value) + { + strtk::iota(set.begin(),set.end(),value); + } + + template + inline void iota(std::multiset& multiset, const T& value) + { + strtk::iota(multiset.begin(),multiset.end(),value); + } + + template + inline void cut(const std::size_t& r0, const std::size_t& r1, + const InputIterator begin, InputIterator end, + OutputIterator out) + { + // static assert: InputIterator must be of type std::string + InputIterator itr = begin; + while (end != itr) + { + const std::string& s = (*itr); + ++itr; + if (s.size() < r0) + continue; + (*out++) = s.substr(r0,std::min(r1,s.size()) - r0); + } + } + + template class Sequence, + typename OutputIterator> + inline void cut(const std::size_t& r0, const std::size_t& r1, + const Sequence& sequence, + OutputIterator out) + { + cut(r0,r1,sequence.begin(),sequence.end(),out); + } + + template + inline void cut_inplace(const std::size_t& r0, const std::size_t& r1, + const Iterator begin, const Iterator end) + { + // static assert: InputIterator must be of type std::string + Iterator itr = begin; + while (end != itr) + { + if ((*itr).size() >= r0) + { + (*itr) = (*itr).substr(r0,std::min(r1,(*itr).size()) - r0); + } + ++itr; + } + } + + template class Sequence> + inline void cut(const std::size_t& r0, const std::size_t& r1, + const Sequence& sequence) + { + cut(r0,r1,sequence.begin(),sequence.end()); + } + + template + inline void cut(const std::size_t& r0, const std::size_t& r1, + const std::set& set) + { + cut(r0,r1,set.begin(),set.end()); + } + + template + inline void cut(const std::size_t& r0, const std::size_t& r1, + const std::multiset& multiset) + { + cut(r0,r1,multiset.begin(),multiset.end()); + } + + class translation_table + { + public: + + translation_table(const std::string& itable, const std::string& otable) + { + if (itable.size() != otable.size()) + { + throw std::runtime_error("translation_table() - Input/Output table size mismatch."); + } + strtk::iota(table_, table_ + 256, static_cast(0)); + for (std::size_t i = 0; i < itable.size(); ++i) + { + table_[static_cast(itable[i])] = static_cast(otable[i]); + } + } + + inline char operator()(const char c) const + { + return static_cast(table_[static_cast(c)]); + } + + inline unsigned char operator()(const unsigned char c) const + { + return static_cast(table_[static_cast(c)]); + } + + private: + + unsigned char table_[256]; + }; + + inline std::string translate(const translation_table& trans_table, const std::string& s) + { + std::string result = s; + std::transform(result.begin(),result.end(),result.begin(),trans_table); + return result; + } + + inline void translate_inplace(const translation_table& trans_table, std::string& s) + { + std::transform(s.begin(),s.end(),s.begin(),trans_table); + } + + #ifdef strtk_enable_random + inline void generate_random_data(unsigned char* data, + std::size_t length, + unsigned int pre_gen_cnt = 0, + unsigned int seed = magic_seed) + { + boost::mt19937 rng(static_cast(seed)); + boost::uniform_int dist(std::numeric_limits::min(),std::numeric_limits::max()); + boost::variate_generator > rnd(rng,dist); + + if (pre_gen_cnt > 0) + { + while (pre_gen_cnt--) rnd(); + } + + unsigned char* itr = data; + unsigned int* x = 0; + while (length >= sizeof(unsigned int)) + { + x = reinterpret_cast(itr); + (*x) = rnd(); + itr += sizeof(unsigned int); + length -= sizeof(unsigned int); + } + + if (length > 0) + { + itr -= (sizeof(unsigned int) - length); + x = reinterpret_cast(itr); + (*x) = rnd(); + } + } + + namespace details + { + struct rand_int_type_tag {}; + struct rand_real_type_tag {}; + + template struct supported_random_type {}; + + #define strtk_register_rand_int_type_tag(T) \ + template<> struct supported_random_type { typedef rand_int_type_tag type; enum { value = true }; }; + + #define strtk_register_rand_real_type_tag(T) \ + template<> struct supported_random_type { typedef rand_real_type_tag type; enum { value = true }; }; + + strtk_register_rand_int_type_tag(char) + strtk_register_rand_int_type_tag(unsigned char) + + strtk_register_rand_int_type_tag(short) + strtk_register_rand_int_type_tag(int) + strtk_register_rand_int_type_tag(long) + strtk_register_rand_int_type_tag(unsigned short) + strtk_register_rand_int_type_tag(unsigned int) + strtk_register_rand_int_type_tag(unsigned long) + + strtk_register_rand_real_type_tag(float) + strtk_register_rand_real_type_tag(double) + strtk_register_rand_real_type_tag(long double) + + #undef strtk_register_rand_int_type_tag + #undef strtk_register_rand_real_type_tag + + template + inline void generate_random_values_impl(const std::size_t& count, + const T& min, + const T& max, + OutputIterator out, + RandomNumberGenerator& rng, + rand_int_type_tag) + { + // Note: The implied range will be: [min,max] + using namespace boost; + variate_generator > rnd(rng,uniform_int(min,max)); + for (std::size_t i = 0; i < count; ++i, *out++ = rnd()) ; + } + + template + inline void generate_random_values_impl(const std::size_t& count, + const T& min, + const T& max, + OutputIterator out, + RandomNumberGenerator& rng, + rand_real_type_tag) + { + // Note: The implied range will be: [min,max) + using namespace boost; + variate_generator > rnd(rng,uniform_real(min,max)); + for (std::size_t i = 0; i < count; ++i, *out++ = rnd()) ; + } + + } // namespace details + + class uniform_real_rng + { + private: + + typedef boost::mt19937 rng_type; + typedef boost::variate_generator > variate_type; + + public: + + uniform_real_rng(const std::size_t& seed = magic_seed, + std::size_t pregen = 0) + : rng_(static_cast(seed)), + rnd_(rng_,boost::uniform_real(0.0,1.0)) + { + while (pregen--) rng_(); + } + + inline double operator()() + { + return rnd_(); + } + + private: + + rng_type rng_; + variate_type rnd_; + }; + + template + inline void generate_random_values(const std::size_t& count, + const T& min, + const T& max, + OutputIterator out, + const std::size_t& seed = magic_seed, + const std::size_t& pregen = 0) + { + typename details::supported_random_type::type type; + boost::mt19937 rng(static_cast(seed)); + for (std::size_t i = 0; i++ < pregen; rng()) ; + generate_random_values_impl(count,min,max,out,rng,type); + } + + template class Sequence> + inline void generate_random_values(const std::size_t& count, + const T& min, + const T& max, + Sequence& sequence, + const std::size_t& seed = magic_seed, + const std::size_t& pregen = 0) + { + typename details::supported_random_type::type type; + boost::mt19937 rng(static_cast(seed)); + for (std::size_t i = 0; i++ < pregen; rng()) ; + generate_random_values_impl(count,min,max,std::back_inserter(sequence),rng,type); + } + + template + inline void random_permutation(const Iterator begin, const Iterator end, + RandomNumberGenerator& rng, + OutputIterator out) + { + const std::size_t size = std::distance(begin,end); + if ((rng. min() < 0.0) || (rng.max() > 1.0)) return; + std::deque index; + for (std::size_t i = 0; i < size; index.push_back(i++)) ; + while (!index.empty()) + { + std::size_t idx = static_cast(index.size() * rng()); + (*out) = *(begin + index[idx]); + index.erase(index.begin() + idx); + ++out; + } + } + + template + inline void random_permutation(const Iterator begin, const Iterator end, + OutputIterator out, + const std::size_t& seed = magic_seed, + const std::size_t& pregen = 0) + { + boost::mt19937 rng(static_cast(seed)); + for (std::size_t i = 0; i++ < pregen; rng()) ; + boost::uniform_real dist(0.0,1.0); + boost::variate_generator > rnd(rng,dist); + random_permutation(begin,end,rnd,out); + } + + template class Sequence, + typename OutputIterator> + inline void random_permutation(const Sequence& sequence, + OutputIterator out, + const std::size_t& seed = magic_seed, + const std::size_t& pregen = 0) + { + random_permutation(sequence.begin(),sequence.end(),out,seed,pregen); + } + + template + inline bool random_combination(const Iterator begin, const Iterator end, + std::size_t set_size, + RandomNumberGenerator& rng, + OutputIterator out) + { + const std::size_t size = std::distance(begin,end); + if ((size < set_size) || (rng. min() < 0.0) || (rng.max() > 1.0)) return false; + std::deque index; + for (std::size_t i = 0; i < size; index.push_back(i++)) ; + while (set_size) + { + std::size_t idx = static_cast(index.size() * rng()); + (*out) = *(begin + index[idx]); + index.erase(index.begin() + idx); + ++out; + --set_size; + } + return true; + } + + template + inline void random_combination(const Iterator begin, const Iterator end, + const std::size_t& set_size, + OutputIterator out, + const std::size_t& seed = magic_seed, + const std::size_t& pregen = 0) + { + boost::mt19937 rng(static_cast(seed)); + for (std::size_t i = 0; i++ < pregen; rng()) ; + boost::uniform_real dist(0.0,1.0); + boost::variate_generator > rnd(rng,dist); + random_combination(begin,end,set_size,rnd,out); + } + + template class Sequence, + typename OutputIterator> + inline void random_combination(const Sequence& sequence, + const std::size_t& set_size, + OutputIterator out, + const std::size_t& seed = magic_seed, + const std::size_t& pregen = 0) + { + random_combination(sequence.begin(),sequence.end(),set_size,out,seed,pregen); + } + + template + inline std::size_t select_k_randomly(const Iterator begin, const Iterator end, + const std::size_t k, + OutputIterator out, + RandomNumberGenerator& rng) + { + typedef typename std::iterator_traits::value_type T; + std::vector selection; + selection.resize(k); + Iterator itr = begin; + std::size_t index = 0; + while ((index < k) && (end != itr)) + { + selection[index] = (*itr); + ++index; + ++itr; + } + if (0 == index) + return 0; + else if (index < k) + { + std::copy(selection.begin(),selection.begin() + index, out); + return index; + } + double n = k + 1; + while (end != itr) + { + if (rng() < (k / n)) + { + selection[static_cast(rng() * k)] = (*itr); + } + ++itr; + ++n; + } + std::copy(selection.begin(),selection.end(),out); + return k; + } + + template + inline void select_1_randomly(const Iterator begin, const Iterator end, + OutputIterator out, + RandomNumberGenerator& rng) + { + typedef typename std::iterator_traits::value_type T; + T selection; + if (begin == end) + return; + Iterator itr = begin; + std::size_t n = 0; + while (end != itr) + { + if (rng() < (1.0 / ++n)) + { + selection = (*itr); + } + ++itr; + } + (*out) = selection; + ++out; + } + #endif // strtk_enable_random + + template + inline bool next_combination(const Iterator first, Iterator k, const Iterator last) + { + /* Credits: Thomas Draper */ + if ((first == last) || (first == k) || (last == k)) + return false; + Iterator itr1 = first; + Iterator itr2 = last; + ++itr1; + if (last == itr1) + return false; + itr1 = last; + --itr1; + itr1 = k; + --itr2; + while (first != itr1) + { + if (*--itr1 < (*itr2)) + { + Iterator j = k; + while (!((*itr1) < (*j))) ++j; + std::iter_swap(itr1,j); + ++itr1; + ++j; + itr2 = k; + std::rotate(itr1,j,last); + while (last != j) + { + ++j; + ++itr2; + } + std::rotate(k,itr2,last); + return true; + } + } + std::rotate(first,k,last); + return false; + } + + template class Sequence> + inline bool next_combination(Sequence& sequence, const std::size_t& size) + { + return next_combination(sequence.begin(), sequence.begin() + size, sequence.end()); + } + + template + inline void for_each_permutation(Iterator begin, Iterator end, Function function) + { + do + { + function(begin,end); + } + while (std::next_permutation(begin,end)); + } + + template + inline bool for_each_permutation_conditional(Iterator begin, Iterator end, Function function) + { + do + { + if (!function(begin,end)) + return false; + } + while (std::next_permutation(begin,end)); + return true; + } + + namespace details + { + /* + Credits: + (C) Copyright Howard Hinnant 2005-2011. + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). + */ + template + static inline void rotate_discontinuous(Iterator first1, Iterator last1, + typename std::iterator_traits::difference_type d1, + Iterator first2, Iterator last2, + typename std::iterator_traits::difference_type d2) + { + using std::swap; + if (d1 <= d2) + std::rotate(first2, std::swap_ranges(first1, last1, first2), last2); + else + { + Iterator i1 = last1; + while (first2 != last2) + { + swap(*--i1,*--last2); + } + std::rotate(first1, i1, last1); + } + } + + template + inline void combine_discontinuous(Iterator first1, Iterator last1, typename std::iterator_traits::difference_type d1, + Iterator first2, Iterator last2, typename std::iterator_traits::difference_type d2, + Function& f, + typename std::iterator_traits::difference_type d = 0) + { + typedef typename std::iterator_traits::difference_type D; + using std::swap; + if ((0 == d1) || (0 == d2)) + return f(); + if (1 == d1) + { + Iterator i2 = first2; + while (i2 != last2) + { + f(); + swap(*first1, *i2); + ++i2; + } + } + else + { + Iterator f1p = first1; + std::advance(f1p,1); + Iterator i2 = first2; + D d22 = d2; + while (i2 != last2) + { + combine_discontinuous(f1p, last1, d1 - 1, i2, last2, d22, f, d + 1); + swap(*first1, *i2); + ++i2; + --d22; + } + } + f(); + if (0 != d) + { + Iterator f2p = first2; + std::advance(f2p,1); + rotate_discontinuous(first1, last1, d1, f2p, last2, d2 - 1); + } + else + rotate_discontinuous(first1, last1, d1, first2, last2, d2); + } + + template + inline bool combine_discontinuous_conditional(Iterator first1, Iterator last1, typename std::iterator_traits::difference_type d1, + Iterator first2, Iterator last2, typename std::iterator_traits::difference_type d2, + Function& f, + typename std::iterator_traits::difference_type d = 0) + { + typedef typename std::iterator_traits::difference_type D; + using std::swap; + if (d1 == 0 || d2 == 0) + return f(); + if (d1 == 1) + { + for (Iterator i2 = first2; i2 != last2; ++i2) + { + if (!f()) + return false; + swap(*first1, *i2); + } + } + else + { + Iterator f1p = first1; + std::advance(f1p,1); + Iterator i2 = first2; + for (D d22 = d2; i2 != last2; ++i2, --d22) + { + if (!combine_discontinuous_conditional(f1p, last1, d1-1, i2, last2, d22, f, d + 1)) + return false; + swap(*first1, *i2); + } + } + if (!f()) + return false; + if (d != 0) + { + Iterator f2p = first2; + std::advance(f2p,1); + rotate_discontinuous(first1, last1, d1, f2p, last2, d2 - 1); + } + else + rotate_discontinuous(first1, last1, d1, first2, last2, d2); + return true; + } + + template + class bound_range + { + public: + + bound_range(Function f, Iterator first, Iterator last) + : f_(f), + first_(first), + last_(last) + {} + + inline void operator()() + { + f_(first_,last_); + } + + private: + + inline bound_range& operator=(const bound_range&); + + Function f_; + Iterator first_; + Iterator last_; + }; + + template + class bound_range_conditional + { + public: + + bound_range_conditional(Function f, Iterator first, Iterator last) + : f_(f), + first_(first), + last_(last) + {} + + inline bool operator()() + { + return f_(first_,last_); + } + + private: + + inline bound_range_conditional& operator=(const bound_range_conditional&); + + Function f_; + Iterator first_; + Iterator last_; + }; + + } + + template + inline void for_each_combination(Iterator begin, Iterator end, + const std::size_t& size, + Function function) + { + if (static_cast::difference_type>(size) > std::distance(begin,end)) + return; + Iterator mid = begin + size; + details::bound_range func(function,begin,mid); + details::combine_discontinuous(begin, mid, + std::distance(begin,mid), + mid, end, + std::distance(mid,end), + func); + } + + template + inline void for_each_combination_conditional(Iterator begin, Iterator end, + const std::size_t& size, + Function function) + { + if (static_cast::difference_type>(size) > std::distance(begin,end)) + return; + Iterator mid = begin + size; + details::bound_range_conditional func(function,begin,mid); + details::combine_discontinuous_conditional(begin, mid, + std::distance(begin,mid), + mid, end, + std::distance(mid,end), + func); + } + + inline unsigned long long int n_choose_k(const unsigned long long int& n, const unsigned long long int& k) + { + if (n < k) return 0; + if (0 == n) return 0; + if (0 == k) return 1; + if (n == k) return 1; + if (1 == k) return n; + + typedef unsigned long long int value_type; + + class n_choose_k_impl + { + public: + + n_choose_k_impl(value_type* table, const value_type& dimension) + : table_(table), + dimension_(dimension / 2) + {} + + inline value_type& lookup(const value_type& n, const value_type& k) + { + const std::size_t difference = static_cast(n - k); + return table_[static_cast((dimension_ * n) + std::min(k,difference))]; + } + + inline value_type compute(const value_type& n, const value_type& k) + { + // n-Choose-k = (n-1)-Choose-(k-1) + (n-1)-Choose-k + if ((0 == k) || (k == n)) + return 1; + value_type v1 = lookup(n - 1,k - 1); + if (0 == v1) + v1 = lookup(n - 1,k - 1) = compute(n - 1,k - 1); + value_type v2 = lookup(n - 1,k); + if (0 == v2) + v2 = lookup(n - 1,k) = compute(n - 1,k); + return v1 + v2; + } + + value_type* table_; + const value_type dimension_; + + private: + + inline n_choose_k_impl& operator=(const n_choose_k_impl&) + { + return *this; + } + }; + + static const std::size_t static_table_dim = 100; + static const std::size_t static_table_size = static_cast((static_table_dim * static_table_dim) / 2); + static value_type static_table[static_table_size]; + static bool static_table_initialized = false; + + if (!static_table_initialized && (n <= static_table_dim)) + { + std::fill_n(static_table,static_table_size,0); + static_table_initialized = true; + } + + const std::size_t table_size = static_cast(n * (n / 2) + (n & 1)); + + unsigned long long int dimension = static_table_dim; + value_type* table = 0; + + if (table_size <= static_table_size) + table = static_table; + else + { + dimension = n; + table = new value_type[table_size]; + std::fill_n(table,table_size,0ULL); + } + + value_type result = n_choose_k_impl(table,dimension).compute(n,k); + + if (table != static_table) + delete [] table; + + return result; + } + + inline void initialize_n_choose_k() + { + const unsigned long long int max_n = 100ULL; + for (unsigned long long int n = 0; n < max_n; ++n) + { + for (unsigned long long int k = 0; k < max_n; ++k) + { + n_choose_k(n,k); + } + } + } + + template + inline void nth_combination_sequence(unsigned long long int n, + const std::size_t& r, + const std::size_t& k, + OutputIterator out, + const bool complete_index = true) + { + //Compute the indicies for the n'th combination of r-choose-k + //n must be in the range [0,r-choose-k) + typedef unsigned long long int value_type; + + std::vector index_list(k,0); + value_type j = 0; + value_type x = 0; + ++n; + + for (std::size_t i = 1; i <= (k - 1); ++i) + { + index_list[i - 1] = 0; + if (1 < i) + { + index_list[i - 1] = index_list[i - 2]; + } + + do + { + index_list[i - 1] += 1; + j = n_choose_k(r - index_list[i - 1], k - i); + x += j; + } + while (n > x); + x -= j; + } + + index_list[k - 1] = index_list[k - 2] + static_cast(n) - static_cast(x); + for (std::size_t i = 0; i < index_list.size(); --index_list[i++]); + + std::copy(index_list.begin(),index_list.end(),out); + + if (complete_index) + { + std::vector exist_table(r,0); + + for (std::size_t i = 0; i < index_list.size(); ++i) + { + exist_table[index_list[i]] = 1; + } + + for (std::size_t i = 0; i < exist_table.size(); ++i) + { + if (0 == exist_table[i]) + { + (*out) = i; + ++out; + } + } + } + } + + template + inline void nth_combination_sequence(const std::size_t& n, + const std::size_t& k, + const InputIterator begin, + const InputIterator end, + OutputIterator out, + const bool complete_index = true) + { + const std::size_t length = std::distance(begin,end); + std::vector index_list; + nth_combination_sequence(n,length,k,std::back_inserter(index_list),complete_index); + for (std::size_t i = 0; i < index_list.size(); ++i) + { + (*out) = *(begin + index_list[i]); + ++out; + } + } + + template + inline void nth_permutation_sequence(std::size_t n, const std::size_t k, OutputIterator out) + { + //Note: n in [0,k!) + std::vector factorid (k,0); + std::vector permutate(k,0); + + factorid[0] = 1; + for (std::size_t i = 1; i < k; ++i) + { + factorid[i] = factorid[i - 1] * i; + } + + for (std::size_t i = 0; i < k; ++i) + { + permutate[i] = n / factorid[k - i - 1]; + n = n % factorid[k - i - 1]; + } + + for (std::size_t i = k - 1; i > 0; --i) + { + for (int j = static_cast(i - 1); j >= 0; --j) + { + if (permutate[j] <= permutate[i]) + { + ++permutate[i]; + } + } + } + + for (std::size_t i = 0; i < k; ++i) + { + *(out++) = permutate[i]; + } + } + + template + inline void nth_permutation_sequence(std::size_t n, + const InputIterator begin, + const InputIterator end, + OutputIterator out) + { + const std::size_t size = std::distance(begin,end); + std::vector index_list(size,0); + nth_permutation_sequence(n,size,index_list.begin()); + for (std::size_t i = 0; i < size; ++i) + { + *(out++) = (begin + index_list[i]); + } + } + + inline std::string nth_permutation_sequence(const std::size_t& n, const std::string& s) + { + std::vector index_list(s.size(),0); + nth_permutation_sequence(n,s.size(),index_list.begin()); + std::string result; + result.reserve(s.size()); + for (std::size_t i = 0; i < index_list.size(); ++i) + { + result += s[index_list[i]]; + } + return result; + } + + template + class combination_iterator : public std::iterator, + void, + void> + { + public: + + typedef Iterator iterator; + typedef const iterator const_iterator; + typedef std::pair range_type; + + explicit inline combination_iterator(const std::size_t& k, + iterator begin, iterator end, + const bool sorted = true) + : begin_(begin), + end_(end), + middle_(begin + k), + current_combination_(begin_,middle_) + { + if (!sorted) + { + std::sort(begin,end); + } + } + + template class Sequence> + explicit inline combination_iterator(const std::size_t& k, + Sequence& seq, + const bool sorted = true) + : begin_(seq.begin()), + end_(seq.end()), + middle_(begin_ + k), + current_combination_(begin_,middle_) + { + if (!sorted) + { + std::sort(begin_,end_); + } + } + + explicit inline combination_iterator(const std::size_t& k, + std::string& str, + const bool sorted = true) + : begin_(const_cast(str.data())), + end_(const_cast(str.data() + str.size())), + middle_(begin_ + k), + current_combination_(begin_,middle_) + { + if (!sorted) + { + std::sort(begin_,end_); + } + } + + inline combination_iterator(iterator end) + : begin_(end), + end_(end), + middle_(end), + current_combination_(end,end) + {} + + inline combination_iterator(const std::string& str) + : begin_(const_cast(str.data() + str.size())), + end_(begin_), + middle_(end_), + current_combination_(end_,end_) + {} + + template class Sequence> + explicit inline combination_iterator(Sequence& seq) + : begin_(seq.end()), + end_(seq.end()), + middle_(end_), + current_combination_(end_,end_) + {} + + inline combination_iterator& operator++() + { + if (begin_ != end_) + { + if (!next_combination(begin_,middle_,end_)) + { + begin_ = middle_ = end_; + } + } + return (*this); + } + + inline combination_iterator operator++(int) + { + combination_iterator tmp = *this; + this->operator++(); + return tmp; + } + + inline combination_iterator& operator+=(const int inc) + { + if (inc > 0) + { + for (int i = 0; i < inc; ++i, ++(*this)) ; + } + return (*this); + } + + inline range_type operator*() const + { + return current_combination_; + } + + inline bool operator==(const combination_iterator& itr) const + { + return (begin_ == itr.begin_ ) && + (end_ == itr.end_ ) && + (middle_ == itr.middle_); + } + + inline bool operator!=(const combination_iterator& itr) const + { + return !operator==(itr); + } + + protected: + + iterator begin_; + iterator end_; + iterator middle_; + range_type current_combination_; + }; + + namespace fast + { + /* + Note: The following routines perform no sanity checks at all + upon the input data. Hence they should only be used with + data that is known to be completely 'valid'. + */ + namespace details + { + + template + struct all_digits_check_impl + { + static inline bool process(Iterator) + { + throw std::runtime_error("all_digits_check_impl - unsupported value for N."); + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + all_digits_check_impl::process(itr + 1); + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + all_digits_check_impl::process(itr + 1); + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + all_digits_check_impl::process(itr + 1); + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10 && + static_cast(itr[ 2] - '0') < 10 && + static_cast(itr[ 3] - '0') < 10 && + static_cast(itr[ 4] - '0') < 10 && + static_cast(itr[ 5] - '0') < 10 && + static_cast(itr[ 6] - '0') < 10 && + static_cast(itr[ 7] - '0') < 10 && + static_cast(itr[ 8] - '0') < 10 && + static_cast(itr[ 9] - '0') < 10 && + static_cast(itr[10] - '0') < 10 && + static_cast(itr[11] - '0') < 10 && + static_cast(itr[12] - '0') < 10 && + static_cast(itr[13] - '0') < 10 && + static_cast(itr[14] - '0') < 10 && + static_cast(itr[15] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10 && + static_cast(itr[ 2] - '0') < 10 && + static_cast(itr[ 3] - '0') < 10 && + static_cast(itr[ 4] - '0') < 10 && + static_cast(itr[ 5] - '0') < 10 && + static_cast(itr[ 6] - '0') < 10 && + static_cast(itr[ 7] - '0') < 10 && + static_cast(itr[ 8] - '0') < 10 && + static_cast(itr[ 9] - '0') < 10 && + static_cast(itr[10] - '0') < 10 && + static_cast(itr[11] - '0') < 10 && + static_cast(itr[12] - '0') < 10 && + static_cast(itr[13] - '0') < 10 && + static_cast(itr[14] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10 && + static_cast(itr[ 2] - '0') < 10 && + static_cast(itr[ 3] - '0') < 10 && + static_cast(itr[ 4] - '0') < 10 && + static_cast(itr[ 5] - '0') < 10 && + static_cast(itr[ 6] - '0') < 10 && + static_cast(itr[ 7] - '0') < 10 && + static_cast(itr[ 8] - '0') < 10 && + static_cast(itr[ 9] - '0') < 10 && + static_cast(itr[10] - '0') < 10 && + static_cast(itr[11] - '0') < 10 && + static_cast(itr[12] - '0') < 10 && + static_cast(itr[13] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10 && + static_cast(itr[ 2] - '0') < 10 && + static_cast(itr[ 3] - '0') < 10 && + static_cast(itr[ 4] - '0') < 10 && + static_cast(itr[ 5] - '0') < 10 && + static_cast(itr[ 6] - '0') < 10 && + static_cast(itr[ 7] - '0') < 10 && + static_cast(itr[ 8] - '0') < 10 && + static_cast(itr[ 9] - '0') < 10 && + static_cast(itr[10] - '0') < 10 && + static_cast(itr[11] - '0') < 10 && + static_cast(itr[12] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10 && + static_cast(itr[ 2] - '0') < 10 && + static_cast(itr[ 3] - '0') < 10 && + static_cast(itr[ 4] - '0') < 10 && + static_cast(itr[ 5] - '0') < 10 && + static_cast(itr[ 6] - '0') < 10 && + static_cast(itr[ 7] - '0') < 10 && + static_cast(itr[ 8] - '0') < 10 && + static_cast(itr[ 9] - '0') < 10 && + static_cast(itr[10] - '0') < 10 && + static_cast(itr[11] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10 && + static_cast(itr[ 2] - '0') < 10 && + static_cast(itr[ 3] - '0') < 10 && + static_cast(itr[ 4] - '0') < 10 && + static_cast(itr[ 5] - '0') < 10 && + static_cast(itr[ 6] - '0') < 10 && + static_cast(itr[ 7] - '0') < 10 && + static_cast(itr[ 8] - '0') < 10 && + static_cast(itr[ 9] - '0') < 10 && + static_cast(itr[10] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10 && + static_cast(itr[4] - '0') < 10 && + static_cast(itr[5] - '0') < 10 && + static_cast(itr[6] - '0') < 10 && + static_cast(itr[7] - '0') < 10 && + static_cast(itr[8] - '0') < 10 && + static_cast(itr[9] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10 && + static_cast(itr[4] - '0') < 10 && + static_cast(itr[5] - '0') < 10 && + static_cast(itr[6] - '0') < 10 && + static_cast(itr[7] - '0') < 10 && + static_cast(itr[8] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10 && + static_cast(itr[4] - '0') < 10 && + static_cast(itr[5] - '0') < 10 && + static_cast(itr[6] - '0') < 10 && + static_cast(itr[7] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10 && + static_cast(itr[4] - '0') < 10 && + static_cast(itr[5] - '0') < 10 && + static_cast(itr[6] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10 && + static_cast(itr[4] - '0') < 10 && + static_cast(itr[5] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10 && + static_cast(itr[4] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10 && + static_cast(itr[3] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return + static_cast(itr[0] - '0') < 10 && + static_cast(itr[1] - '0') < 10 && + static_cast(itr[2] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10 && + static_cast(itr[ 1] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator itr) + { + return static_cast(itr[ 0] - '0') < 10; + } + }; + + template + struct all_digits_check_impl + { + static inline bool process(Iterator) + { + return false; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator, T&) + { throw std::runtime_error("numeric_convert_impl::process( - unsupported value for N."); } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + strtk::fast::details::numeric_convert_impl::process(itr + 1,t); + t += static_cast((itr[0] - '0') * 1000000000000000000LL); + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + strtk::fast::details::numeric_convert_impl::process(itr + 1,t); + t += static_cast((itr[0] - '0') * 100000000000000000LL); + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + numeric_convert_impl::process(itr + 1,t); + t += static_cast((itr[0] - '0') * 10000000000000000LL); + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[ 0] - '0') * 1000000000000000LL); + x += static_cast((itr[ 1] - '0') * 100000000000000LL); + x += static_cast((itr[ 2] - '0') * 10000000000000LL); + x += static_cast((itr[ 3] - '0') * 1000000000000LL); + x += static_cast((itr[ 4] - '0') * 100000000000LL); + x += static_cast((itr[ 5] - '0') * 10000000000LL); + x += static_cast((itr[ 6] - '0') * 1000000000LL); + x += static_cast((itr[ 7] - '0') * 100000000LL); + x += static_cast((itr[ 8] - '0') * 10000000LL); + x += static_cast((itr[ 9] - '0') * 1000000LL); + x += static_cast((itr[10] - '0') * 100000LL); + x += static_cast((itr[11] - '0') * 10000LL); + x += static_cast((itr[12] - '0') * 1000LL); + x += static_cast((itr[13] - '0') * 100LL); + x += static_cast((itr[14] - '0') * 10LL); + x += static_cast((itr[15] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[ 0] - '0') * 100000000000000LL); + x += static_cast((itr[ 1] - '0') * 10000000000000LL); + x += static_cast((itr[ 2] - '0') * 1000000000000LL); + x += static_cast((itr[ 3] - '0') * 100000000000LL); + x += static_cast((itr[ 4] - '0') * 10000000000LL); + x += static_cast((itr[ 5] - '0') * 1000000000LL); + x += static_cast((itr[ 6] - '0') * 100000000LL); + x += static_cast((itr[ 7] - '0') * 10000000LL); + x += static_cast((itr[ 8] - '0') * 1000000LL); + x += static_cast((itr[ 9] - '0') * 100000LL); + x += static_cast((itr[10] - '0') * 10000LL); + x += static_cast((itr[11] - '0') * 1000LL); + x += static_cast((itr[12] - '0') * 100LL); + x += static_cast((itr[13] - '0') * 10LL); + x += static_cast((itr[14] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[ 0] - '0') * 10000000000000LL); + x += static_cast((itr[ 1] - '0') * 1000000000000LL); + x += static_cast((itr[ 2] - '0') * 100000000000LL); + x += static_cast((itr[ 3] - '0') * 10000000000LL); + x += static_cast((itr[ 4] - '0') * 1000000000LL); + x += static_cast((itr[ 5] - '0') * 100000000LL); + x += static_cast((itr[ 6] - '0') * 10000000LL); + x += static_cast((itr[ 7] - '0') * 1000000LL); + x += static_cast((itr[ 8] - '0') * 100000LL); + x += static_cast((itr[ 9] - '0') * 10000LL); + x += static_cast((itr[10] - '0') * 1000LL); + x += static_cast((itr[11] - '0') * 100LL); + x += static_cast((itr[12] - '0') * 10LL); + x += static_cast((itr[13] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[ 0] - '0') * 1000000000000LL); + x += static_cast((itr[ 1] - '0') * 100000000000LL); + x += static_cast((itr[ 2] - '0') * 10000000000LL); + x += static_cast((itr[ 3] - '0') * 1000000000LL); + x += static_cast((itr[ 4] - '0') * 100000000LL); + x += static_cast((itr[ 5] - '0') * 10000000LL); + x += static_cast((itr[ 6] - '0') * 1000000LL); + x += static_cast((itr[ 7] - '0') * 100000LL); + x += static_cast((itr[ 8] - '0') * 10000LL); + x += static_cast((itr[ 9] - '0') * 1000LL); + x += static_cast((itr[10] - '0') * 100LL); + x += static_cast((itr[11] - '0') * 10LL); + x += static_cast((itr[12] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[ 0] - '0') * 100000000000LL); + x += static_cast((itr[ 1] - '0') * 10000000000LL); + x += static_cast((itr[ 2] - '0') * 1000000000LL); + x += static_cast((itr[ 3] - '0') * 100000000LL); + x += static_cast((itr[ 4] - '0') * 10000000LL); + x += static_cast((itr[ 5] - '0') * 1000000LL); + x += static_cast((itr[ 6] - '0') * 100000LL); + x += static_cast((itr[ 7] - '0') * 10000LL); + x += static_cast((itr[ 8] - '0') * 1000LL); + x += static_cast((itr[ 9] - '0') * 100LL); + x += static_cast((itr[10] - '0') * 10LL); + x += static_cast((itr[11] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[ 0] - '0') * 10000000000LL); + x += static_cast((itr[ 1] - '0') * 1000000000LL); + x += static_cast((itr[ 2] - '0') * 100000000LL); + x += static_cast((itr[ 3] - '0') * 10000000LL); + x += static_cast((itr[ 4] - '0') * 1000000LL); + x += static_cast((itr[ 5] - '0') * 100000LL); + x += static_cast((itr[ 6] - '0') * 10000LL); + x += static_cast((itr[ 7] - '0') * 1000LL); + x += static_cast((itr[ 8] - '0') * 100LL); + x += static_cast((itr[ 9] - '0') * 10LL); + x += static_cast((itr[10] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 1000000000); + x += static_cast((itr[1] - '0') * 100000000); + x += static_cast((itr[2] - '0') * 10000000); + x += static_cast((itr[3] - '0') * 1000000); + x += static_cast((itr[4] - '0') * 100000); + x += static_cast((itr[5] - '0') * 10000); + x += static_cast((itr[6] - '0') * 1000); + x += static_cast((itr[7] - '0') * 100); + x += static_cast((itr[8] - '0') * 10); + x += static_cast((itr[9] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 100000000); + x += static_cast((itr[1] - '0') * 10000000); + x += static_cast((itr[2] - '0') * 1000000); + x += static_cast((itr[3] - '0') * 100000); + x += static_cast((itr[4] - '0') * 10000); + x += static_cast((itr[5] - '0') * 1000); + x += static_cast((itr[6] - '0') * 100); + x += static_cast((itr[7] - '0') * 10); + x += static_cast((itr[8] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 10000000); + x += static_cast((itr[1] - '0') * 1000000); + x += static_cast((itr[2] - '0') * 100000); + x += static_cast((itr[3] - '0') * 10000); + x += static_cast((itr[4] - '0') * 1000); + x += static_cast((itr[5] - '0') * 100); + x += static_cast((itr[6] - '0') * 10); + x += static_cast((itr[7] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 1000000); + x += static_cast((itr[1] - '0') * 100000); + x += static_cast((itr[2] - '0') * 10000); + x += static_cast((itr[3] - '0') * 1000); + x += static_cast((itr[4] - '0') * 100); + x += static_cast((itr[5] - '0') * 10); + x += static_cast((itr[6] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 100000); + x += static_cast((itr[1] - '0') * 10000); + x += static_cast((itr[2] - '0') * 1000); + x += static_cast((itr[3] - '0') * 100); + x += static_cast((itr[4] - '0') * 10); + x += static_cast((itr[5] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 10000); + x += static_cast((itr[1] - '0') * 1000); + x += static_cast((itr[2] - '0') * 100); + x += static_cast((itr[3] - '0') * 10); + x += static_cast((itr[4] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 1000); + x += static_cast((itr[1] - '0') * 100); + x += static_cast((itr[2] - '0') * 10); + x += static_cast((itr[3] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 100); + x += static_cast((itr[1] - '0') * 10); + x += static_cast((itr[2] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + T x = static_cast((itr[0] - '0') * 10); + x += static_cast((itr[1] - '0') ); + t = x; + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator itr, T& t) + { + t = static_cast((itr[0] - '0')); + } + }; + + template + struct numeric_convert_impl + { + static inline void process(Iterator, T& t) + { + t = 0; + } + }; + + template + inline bool negate(T&, NoneSignedTag) + { + return false; + } + + template + inline bool negate(T& t, strtk::details::signed_type_tag) + { + t = -t; + return true; + } + + } // namespace details + + template + inline bool all_digits_check(Iterator itr) + { + typedef typename strtk::details::is_valid_iterator::type itr_type; + strtk::details::convert_type_assert(); + return details::all_digits_check_impl::process(itr); + } + + template + inline bool all_digits_check(const std::string& s) + { + return all_digits_check(s.data()); + } + + template + inline bool all_digits_check(const std::size_t& n, Iterator itr) + { + switch (n) + { + case 0 : return details::all_digits_check_impl::process(itr); + case 1 : return details::all_digits_check_impl::process(itr); + case 2 : return details::all_digits_check_impl::process(itr); + case 3 : return details::all_digits_check_impl::process(itr); + case 4 : return details::all_digits_check_impl::process(itr); + case 5 : return details::all_digits_check_impl::process(itr); + case 6 : return details::all_digits_check_impl::process(itr); + case 7 : return details::all_digits_check_impl::process(itr); + case 8 : return details::all_digits_check_impl::process(itr); + case 9 : return details::all_digits_check_impl::process(itr); + case 10 : return details::all_digits_check_impl::process(itr); + case 11 : return details::all_digits_check_impl::process(itr); + case 12 : return details::all_digits_check_impl::process(itr); + case 13 : return details::all_digits_check_impl::process(itr); + case 14 : return details::all_digits_check_impl::process(itr); + case 15 : return details::all_digits_check_impl::process(itr); + case 16 : return details::all_digits_check_impl::process(itr); + case 17 : return details::all_digits_check_impl::process(itr); + case 18 : return details::all_digits_check_impl::process(itr); + case 19 : return details::all_digits_check_impl::process(itr); + default : return false; + } + } + + template + inline bool all_digits_check(Iterator begin, Iterator end) + { + return all_digits_check(std::distance(begin,end),begin); + } + + inline bool all_digits_check(const std::string& s) + { + return all_digits_check(s.size(),s.data()); + } + + template + inline bool signed_all_digits_check(Iterator itr) + { + if (('-' == (*itr)) || ('+' == (*itr))) + return all_digits_check((itr + 1)); + else + return all_digits_check(itr); + } + + template + inline bool signed_all_digits_check(const std::size_t& n, Iterator itr) + { + if (('-' == (*itr)) || ('+' == (*itr))) + return all_digits_check(n - 1,(itr + 1)); + else + return all_digits_check(n,itr); + } + + template + inline bool signed_all_digits_check(const std::string& s) + { + return signed_all_digits_check(s.data()); + } + + template + inline bool signed_all_digits_check(Iterator begin, Iterator end) + { + return signed_all_digits_check(std::distance(begin,end),begin); + } + + inline bool signed_all_digits_check(const std::string& s) + { + return signed_all_digits_check(s.size(),s.data()); + } + + template + inline void numeric_convert(Iterator itr, T& t, const bool digit_check = false) + { + typedef typename strtk::details::is_valid_iterator::type itr_type; + strtk::details::convert_type_assert(); + if (digit_check) + { + if (!all_digits_check(itr)) + { + t = 0; + return; + } + } + + details::numeric_convert_impl::process(itr,t); + } + + template + inline void numeric_convert(const std::string& s, T& t, const bool digit_check = false) + { + numeric_convert(s.data(),t,digit_check); + } + + template + inline bool numeric_convert(const std::size_t& n, + Iterator itr, T& t, + const bool digit_check = false) + { + if (digit_check) + { + if (!all_digits_check(n,itr)) + { + return false; + } + } + + switch (n) + { + case 0 : details::numeric_convert_impl::process(itr,t); return true; + case 1 : details::numeric_convert_impl::process(itr,t); return true; + case 2 : details::numeric_convert_impl::process(itr,t); return true; + case 3 : details::numeric_convert_impl::process(itr,t); return true; + case 4 : details::numeric_convert_impl::process(itr,t); return true; + case 5 : details::numeric_convert_impl::process(itr,t); return true; + case 6 : details::numeric_convert_impl::process(itr,t); return true; + case 7 : details::numeric_convert_impl::process(itr,t); return true; + case 8 : details::numeric_convert_impl::process(itr,t); return true; + case 9 : details::numeric_convert_impl::process(itr,t); return true; + case 10 : details::numeric_convert_impl::process(itr,t); return true; + case 11 : details::numeric_convert_impl::process(itr,t); return true; + case 12 : details::numeric_convert_impl::process(itr,t); return true; + case 13 : details::numeric_convert_impl::process(itr,t); return true; + case 14 : details::numeric_convert_impl::process(itr,t); return true; + case 15 : details::numeric_convert_impl::process(itr,t); return true; + case 16 : details::numeric_convert_impl::process(itr,t); return true; + case 17 : details::numeric_convert_impl::process(itr,t); return true; + case 18 : details::numeric_convert_impl::process(itr,t); return true; + case 19 : details::numeric_convert_impl::process(itr,t); return true; + default : return false; + } + } + + template + inline void numeric_convert(const std::string& s, T& t, const bool digit_check = false) + { + numeric_convert(s.size(),s.data(),t,digit_check); + } + + template + inline void signed_numeric_convert(Iterator itr, T& t, const bool digit_check = false) + { + if ('-' == (*itr)) + { + numeric_convert((itr + 1),t,digit_check); + typename strtk::details::supported_conversion_to_type::type type; + details::negate(t,type); + } + else if ('+' == (*itr)) + { + numeric_convert((itr + 1),t,digit_check); + } + else + numeric_convert(itr,t,digit_check); + } + + template + inline bool signed_numeric_convert(const std::size_t& n, + Iterator itr, + T& t, + const bool digit_check = false) + { + if ('-' == (*itr)) + { + bool result = numeric_convert((n - 1),(itr + 1),t,digit_check); + typename strtk::details::supported_conversion_to_type::type type; + return details::negate(t,type) && result; + } + else if ('+' == (*itr)) + { + return numeric_convert((n - 1),(itr + 1),t,digit_check); + } + else + return numeric_convert(n,itr,t,digit_check); + } + + template + inline void signed_numeric_convert(const std::string& s, + T& t, + const bool digit_check = false) + { + signed_numeric_convert(s.data(),t,digit_check); + } + + template + inline bool signed_numeric_convert(const std::string& s, + T& t, + const bool digit_check = false) + { + return signed_numeric_convert(s.size(),s.data(),t,digit_check); + } + + } // namespace fast + + namespace binary + { + + namespace details + { + namespace details_endian + { + #if (defined(__LITTLE_ENDIAN__)) ||\ + (defined(WIN32)) ||\ + (defined(__MINGW32_VERSION)) ||\ + (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + static const bool __le_result = true; + static const bool __be_result = false; + #else + static const bool __le_result = false; + static const bool __be_result = true; + #endif + } + + static inline bool is_little_endian() + { + //Is the current architecture/platform little-endian? + return details_endian::__le_result; + } + + static inline bool is_big_endian() + { + return details_endian::__be_result; + } + + static inline unsigned short convert(const unsigned short v) + { + //static_assert(2 == sizeof(v),""); + return ((v >> 8) & 0x00FF) | ((v << 8) & 0xFFFF); + } + + static inline unsigned int convert(const unsigned int v) + { + //static_assert(4 == sizeof(v),""); + return ((v >> 24) & 0x000000FF) | ((v << 24) & 0x0000FF00) | + ((v << 8) & 0x00FF0000) | ((v >> 8) & 0xFF000000); + } + + static inline unsigned long long int convert(const unsigned long long int v) + { + //static_assert(8 == sizeof(v),""); + return ((v >> 56) & 0x00000000000000FFLL) | ((v << 56) & 0xFF00000000000000LL) | + ((v >> 40) & 0x000000000000FF00LL) | ((v << 40) & 0x00FF000000000000LL) | + ((v >> 24) & 0x0000000000FF0000LL) | ((v << 24) & 0x0000FF0000000000LL) | + ((v >> 8) & 0x00000000FF000000LL) | ((v << 8) & 0x000000FF00000000LL) ; + } + + static inline short convert(const short v) + { + return static_cast(convert(static_cast(v))); + } + + static inline int convert(const int v) + { + return static_cast(convert(static_cast(v))); + } + + static inline long long int convert(const long long int v) + { + return static_cast(convert(static_cast(v))); + } + + static inline unsigned short convert_to_be(const unsigned short v) + { + return (is_little_endian()) ? convert(v) : v; + } + + static inline unsigned int convert_to_be(const unsigned int v) + { + return (is_little_endian()) ? convert(v) : v; + } + + static inline unsigned long long int convert_to_be(const unsigned long long int v) + { + return (is_little_endian()) ? convert(v) : v; + } + + static inline short convert_to_be(const short v) + { + return (is_little_endian()) ? convert(v) : v; + } + + static inline int convert_to_be(const int v) + { + return (is_little_endian()) ? convert(v) : v; + } + + static inline long long int convert_to_be(const long long int v) + { + return (is_little_endian()) ? convert(v) : v; + } + + static inline unsigned short convert_to_le(const unsigned short v) + { + return (is_big_endian()) ? convert(v) : v; + } + + static inline unsigned int convert_to_le(const unsigned int v) + { + return (is_big_endian()) ? convert(v) : v; + } + + static inline unsigned long long int convert_to_le(const unsigned long long int v) + { + return (is_big_endian()) ? convert(v) : v; + } + + static inline short convert_to_le(const short v) + { + return (is_big_endian()) ? convert(v) : v; + } + + static inline int convert_to_le(const int v) + { + return (is_big_endian()) ? convert(v) : v; + } + + static inline unsigned long long int convert_to_le(const long long int v) + { + return (is_big_endian()) ? convert(v) : v; + } + + class marker + { + private: + + typedef std::pair mark_type; + + public: + + inline bool reset(std::size_t& v1, char*& v2) + { + if (stack_.empty()) + return false; + v1 = stack_.top().first; + v2 = stack_.top().second; + stack_.pop(); + return true; + } + + inline void mark(const std::size_t& v1,char* v2) + { + stack_.push(std::make_pair(v1,v2)); + } + + private: + + std::stack stack_; + }; + + } + + class reader + { + public: + + // should be sourced from cstdint + typedef unsigned int uint32_t; + typedef unsigned short uint16_t; + typedef unsigned char uint8_t; + typedef unsigned long long int uint64_t; + + template + reader(T* buffer, + const std::size_t& buffer_length) + : original_buffer_(reinterpret_cast(buffer)), + buffer_(reinterpret_cast(buffer)), + buffer_length_(buffer_length * sizeof(T)), + amount_read_sofar_(0) + {} + + inline bool operator!() const + { + return (0 == buffer_length_) || + (0 == original_buffer_) || + (0 == buffer_); + } + + inline void reset(const bool clear_buffer = false) + { + amount_read_sofar_ = 0; + buffer_ = original_buffer_; + if (clear_buffer) + clear(); + } + + inline std::size_t position() const + { + return amount_read_sofar_; + } + + inline const char* position_ptr() const + { + return buffer_ ; + } + + inline std::size_t amount_read() + { + return amount_read_sofar_; + } + + inline bool rewind(const std::size_t& n_bytes) + { + if (n_bytes <= amount_read_sofar_) + { + amount_read_sofar_ -= n_bytes; + buffer_ -= n_bytes; + return true; + } + else + return false; + } + + inline bool seek(const int& n_bytes) + { + if (n_bytes < 0) + return rewind(-n_bytes); + else if (n_bytes > 0) + { + if ((amount_read_sofar_ + n_bytes) <= buffer_length_) + { + amount_read_sofar_ += n_bytes; + buffer_ += n_bytes; + return true; + } + else + return false; + } + else + return true; + } + + inline void clear() + { + reset(); + std::memset(buffer_,0x00,buffer_length_); + } + + template + inline bool operator()(T*& data, uint32_t& length, const bool read_length = true) + { + if (read_length && !operator()(length)) + return false; + + const std::size_t raw_size = length * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + if (read_length) + { + data = new T[length]; + } + std::copy(buffer_, buffer_ + raw_size, reinterpret_cast(data)); + buffer_ += raw_size; + amount_read_sofar_ += raw_size; + return true; + } + + template + inline bool operator()(T*& data, uint64_t& length, const bool read_length = true) + { + uint32_t l = 0; + if (read_length) + l = static_cast(length); + if (!operator()(data,l,read_length)) + return false; + if (read_length) + length = l; + return true; + } + + inline bool operator()(std::string& output) + { + uint32_t length = 0; + if (!operator()(length)) + return false; + + if (!buffer_capacity_ok(length)) + return false; + + output.resize(length); + std::copy(buffer_, + buffer_ + length, + const_cast(output.data())); + buffer_ += length; + amount_read_sofar_ += length; + return true; + } + + template + inline bool operator()(std::pair& p) + { + if (!operator()(p.first)) + return false; + if (!operator()(p.second)) + return false; + return true; + } + + template class Sequence> + inline bool operator()(Sequence& seq) + { + uint32_t size = 0; + if (!read_pod(size)) + return false; + + const std::size_t raw_size = size * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + T t = T(); + + for (std::size_t i = 0; i < size; ++i) + { + if (operator()(t)) + seq.push_back(t); + else + return false; + } + return true; + } + + template + inline bool operator()(std::vector& vec) + { + uint32_t size = 0; + if (!read_pod(size)) + return false; + const std::size_t raw_size = size * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + vec.resize(size); + return selector::type::batch_vector_read(*this,size,vec,false); + } + + template + inline bool operator()(std::set& set) + { + uint32_t size = 0; + if (!read_pod(size)) + return false; + + const std::size_t raw_size = size * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + T t; + for (std::size_t i = 0; i < size; ++i) + { + if (!operator()(t)) + return false; + set.insert(t); + } + + return true; + } + + template + inline bool operator()(std::multiset& multiset) + { + uint32_t size = 0; + if (!read_pod(size)) + return false; + + const std::size_t raw_size = size * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + T t; + for (std::size_t i = 0; i < size; ++i) + { + if (!operator()(t)) + return false; + multiset.insert(t); + } + + return true; + } + + inline bool operator()(std::ifstream& stream, const std::size_t& length) + { + if (length > buffer_length_) return false; + stream.read(original_buffer_,static_cast(length)); + return true; + } + + inline bool operator()(std::ifstream& stream) + { + if (0 == amount_read_sofar_) return false; + stream.read(original_buffer_,static_cast(amount_read_sofar_)); + return true; + } + + template + inline bool operator()(T& output) + { + return selector::type::run(*this,output); + } + + template + inline bool operator()(const T& output) + { + return selector::type::run(*this,const_cast(output)); + } + + template + inline bool be_to_native(T& output) + { + //From big-endian to native + if (details::is_little_endian()) + { + if (!operator()(output)) return false; + output = details::convert(output); + return true; + } + else + return operator()(output); + } + + template + inline bool le_to_native(T& output) + { + //From little-endian to native + if (details::is_little_endian()) + return operator()(output); + else + { + if (!operator()(output)) return false; + output = details::convert(output); + return true; + } + } + + template + inline bool operator()(T (&output)[N]) + { + const std::size_t raw_size = N * sizeof(T); + if (buffer_capacity_ok(raw_size)) + { + std::copy(buffer_, + buffer_ + raw_size, + reinterpret_cast(output)); + buffer_ += raw_size; + amount_read_sofar_ += raw_size; + return true; + } + else + return false; + } + + template + inline bool operator()(T& output, const std::size_t& size) + { + if (buffer_capacity_ok(size)) + { + bool result = strtk::string_to_type_converter(buffer_,buffer_ + size,output); + buffer_ += size; + amount_read_sofar_ += size; + return result; + } + else + return false; + } + + inline void mark() + { + marker_.mark(amount_read_sofar_,buffer_); + } + + inline bool reset_to_mark() + { + return marker_.reset(amount_read_sofar_,buffer_); + } + + private: + + reader(); + reader(const reader& s); + reader& operator=(const reader& s); + + inline bool buffer_capacity_ok(const std::size_t& required_read_qty) + { + return ((required_read_qty + amount_read_sofar_) <= buffer_length_); + } + + template + struct selector + { + private: + + template + struct selector_impl + { + template + static inline bool run(Reader& r, T& t) + { + return t(r); + } + + template + static inline bool batch_vector_read(Reader& r, + const std::size_t& size, + std::vector& v, + const bool) + { + T t; + for (std::size_t i = 0; i < size; ++i) + { + if (r.operator()(t)) + v[i] = t; + else + return false; + } + return true; + } + }; + + template + struct selector_impl + { + template + static inline bool run(Reader& r, + T& t, + const bool perform_buffer_capacity_check = true) + { + return r.read_pod(t,perform_buffer_capacity_check); + } + + template + static inline bool batch_vector_read(Reader& r, + const std::size_t& size, + std::vector& v, + const bool) + { + const std::size_t raw_size = sizeof(T) * size; + char* ptr = const_cast(reinterpret_cast(&v[0])); + std::copy(r.buffer_, r.buffer_ + raw_size, ptr); + r.buffer_ += raw_size; + r.amount_read_sofar_ += raw_size; + return true; + } + }; + + public: + + typedef selector_impl::result_t> type; + }; + + template + inline bool read_pod(T& data, const bool perform_buffer_capacity_check = true) + { + static const std::size_t data_length = sizeof(T); + if (perform_buffer_capacity_check) + { + if (!buffer_capacity_ok(data_length)) + return false; + } + data = (*reinterpret_cast(buffer_)); + buffer_ += data_length; + amount_read_sofar_ += data_length; + return true; + } + + char* const original_buffer_; + char* buffer_; + std::size_t buffer_length_; + std::size_t amount_read_sofar_; + details::marker marker_; + }; + + class writer + { + public: + + // should be sourced from cstdint + typedef unsigned int uint32_t; + typedef unsigned short uint16_t; + typedef unsigned char uint8_t; + typedef unsigned long long int uint64_t; + + template + writer(T* buffer, const std::size_t& buffer_length) + : original_buffer_(reinterpret_cast(buffer)), + buffer_(reinterpret_cast(buffer)), + buffer_length_(buffer_length * sizeof(T)), + amount_written_sofar_(0) + {} + + inline bool operator!() const + { + return (0 == buffer_length_) || + (0 == original_buffer_) || + (0 == buffer_); + } + + inline void reset(const bool clear_buffer = false) + { + amount_written_sofar_ = 0; + buffer_ = original_buffer_; + if (clear_buffer) + clear(); + } + + inline std::size_t position() const + { + return amount_written_sofar_; + } + + inline const char* position_ptr() const + { + return buffer_ ; + } + + inline std::size_t amount_written() const + { + return amount_written_sofar_; + } + + inline void clear() + { + reset(); + std::memset(buffer_,0x00,buffer_length_); + } + + template + inline bool operator()(const T (&data)[N], const bool write_length = false) + { + if (write_length && !operator()(N)) + return false; + + const std::size_t raw_size = N * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + const char* ptr = reinterpret_cast(data); + std::copy(ptr, ptr + raw_size, buffer_); + buffer_ += raw_size; + amount_written_sofar_ += raw_size; + return true; + } + + template + inline bool operator()(const T* data, const uint32_t& length, const bool write_length = true) + { + if (write_length && !operator()(length)) + return false; + + const std::size_t raw_size = length * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + const char* ptr = reinterpret_cast(data); + std::copy(ptr, ptr + raw_size, buffer_); + buffer_ += raw_size; + amount_written_sofar_ += raw_size; + return true; + } + + template + inline bool operator()(const T* data, const uint64_t& length, const bool write_length = true) + { + return operator()(data,static_cast(length),write_length); + } + + template + inline bool operator()(const T* data, const uint16_t& length, const bool write_length = true) + { + return operator()(data,static_cast(length),write_length); + } + + template + inline bool operator()(const T* data, const uint8_t& length, const bool write_length = true) + { + return operator()(data,static_cast(length),write_length); + } + + template + inline bool operator()(const std::pair& p) + { + if (!operator()(p.first)) + return false; + if (!operator()(p.second)) + return false; + return true; + } + + inline bool operator()(const std::string& input) + { + return operator()(input.data(),static_cast(input.size())); + } + + template class Sequence> + inline bool operator()(const Sequence& seq) + { + const uint32_t size = static_cast(seq.size()); + if (!operator()(size)) + return false; + + typename Sequence::const_iterator itr = seq.begin(); + typename Sequence::const_iterator end = seq.end(); + while (end != itr) + { + if (!operator()(*itr)) + return false; + ++itr; + } + return true; + } + + template + inline bool operator()(const std::vector& vec) + { + const uint32_t size = static_cast(vec.size()); + const std::size_t raw_size = (size * sizeof(T)); + if (!buffer_capacity_ok(raw_size + sizeof(size))) + return false; + if (!operator()(size)) + return false; + return selector::type::batch_vector_writer(*this,raw_size,vec); + } + + template + inline bool operator()(const std::set& set) + { + const uint32_t size = static_cast(set.size()); + if (!operator()(size)) + return false; + + const std::size_t raw_size = size * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + typename std::set::const_iterator itr = set.begin(); + typename std::set::const_iterator end = set.end(); + while (end != itr) + { + if (!operator()(*itr)) + return false; + ++itr; + } + return true; + } + + template + inline bool operator()(const std::multiset& multiset) + { + const uint32_t size = static_cast(multiset.size()); + if (!operator()(size)) + return false; + + const std::size_t raw_size = size * sizeof(T); + if (!buffer_capacity_ok(raw_size)) + return false; + + typename std::multiset::const_iterator itr = multiset.begin(); + typename std::multiset::const_iterator end = multiset.end(); + while (end != itr) + { + if (!operator()(*itr)) + return false; + ++itr; + } + return true; + } + + inline std::size_t operator()(std::ofstream& stream) + { + stream.write(original_buffer_,static_cast(amount_written_sofar_)); + return amount_written_sofar_; + } + + template + inline bool operator()(const T& input) + { + return selector::type::run(*this,input); + } + + template + inline bool native_to_be(const T& input) + { + //From native to big-endian + if (details::is_little_endian()) + { + return operator()(details::convert(input)); + } + else + return operator()(input); + } + + template + inline bool native_to_le(const T& input) + { + //From native to little-endian + if (details::is_little_endian()) + return operator()(input); + else + return operator()(details::convert(input)); + } + + enum padding_mode + { + right_padding = 0, + left_padding = 1 + }; + + template + inline bool operator()(const T& input, + const std::size_t& size, + const padding_mode pmode, + const char padding = ' ') + { + if (amount_written_sofar_ + size <= buffer_length_) + { + std::string s; + s.reserve(size); + if (!strtk::type_to_string(input,s)) + return false; + else if (s.size() > size) + return false; + else if (s.size() < size) + { + if (right_padding == pmode) + s.resize(size - s.size(),padding); + else + s = std::string(size - s.size(),padding) + s; + } + return operator()(s.data(),static_cast(size),false); + } + else + return false; + } + + inline void mark() + { + marker_.mark(amount_written_sofar_,buffer_); + } + + inline bool reset_to_mark() + { + return marker_.reset(amount_written_sofar_,buffer_); + } + + private: + + writer(); + writer(const writer& s); + writer& operator=(const writer& s); + + inline bool buffer_capacity_ok(const std::size_t& required_write_qty) + { + return ((required_write_qty + amount_written_sofar_) <= buffer_length_); + } + + template + struct selector + { + private: + + template + struct selector_impl + { + template + static inline bool run(Writer& w, const T& t) + { + return t(w); + } + + template + static inline bool batch_vector_writer(Writer& w, + const std::size_t&, + const std::vector& v) + { + for (std::size_t i = 0; i < v.size(); ++i) + { + if (w.operator()(v[i])) + continue; + else + return false; + } + return true; + } + }; + + template + struct selector_impl + { + template + static inline bool run(Writer& w, const T& t) + { + return w.write_pod(t); + } + + template + static inline bool batch_vector_writer(Writer& w, + const std::size_t& raw_size, + const std::vector& v) + { + const char* ptr = reinterpret_cast(&v[0]); + std::copy(ptr, ptr + raw_size, w.buffer_); + w.buffer_ += raw_size; + w.amount_written_sofar_ += raw_size; + return true; + } + }; + + public: + + typedef selector_impl::result_t> type; + }; + + template + inline bool write_pod(const T& data, const bool perform_buffer_capacity_check = true) + { + static const std::size_t data_length = sizeof(T); + if (perform_buffer_capacity_check) + { + if ((data_length + amount_written_sofar_) > buffer_length_) + { + return false; + } + } + *(reinterpret_cast(buffer_)) = data; + buffer_ += data_length; + amount_written_sofar_ += data_length; + return true; + } + + char* const original_buffer_; + char* buffer_; + std::size_t buffer_length_; + std::size_t amount_written_sofar_; + details::marker marker_; + }; + + #define strtk_binary_reader_begin() \ + bool operator()(strtk::binary::reader& reader)\ + { return true \ + + #define strtk_binary_reader(T) \ + && reader(T) \ + + #define strtk_binary_reader_end() \ + ;} \ + + #define strtk_binary_writer_begin() \ + bool operator()(strtk::binary::writer& writer) const\ + { return true \ + + #define strtk_binary_writer(T) \ + && writer(T) \ + + #define strtk_binary_writer_end() \ + ;} \ + + namespace details + { + template + class short_string_impl + { + public: + + short_string_impl() + : s(0) + {} + + short_string_impl(std::string& str) + : s(&str) + {} + + inline void clear() + { + s = 0; + } + + inline short_string_impl& set(std::string& str) + { + s = &str; + return *this; + } + + inline bool operator()(reader& r) + { + if (0 == s) + return false; + size_type size = 0; + if (!r(size)) + return false; + s->resize(size); + char* ptr = const_cast(s->data()); + strtk::binary::reader::uint32_t length = size; + if (!r(ptr,length,false)) + return false; + return true; + } + + inline bool operator()(writer& w) const + { + if (0 == s) + return false; + if (s->size() > std::numeric_limits::max()) + return false; + const size_type size = static_cast(s->size()); + if (!w(size)) + return false; + if (!w(s->data(),size, false)) + return false; + return true; + } + + private: + + short_string_impl& operator=(const short_string_impl&); + mutable std::string* s; + }; + } + + typedef details::short_string_impl short_string; + typedef details::short_string_impl pascal_string; + + } // namespace binary + + class ignore_token + { + public: + + template + inline ignore_token& operator=(const std::pair&) + { + return (*this); + } + + inline ignore_token& operator=(const std::string&) + { + return (*this); + } + }; + + template + class hex_to_number_sink + { + // static_assert for T either int or unsigned int and alike (could use a concept) + private: + + struct hex_value_check + { + inline bool operator()(const unsigned char c) const + { + return (('0' <= c) && (c <= '9')) || + (('A' <= c) && (c <= 'F')) || + (('a' <= c) && (c <= 'f')); + } + + inline bool operator()(const char c) const + { + return (*this)(static_cast(c)); + } + }; + + public: + + hex_to_number_sink(T& t) + : valid_(false), + t_(&t) + {} + + hex_to_number_sink(const hex_to_number_sink& hns) + : valid_(hns.valid), + t_(hns.t_) + {} + + inline hex_to_number_sink& operator=(const hex_to_number_sink& hns) + { + valid_ = hns.valid_; + t_ = hns.t_; + return (*this); + } + + template + inline hex_to_number_sink& operator=(const std::pair& s) + { + std::size_t offset = 0; + const std::size_t size = std::distance(s.first,s.second); + if ((size > 2) && ((*s.first) == '0') && (((*(s.first + 1)) == 'x') || ((*(s.first + 1)) == 'X'))) + offset = 2; + if ((size - offset) > (2 * sizeof(T))) + return (*this); + + const std::size_t buffer_size = 2 * sizeof(T); + const std::size_t buffer_offset = ((size - offset) % 2); + char buffer[buffer_size] = { '0' }; + if (!range_only_contains(hex_value_check(),s.first + offset,s.first + size)) + { + valid_ = false; + return (*this); + } + + std::copy(s.first + offset, s.first + size, buffer + buffer_offset); + (*t_) = 0; + valid_= convert_hex_to_bin(buffer, + buffer + (size - offset) + buffer_offset, + reinterpret_cast(t_)); + reverse_bytes(); + return (*this); + } + + inline hex_to_number_sink& operator=(const std::string& s) + { + return this->operator =(std::make_pair(s.data(),s.data() + s.size())); + } + + inline bool valid() const + { + return valid_; + } + + private: + + inline void reverse_bytes() + { + unsigned char* itr1 = reinterpret_cast(t_); + unsigned char* itr2 = itr1 + (sizeof(T) - 1); + while (itr1 < itr2) + { + std::swap(*itr1,*itr2); + ++itr1; + --itr2; + } + } + + private: + + bool valid_; + T* t_; + }; + + template + class base64_to_number_sink + { + // static_assert for T either int or unsigned int and alike (could use a concept) + private: + + struct base64_value_check + { + inline bool operator()(const unsigned char c) const + { + return (('0' <= c) && (c <= '9')) || + (('A' <= c) && (c <= 'Z')) || + (('a' <= c) && (c <= 'z')) || + ('+' == c) || + ('/' == c) || + ('=' == c); + } + + inline bool operator()(const char c) const + { + return (*this)(static_cast(c)); + } + }; + + public: + + base64_to_number_sink(T& t) + : valid_(false), + t_(&t) + {} + + base64_to_number_sink(const base64_to_number_sink& bns) + : valid_(bns.valid), + t_(bns.t_) + {} + + inline base64_to_number_sink& operator=(const base64_to_number_sink& bns) + { + valid_ = bns.valid_; + t_ = bns.t_; + return (*this); + } + + inline base64_to_number_sink& operator=(const std::string& s) + { + if (!range_only_contains(base64_value_check(),s.data(),s.data() + s.size())) + { + valid_ = false; + return (*this); + } + + (*t_) = T(0); + convert_base64_to_bin(s.data(), + s.data() + s.size(), + reinterpret_cast(t_)); + reverse_bytes(); + return (*this); + } + + template + inline base64_to_number_sink& operator=(const std::pair& s) + { + if (!range_only_contains(base64_value_check(),s.first,s.second)) + { + valid_ = false; + return (*this); + } + + (*t_) = T(0); + convert_base64_to_bin(s.first, s.second,reinterpret_cast(t_)); + reverse_bytes(); + return (*this); + } + + inline bool valid() const + { + return valid_; + } + + private: + + inline void reverse_bytes() + { + unsigned char* itr1 = reinterpret_cast(t_); + unsigned char* itr2 = itr1 + (sizeof(T) - 1); + while (itr1 < itr2) + { + std::swap(*itr1,*itr2); + ++itr1; + --itr2; + } + } + + private: + + bool valid_; + T* t_; + }; + + class hex_to_string_sink + { + public: + + hex_to_string_sink(std::string& s) + : valid_(false), + s_(s) + {} + + hex_to_string_sink(const hex_to_string_sink& hss) + : valid_(hss.valid_), + s_(hss.s_) + {} + + inline hex_to_string_sink& operator=(const hex_to_string_sink& hss) + { + valid_ = hss.valid_; + s_ = hss.s_; + return (*this); + } + + template + inline hex_to_string_sink& operator=(const std::pair& s) + { + const std::size_t size = std::distance(s.first,s.second); + std::size_t offset = 0; + if ((size > 2) && ((*s.first) == '0') && (((*(s.first + 1)) == 'x') || ((*(s.first + 1)) == 'X'))) + offset = 2; + if ((size - offset) < 2) + { + valid_ = false; + return (*this); + } + s_.resize((size - offset) / 2); + valid_ = convert_hex_to_bin(s.first + offset, + s.second, + const_cast(s_.data())); + return (*this); + } + + inline hex_to_string_sink& operator=(const std::string& s) + { + return this->operator=(std::make_pair(const_cast(s.data()), + const_cast(s.data() + s.size()))); + } + + inline bool valid() const + { + return valid_; + } + + private: + + bool valid_; + std::string& s_; + }; + + template + class truncated_int + { + public: + + truncated_int() + : t_(0), + fractional_size_(std::numeric_limits::max()) + {} + + truncated_int& fractional_size(const std::size_t& size) + { + fractional_size_ = size; + return *this; + } + + truncated_int& fractional_unknown_size() + { + fractional_size_ = std::numeric_limits::max(); + return *this; + } + + truncated_int& operator()(T& t) + { + t_ = &t; + return *this; + } + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + if (0 == t_) + return false; + + const std::size_t size = std::distance(begin,end); + + if (std::numeric_limits::max() != fractional_size_) + { + if (size < (fractional_size_ + 1)) + return false; + else + return strtk::string_to_type_converter(begin, begin + (size - (fractional_size_ + 1)),(*t_)); + } + + typedef typename std::iterator_traits::value_type value_type; + const value_type fullstop = value_type('.'); + InputIterator new_end = std::find(begin,end,fullstop); + return strtk::string_to_type_converter(begin,new_end,(*t_)); + } + + private: + + T* t_; + std::size_t fractional_size_; + }; + + namespace details + { + + template class Sequence> + inline std::size_t parse_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(begin,end,delimiters,sequence,split_option); + } + + template + inline std::size_t parse_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(begin,end,delimiters,set,split_option); + } + + template + inline std::size_t parse_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(begin,end,delimiters,multiset,split_option); + } + + template + inline std::size_t parse_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(begin,end,delimiters,queue,split_option); + } + + template + inline std::size_t parse_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(begin,end,delimiters,stack,split_option); + } + + template + inline std::size_t parse_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse(begin,end,delimiters,priority_queue,split_option); + } + + template class Sequence> + inline std::size_t parse_n_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + Sequence& sequence, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(begin,end,delimiters,n,sequence,split_option); + } + + template + inline std::size_t parse_n_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::set& set, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(begin,end,delimiters,n,set,split_option); + } + + template + inline std::size_t parse_n_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::multiset& multiset, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(begin,end,delimiters,n,multiset,split_option); + } + + template + inline std::size_t parse_n_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::queue& queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(begin,end,delimiters,n,queue,split_option); + } + + template + inline std::size_t parse_n_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::stack& stack, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(begin,end,delimiters,n,stack,split_option); + } + + template + inline std::size_t parse_n_stl_container_proxy(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const std::size_t& n, + std::priority_queue& priority_queue, + const split_options::type& split_option = split_options::compress_delimiters) + { + return parse_n(begin,end,delimiters,n,priority_queue,split_option); + } + + } // namespace details + + template + class sink_type + { + public: + + typedef typename Container::value_type value_type; + + inline sink_type(const std::string& delimiters, + const split_options::type& split_option = split_options::compress_delimiters) + : delimiters_(delimiters), + split_option_(split_option), + container_(0), + element_count_(std::numeric_limits::max()) + {} + + inline sink_type(Container& container, + const std::string& delimiters, + const split_options::type& split_option = split_options::compress_delimiters) + : delimiters_(delimiters), + split_option_(split_option), + container_(&container) + {} + + inline sink_type& count(const std::size_t& element_count = std::numeric_limits::max()) + { + element_count_ = element_count; + return (*this); + } + + inline sink_type& operator()(Container& container, + const std::string& delimiters = "", + const split_options::type& split_option = split_options::compress_delimiters) + { + container_ = (&container); + if (!delimiters.empty()) + delimiters_ = delimiters; + split_option_ = split_option; + return (*this); + } + + template + inline bool parse(InputIterator begin, InputIterator end) + { + if (container_) + { + if (std::numeric_limits::max() == element_count_) + return (details::parse_stl_container_proxy + (begin,end,delimiters_,(*container_),split_option_) > 0); + else + return (details::parse_n_stl_container_proxy + (begin,end,delimiters_,element_count_,(*container_),split_option_) == element_count_); + } + else + return false; + } + + sink_type& reference() + { + return *this; + } + + private: + + std::string delimiters_; + split_options::type split_option_; + Container* container_; + std::size_t element_count_; + }; + + template struct vector_sink { typedef sink_type > type; }; + template struct deque_sink { typedef sink_type > type; }; + template struct list_sink { typedef sink_type > type; }; + template struct set_sink { typedef sink_type > type; }; + template struct multiset_sink { typedef sink_type > type; }; + template struct queue_sink { typedef sink_type > type; }; + template struct stack_sink { typedef sink_type > type; }; + template struct priority_queue_sink { typedef sink_type > type; }; + + namespace text + { + inline std::string center(const std::size_t& width, + const std::string::value_type& pad, + const std::string& str) + { + if (str.size() >= width) return str; + const std::size_t pad_count = width - str.size(); + const std::size_t pad_count_2 = (pad_count >> 1) + (pad_count & 1); + return std::string(pad_count >> 1,pad) + str + std::string(pad_count_2,pad); + } + + inline std::string right_align(const std::size_t& width, + const std::string::value_type& pad, + const std::string& str) + { + if (str.size() >= width) return str; + return std::string(width - str.size(),pad) + str; + } + + inline std::string left_align(const std::size_t& width, + const std::string::value_type& pad, + const std::string& str) + { + if (str.size() >= width) return str; + return str + std::string(width - str.size(),pad); + } + + template + inline std::string center(const std::size_t& width, + const std::string::value_type& pad, + const T& t) + { + return center(width,pad,type_to_string(t)); + } + + template + inline std::string right_align(const std::size_t& width, + const std::string::value_type& pad, + const T& t) + { + return right_align(width,pad,type_to_string(t)); + } + + template + inline std::string left_align(const std::size_t& width, + const std::string::value_type& pad, + const T& t) + { + return left_align(width,pad,type_to_string(t)); + } + + template + inline std::string center(const std::size_t& width, const T& t) + { + return center(width,' ',type_to_string(t)); + } + + template + inline std::string right_align(const std::size_t& width, const T& t) + { + return right_align(width,' ',type_to_string(t)); + } + + template + inline std::string left_align(const std::size_t& width, const T& t) + { + return left_align(width,' ',type_to_string(t)); + } + + inline std::string remaining_string(const std::size_t& index, + const std::string& str) + { + return (index < str.size()) ? str.substr(index,str.size() - index) : str; + } + + inline void remaining_string(const std::size_t& index, + const std::string& str, + std::string& result) + { + result = (index < str.size()) ? str.substr(index,str.size() - index) : str; + } + + inline bool is_letter(const char c) + { + return (('A' <= c) && ( c <= 'Z')) || (('a' <= c) && ( c <= 'z')); + } + + inline bool is_lowercase_letter(const char c) + { + return (('a' <= c) && ( c <= 'z')); + } + + inline bool is_uppercase_letter(const char c) + { + return (('A' <= c) && ( c <= 'Z')); + } + + inline bool is_digit(const char c) + { + return (('0' <= c) && ( c <= '9')); + } + + inline bool is_hex_digit(const char c) + { + return (('0' <= c) && (c <= '9')) || + (('A' <= c) && (c <= 'F')) || + (('a' <= c) && (c <= 'f')); + } + + inline bool is_letter_or_digit(const char c) + { + return (is_letter(c) || is_digit(c)); + } + + inline bool is_all_letters(const std::string& s) + { + for (std::size_t i = 0; i < s.size(); ++i) + { + if (!is_letter(s[i])) + return false; + } + return true; + } + + inline bool is_all_digits(const std::string& s) + { + for (std::size_t i = 0; i < s.size(); ++i) + { + if (!is_digit(s[i])) + return false; + } + return true; + } + + inline void swap_inplace(std::string& s, const std::size_t& i0, const std::size_t& i1) + { + if (i0 >= s.size()) return; + if (i1 >= s.size()) return; + std::swap(s[i0],s[i1]); + } + + inline std::string swap(const std::string& s, const std::size_t& i0, const std::size_t& i1) + { + std::string result = s; + swap_inplace(result,i0,i1); + return result; + } + + inline void remove_inplace(std::string& s, const std::size_t& index) + { + if (index >= s.size()) + return; + std::memcpy(const_cast(s.data() + index), const_cast(s.data() + (index + 1)), s.size() - index); + s.resize(s.size() - 1); + } + + inline std::string remove(const std::string& s, const std::size_t& index) + { + std::string result = s; + remove_inplace(result,index); + return result; + } + + inline void insert_inplace(std::string& s, const std::size_t& index, const char c) + { + s.resize(s.size() + 1); + std::memcpy(const_cast(s.data() + index + 1), const_cast(s.data() + (index)), s.size() - index); + s[index] = c; + } + + inline std::string insert(const std::string& s, const std::size_t& index, const char c) + { + std::string result = s; + insert_inplace(result,index,c); + return result; + } + + } // namespace text + + namespace find_mode + { + enum type + { + exactly_n, + atleast_n + }; + } + + namespace find_type + { + enum type + { + digits, + letters, + lowercase_letters, + uppercase_letters, + letters_digits + }; + } + + namespace details + { + template + struct range_type + { + typedef typename std::pair type; + }; + + template + inline typename range_type::type find_exactly_n_consecutive_values(const std::size_t n, + Predicate p, + Iterator itr, + const Iterator end, + const bool stateful_predicate = false) + { + if (static_cast(std::distance(itr,end)) < n) + return typename range_type::type(end,end); + std::size_t count = n; + while (end != itr) + { + if (p(*itr)) + { + if (0 != --count) + ++itr; + else + { + std::advance(itr,1 - n); + return typename range_type::type(itr,itr + n); + } + } + else + { + ++itr; + while ((end != itr) && !p(*itr)) + ++itr; + if (!stateful_predicate) + count = n; + else + { + --count; + ++itr; + } + } + } + return typename range_type::type(end,end); + } + + template + inline typename range_type::type find_atleast_n_consecutive_values(const std::size_t n, + Predicate p, + Iterator itr, + const Iterator end) + { + if (static_cast(std::distance(itr,end)) < n) + return typename range_type::type(end,end); + std::size_t count = 0; + while (end != itr) + { + if (p(*itr)) + { + ++count; + ++itr; + } + else + { + if (count >= n) + { + std::advance(itr,-static_cast(count)); + return typename range_type::type(itr,itr + count); + } + while ((end != itr) && !p(*itr)) + ++itr; + count = 0; + } + } + if (count >= n) + { + std::advance(itr,-static_cast(count)); + return typename range_type::type(itr,itr + count); + } + else + return typename range_type::type(end,end); + } + + template + inline typename range_type::type find_exactly_n_consecutive_values(const std::size_t n, + Predicate p, + typename details::range_type::type range, + const bool stateful_predicate = false) + { + return find_exactly_n_consecutive_values(n,p,range.first,range.second,stateful_predicate); + } + + template + inline typename range_type::type find_atleast_n_consecutive_values(const std::size_t n, + Predicate p, + typename details::range_type::type range) + { + return find_atleast_n_consecutive_values(n,p,range.first,range.second); + } + + template + inline typename range_type::type find_n_consecutive_values(const std::size_t n, + find_mode::type mode, + Predicate p, + Iterator itr, + const Iterator end) + { + switch (mode) + { + case find_mode::exactly_n : return find_exactly_n_consecutive_values(n,p,itr,end); + case find_mode::atleast_n : return find_atleast_n_consecutive_values(n,p,itr,end); + default : return typename range_type::type(end,end); + } + } + + template + inline bool match_exactly_n_consecutive_values(const std::size_t n, + Predicate p, + Iterator itr, + const Iterator end) + { + if (static_cast(std::distance(itr,end)) < n) + return false; + std::size_t count = n; + while (end != itr) + { + if (p(*itr)) + { + if (0 == --count) + return true; + else + ++itr; + } + else + return false; + } + return false; + } + + template + inline bool match_atleast_n_consecutive_values(const std::size_t n, + Predicate p, + Iterator itr, + const Iterator end) + { + if (static_cast(std::distance(itr,end)) < n) + return false; + std::size_t count = 0; + while (end != itr) + { + if (p(*itr)) + { + ++count; + ++itr; + } + else if (count >= n) + return true; + else + return false; + } + return false; + } + + template + inline bool match_n_consecutive_values(const std::size_t n, + find_mode::type mode, + Predicate p, + Iterator itr, + const Iterator end) + { + switch (mode) + { + case find_mode::exactly_n : return match_exactly_n_consecutive_values(n,p,itr,end); + case find_mode::atleast_n : return match_atleast_n_consecutive_values(n,p,itr,end); + default : return false; + } + } + + } + + template + inline typename details::range_type::type find_n_consecutive(const std::size_t n, + find_type::type type, + find_mode::type mode, + typename details::range_type::type range) + { + switch (type) + { + case find_type::digits : return details::find_n_consecutive_values(n, + mode, + strtk::text::is_digit, + range.first,range.second); + + case find_type::letters : return details::find_n_consecutive_values(n, + mode, + strtk::text::is_letter, + range.first,range.second); + + case find_type::lowercase_letters : return details::find_n_consecutive_values(n, + mode, + strtk::text::is_lowercase_letter, + range.first,range.second); + + case find_type::uppercase_letters : return details::find_n_consecutive_values(n, + mode, + strtk::text::is_uppercase_letter, + range.first,range.second); + + case find_type::letters_digits : return details::find_n_consecutive_values(n, + mode, + strtk::text::is_letter_or_digit, + range.first,range.second); + + default : return typename details::range_type::type(range.second,range.second); + } + } + + template + inline bool match_n_consecutive(const std::size_t n, + find_type::type type, + find_mode::type mode, + typename details::range_type::type range) + { + switch (type) + { + case find_type::digits : return details::match_n_consecutive_values(n, + mode, + strtk::text::is_digit, + range.first,range.second); + + case find_type::letters : return details::match_n_consecutive_values(n, + mode, + strtk::text::is_letter, + range.first,range.second); + + case find_type::lowercase_letters : return details::match_n_consecutive_values(n, + mode, + strtk::text::is_lowercase_letter, + range.first,range.second); + + case find_type::uppercase_letters : return details::match_n_consecutive_values(n, + mode, + strtk::text::is_uppercase_letter, + range.first,range.second); + + case find_type::letters_digits : return details::match_n_consecutive_values(n, + mode, + strtk::text::is_letter_or_digit, + range.first,range.second); + + default : return false; + } + } + + template + inline std::size_t split_on_consecutive(const std::size_t n, + Predicate p, + char* begin, + char* end, + OutputIterator out, + const bool stateful_predicate = false) + { + if (0 == n) return 0; + typedef char* iterator_type; + typedef details::range_type::type range_type; + range_type itr_range(begin,end); + std::size_t match_count = 0; + while (end != itr_range.first) + { + range_type found_itr = + details::find_exactly_n_consecutive_values(n, + p, + itr_range, + stateful_predicate); + + if ((end == found_itr.first) && (found_itr.first == found_itr.second)) + { + break; + } + else + { + (*out) = found_itr; + ++out; + ++match_count; + itr_range.first = found_itr.second; + } + } + return match_count; + } + + template + inline std::size_t split_on_consecutive(const std::size_t n, + const std::size_t m, + Predicate p, + char* begin, + char* end, + OutputIterator out) + { + if (0 == n) return 0; + typedef char* iterator_type; + typedef details::range_type::type range_type; + range_type itr_range(begin,end); + std::size_t match_count = 0; + while ((end != itr_range.first) && (match_count <= n)) + { + range_type found_itr = details::find_exactly_n_consecutive_values(m,p,itr_range); + if ((end == found_itr.first) && (found_itr.first == found_itr.second)) + { + break; + } + else + { + (*out) = found_itr; + ++out; + ++match_count; + itr_range.first = found_itr.second; + } + } + return match_count; + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + const find_type::type type, + const find_mode::type mode, + char* begin, + char* end, + OutputIterator out) + { + if (0 == n) return 0; + typedef char* iterator_type; + typedef details::range_type::type range_type; + range_type itr_range(begin,end); + std::size_t match_count = 0; + while (end != itr_range.first) + { + range_type found_itr = find_n_consecutive(n,type,mode,itr_range); + if ((end == found_itr.first) && (found_itr.first == found_itr.second)) + { + break; + } + else + { + (*out) = found_itr; + ++out; + ++match_count; + itr_range.first = found_itr.second; + } + } + return match_count; + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + const find_type::type type, + const find_mode::type mode, + char* begin, + char* end, + OutputIterator out) + { + if (0 == n) return 0; + typedef char* iterator_type; + typedef details::range_type::type range_type; + range_type itr_range(begin,end); + std::size_t match_count = 0; + while ((end != itr_range.first) && (match_count <= n)) + { + range_type found_itr = find_n_consecutive(m,type,mode,itr_range); + if ((end == found_itr.first) && (found_itr.first == found_itr.second)) + { + break; + } + else + { + (*out) = found_itr; + ++out; + ++match_count; + itr_range.first = found_itr.second; + } + } + return match_count; + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + const find_type::type type, + const find_mode::type mode, + const char* begin, + const char* end, + OutputIterator out) + { + return split_on_consecutive(n, + type, + mode, + const_cast(begin), + const_cast(end), + out); + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + const find_type::type type, + const find_mode::type mode, + const unsigned char* begin, + const unsigned char* end, + OutputIterator out) + { + return split_on_consecutive(n, + type, + mode, + reinterpret_cast(begin), + reinterpret_cast(end), + out); + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + const find_type::type type, + const find_mode::type mode, + const std::string& str, + OutputIterator out) + { + return split_on_consecutive(n, + type, + mode, + str.data(), + str.data() + str.size(), + out); + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + const find_type::type type, + const find_mode::type mode, + const char* begin, + const char* end, + OutputIterator out) + { + return split_on_consecutive_n(n, + m, + type, + mode, + const_cast(begin), + const_cast(end), + out); + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + const find_type::type type, + const find_mode::type mode, + const unsigned char* begin, + const unsigned char* end, + OutputIterator out) + { + return split_on_consecutive_n(n, + m, + type, + mode, + reinterpret_cast(begin), + reinterpret_cast(end), + out); + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + const find_type::type type, + const find_mode::type mode, + const std::string& str, + OutputIterator out) + { + return split_on_consecutive_n(n, + m, + type, + mode, + str.data(), + str.data() + str.size(), + out); + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + Predicate p, + const char* begin, + const char* end, + OutputIterator out, + const bool stateful_predicate = false) + { + return split_on_consecutive(n, + p, + const_cast(begin), + const_cast(end), + out, + stateful_predicate); + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + Predicate p, + const unsigned char* begin, + const unsigned char* end, + OutputIterator out, + const bool stateful_predicate = false) + { + return split_on_consecutive(n, + p, + reinterpret_cast(begin), + reinterpret_cast(end), + out, + stateful_predicate); + } + + template + inline std::size_t split_on_consecutive(const std::size_t& n, + Predicate p, + const std::string& str, + OutputIterator out, + const bool stateful_predicate = false) + { + return split_on_consecutive(n, + p, + str.data(), + str.data() + str.size(), + out, + stateful_predicate); + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + Predicate p, + const char* begin, + const char* end, + OutputIterator out) + { + return split_on_consecutive_n(n, + m, + p, + const_cast(begin), + const_cast(end), + out); + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + Predicate p, + const unsigned char* begin, + const unsigned char* end, + OutputIterator out) + { + return split_on_consecutive_n(n, + m, + p, + reinterpret_cast(begin), + reinterpret_cast(end), + out); + } + + template + inline std::size_t split_on_consecutive_n(const std::size_t& n, + const std::size_t& m, + Predicate p, + const std::string& str, + OutputIterator out) + { + return split_on_consecutive_n(n, + m, + p, + str.data(), + str.data() + str.size(), + out); + } + + // Required for broken versions of GCC pre 4.5 + namespace util { class value; } + + namespace details + { + + class expect_impl + { + public: + + expect_impl(const std::string& s) + : s_(s) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + if (static_cast(std::distance(begin,end)) != s_.size()) + return false; + else + return std::equal(s_.data(),s_.data() + s_.size(),begin); + } + + inline expect_impl& ref() + { + return (*this); + } + + inline void set_value(const std::string& s) + { + s_ = s; + } + + private: + + std::string s_; + }; + + class iexpect_impl + { + public: + + iexpect_impl(const std::string& s) + : s_(s) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + if (static_cast(std::distance(begin,end)) != s_.size()) + return false; + else + return std::equal(s_.data(),s_.data() + s_.size(),begin,imatch_char); + } + + inline iexpect_impl& ref() + { + return (*this); + } + + inline void set_value(const std::string& s) + { + s_ = s; + } + + private: + + std::string s_; + }; + + class like_impl + { + public: + + like_impl(const std::string& s) + : s_(s) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + typedef typename std::iterator_traits::value_type value_type; + static const value_type zero_or_more = value_type('*'); + static const value_type zero_or_one = value_type('?'); + return strtk::match(s_.data(),s_.data() + s_.size(),begin,end,zero_or_more,zero_or_one); + } + + inline like_impl& ref() + { + return (*this); + } + + inline void set_pattern(const std::string& s) + { + s_ = s; + } + + private: + + std::string s_; + }; + + template + class inrange_impl + { + public: + + inrange_impl(T& t, const T& low, const T& hi) + : t_(&t), + low_(low), + hi_(hi) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + T temp; + if (!strtk::string_to_type_converter(begin,end,temp)) + return false; + else if (temp < low_) + return false; + else if (temp > hi_) + return false; + (*t_) = temp; + return true; + } + + inline inrange_impl& ref() + { + return (*this); + } + + inline void set_low_hi(const T& low, const T& hi) + { + low_ = low; + hi_ = hi; + } + + private: + + T* t_; + T low_; + T hi_; + }; + + namespace trim_details + { + template + struct convert_impl + { + template + static bool execute(InputIterator begin, InputIterator end, + const std::string& rem_chars, + std::size_t mode, + Type& t) + { + std::string s; + if (!strtk::string_to_type_converter(begin,end,s)) + return false; + switch (mode) + { + case 0 : remove_leading_trailing(rem_chars,s); break; + case 1 : remove_leading (rem_chars,s); break; + case 2 : remove_trailing (rem_chars,s); break; + default : return false; + } + return strtk::string_to_type_converter(s,t); + } + }; + + template <> + struct convert_impl + { + template + static bool execute(InputIterator begin, InputIterator end, + const std::string& rem_chars, + std::size_t mode, + std::string& t) + { + if (!strtk::string_to_type_converter(begin,end,t)) + return false; + switch (mode) + { + case 0 : remove_leading_trailing(rem_chars,t); break; + case 1 : remove_leading (rem_chars,t); break; + case 2 : remove_trailing (rem_chars,t); break; + default : return false; + } + return true; + } + }; + } + + template + class trim_impl + { + public: + + trim_impl(const std::size_t mode, + T& t, + const std::string& rem_chars = " ") + : mode_(mode), + t_(&t), + rem_chars_(rem_chars) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + return trim_details::convert_impl::execute(begin,end,rem_chars_,mode_,(*t_)); + } + + inline trim_impl& ref() + { + return (*this); + } + + private: + + std::size_t mode_; + T* t_; + std::string rem_chars_; + }; + + class conv_to_lcase_impl + { + public: + + conv_to_lcase_impl(std::string& s) + : s_(&s) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + std::string& s = (*s_); + s.assign(begin,end); + convert_to_lowercase(s); + return true; + } + + inline conv_to_lcase_impl& ref() + { + return (*this); + } + + private: + + std::string* s_; + }; + + class conv_to_ucase_impl + { + public: + + conv_to_ucase_impl(std::string& s) + : s_(&s) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + std::string& s = (*s_); + s.assign(begin,end); + convert_to_uppercase(s); + return true; + } + + inline conv_to_ucase_impl& ref() + { + return (*this); + } + + private: + + std::string* s_; + }; + + class fill_array_impl + { + public: + + fill_array_impl(unsigned char* data, const std::size_t& size) + : data_(data), + size_(size) + {} + + template + inline bool operator()(InputIterator begin, InputIterator end) + { + const std::size_t range_size = static_cast(std::distance(begin,end)); + if (range_size != size_) + return false; + std::memcpy(data_,begin,range_size); + return true; + } + + inline fill_array_impl& ref() + { + return (*this); + } + + inline fill_array_impl& set(unsigned char* data, const std::size_t& size) + { + data_ = data; + size_ = size; + return (*this); + } + + inline fill_array_impl& set(char* data, const std::size_t& size) + { + data_ = reinterpret_cast(data); + size_ = size; + return (*this); + } + + inline fill_array_impl& set_data(unsigned char* data) + { + data_ = data; + return (*this); + } + + inline fill_array_impl& set_data(char* data) + { + data_ = reinterpret_cast(data); + return (*this); + } + + inline fill_array_impl& set_size(const std::size_t& size) + { + size_ = size; + return (*this); + } + + private: + + unsigned char* data_; + std::size_t size_; + }; + } + + inline details::expect_impl expect(const std::string& s) + { + return details::expect_impl(s); + } + + inline details::iexpect_impl iexpect(const std::string& s) + { + return details::iexpect_impl(s); + } + + inline details::like_impl like(const std::string& s) + { + return details::like_impl(s); + } + + template + inline details::inrange_impl inrange(T& t, const T0& low, const T1& hi) + { + return details::inrange_impl(t,T(low),T(hi)); + } + + template + inline details::trim_impl trim(const std::string& rem_chars, T& t) + { + return details::trim_impl(0,t,rem_chars); + } + + template + inline details::trim_impl trim_leading(const std::string& rem_chars, T& t) + { + return details::trim_impl(1,t,rem_chars); + } + + template + inline details::trim_impl trim_trailing(const std::string& rem_chars, T& t) + { + return details::trim_impl(2,t,rem_chars); + } + + inline details::conv_to_lcase_impl as_lcase(std::string& s) + { + return details::conv_to_lcase_impl(s); + } + + inline details::conv_to_ucase_impl as_ucase(std::string& s) + { + return details::conv_to_ucase_impl(s); + } + + inline details::fill_array_impl fill_array(unsigned char* data, const std::size_t& size) + { + return details::fill_array_impl(data,size); + } + + inline details::fill_array_impl fill_array(char* data, const std::size_t& size) + { + return details::fill_array_impl(reinterpret_cast(data),size); + } + + template + inline details::fill_array_impl fill_array(unsigned char (&data)[N]) + { + return details::fill_array_impl(data,N); + } + + template + inline details::fill_array_impl fill_array(char (&data)[N]) + { + return details::fill_array_impl(reinterpret_cast(data),N); + } + + inline details::fill_array_impl fill_array(std::string& data, const std::size_t& size) + { + return fill_array(const_cast(data.data()),size); + } + + inline details::fill_array_impl fill_array(std::string& data) + { + return fill_array(const_cast(data.data()),data.size()); + } + + namespace details + { + static const unsigned char digit_table[] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF - 0x07 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x08 - 0x0F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10 - 0x17 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x18 - 0x1F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20 - 0x27 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x28 - 0x2F + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 0x30 - 0x37 + 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x38 - 0x3F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x40 - 0x47 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x48 - 0x4F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x50 - 0x57 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x58 - 0x5F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x60 - 0x67 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x68 - 0x6F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x70 - 0x77 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x78 - 0x7F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x80 - 0x87 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x88 - 0x8F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x90 - 0x97 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x98 - 0x9F + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA0 - 0xA7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xA8 - 0xAF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB0 - 0xB7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xB8 - 0xBF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC0 - 0xC7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xC8 - 0xCF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD0 - 0xD7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xD8 - 0xDF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE0 - 0xE7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xE8 - 0xEF + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xF0 - 0xF7 + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 0xF8 - 0xFF + }; + + static const std::size_t digit_table_size = sizeof(digit_table) / sizeof(unsigned char); + + template + static inline bool is_invalid_digit(const T& t) + { + static const unsigned int invalid_digit = 0xFF; + return (static_cast(invalid_digit) == t); + } + + template + static inline bool is_valid_digit(const T& t) + { + static const unsigned int invalid_digit = 0xFF; + return (static_cast(invalid_digit) != t); + } + + static const unsigned char digitr[] = + { + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + }; + + static const unsigned char rev_3digit_lut[] = + { + "000001002003004005006007008009010011012013014015016017018019020021022023024" + "025026027028029030031032033034035036037038039040041042043044045046047048049" + "050051052053054055056057058059060061062063064065066067068069070071072073074" + "075076077078079080081082083084085086087088089090091092093094095096097098099" + "100101102103104105106107108109110111112113114115116117118119120121122123124" + "125126127128129130131132133134135136137138139140141142143144145146147148149" + "150151152153154155156157158159160161162163164165166167168169170171172173174" + "175176177178179180181182183184185186187188189190191192193194195196197198199" + "200201202203204205206207208209210211212213214215216217218219220221222223224" + "225226227228229230231232233234235236237238239240241242243244245246247248249" + "250251252253254255256257258259260261262263264265266267268269270271272273274" + "275276277278279280281282283284285286287288289290291292293294295296297298299" + "300301302303304305306307308309310311312313314315316317318319320321322323324" + "325326327328329330331332333334335336337338339340341342343344345346347348349" + "350351352353354355356357358359360361362363364365366367368369370371372373374" + "375376377378379380381382383384385386387388389390391392393394395396397398399" + "400401402403404405406407408409410411412413414415416417418419420421422423424" + "425426427428429430431432433434435436437438439440441442443444445446447448449" + "450451452453454455456457458459460461462463464465466467468469470471472473474" + "475476477478479480481482483484485486487488489490491492493494495496497498499" + "500501502503504505506507508509510511512513514515516517518519520521522523524" + "525526527528529530531532533534535536537538539540541542543544545546547548549" + "550551552553554555556557558559560561562563564565566567568569570571572573574" + "575576577578579580581582583584585586587588589590591592593594595596597598599" + "600601602603604605606607608609610611612613614615616617618619620621622623624" + "625626627628629630631632633634635636637638639640641642643644645646647648649" + "650651652653654655656657658659660661662663664665666667668669670671672673674" + "675676677678679680681682683684685686687688689690691692693694695696697698699" + "700701702703704705706707708709710711712713714715716717718719720721722723724" + "725726727728729730731732733734735736737738739740741742743744745746747748749" + "750751752753754755756757758759760761762763764765766767768769770771772773774" + "775776777778779780781782783784785786787788789790791792793794795796797798799" + "800801802803804805806807808809810811812813814815816817818819820821822823824" + "825826827828829830831832833834835836837838839840841842843844845846847848849" + "850851852853854855856857858859860861862863864865866867868869870871872873874" + "875876877878879880881882883884885886887888889890891892893894895896897898899" + "900901902903904905906907908909910911912913914915916917918919920921922923924" + "925926927928929930931932933934935936937938939940941942943944945946947948949" + "950951952953954955956957958959960961962963964965966967968969970971972973974" + "975976977978979980981982983984985986987988989990991992993994995996997998999" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + }; + + static const unsigned char rev_2digit_lut[] = + { + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + }; + + #define strtk_register_pod_type(T) \ + template<> struct is_pod{ typedef yes_t result_t; enum {result = true }; }; \ + template<> struct is_pod{ typedef yes_t result_t; enum {result = true }; }; \ + template<> struct is_pod{ typedef yes_t result_t; enum {result = true }; }; \ + template<> struct is_pod{ typedef yes_t result_t; enum {result = true }; };\ + + strtk_register_pod_type(bool) + strtk_register_pod_type(signed char) + strtk_register_pod_type(char) + strtk_register_pod_type(short) + strtk_register_pod_type(int) + strtk_register_pod_type(long int) + strtk_register_pod_type(long long int) + strtk_register_pod_type(unsigned char) + strtk_register_pod_type(unsigned short) + strtk_register_pod_type(unsigned int) + strtk_register_pod_type(unsigned long int) + strtk_register_pod_type(unsigned long long int) + strtk_register_pod_type(float) + strtk_register_pod_type(double) + strtk_register_pod_type(long double) + + #undef strtk_register_pod_type + + template + struct numeric { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; + + template<> struct numeric { enum { length = 5, size = 16, bound_length = 4}; }; + template<> struct numeric { enum { length = 5, size = 16, bound_length = 4}; }; + + template<> struct numeric { enum { length = 10, size = 16, bound_length = 9}; }; + template<> struct numeric { enum { length = 10, size = 16, bound_length = 9}; }; + + template<> struct numeric { enum { length = 10, size = 16, bound_length = 9}; }; + template<> struct numeric { enum { length = 10, size = 16, bound_length = 9}; }; + + template<> struct numeric { enum { length = 19, size = 24, bound_length = 18}; }; + template<> struct numeric { enum { length = 20, size = 24, bound_length = 19}; }; + + template<> struct numeric { enum { min_exp = -37, max_exp = +38, precision = 10}; }; + template<> struct numeric { enum { min_exp = -307, max_exp = +308, precision = 15}; }; + + template struct ldt {}; + template <> struct ldt { enum { i = -308, a = +308, p = 15}; }; //64-bit + template <> struct ldt { enum { i = -4931, a = +4931, p = 18}; }; //80-bit + template <> struct ldt { enum { i = -4931, a = +4931, p = 22}; }; //96-bit + template <> struct ldt { enum { i = -4931, a = +4931, p = 34}; }; //128-bit + + template<> + struct numeric + { + typedef ldt ld; + enum { min_exp = ld::i, max_exp = ld::a, precision = ld::p}; + }; + + #define strtk_register_unsigned_type_tag(T) \ + template<> struct supported_conversion_to_type { typedef unsigned_type_tag type; }; \ + template<> struct supported_conversion_from_type { typedef unsigned_type_tag type; };\ + + #define strtk_register_signed_type_tag(T) \ + template<> struct supported_conversion_to_type{ typedef signed_type_tag type; }; \ + template<> struct supported_conversion_from_type { typedef signed_type_tag type; }; \ + + #define strtk_register_real_type_tag(T) \ + template<> struct supported_conversion_to_type{ typedef real_type_tag type; }; + + #define strtk_register_byte_type_tag(T) \ + template<> struct supported_conversion_to_type{ typedef byte_type_tag type; }; \ + template<> struct supported_conversion_from_type { typedef byte_type_tag type; };\ + + #define strtk_register_hex_number_type_tag(T) \ + template<> struct supported_conversion_to_type{ typedef hex_number_type_tag type; }; + + template<> struct supported_conversion_to_type{ typedef hex_string_type_tag type; }; + + #define strtk_register_base64_type_tag(T) \ + template<> struct supported_conversion_to_type{ typedef base64_type_tag type; }; + + #define strtk_register_supported_iterator_type(T) \ + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef bool_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef stdstring_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef value_type_tag type; }; + template<> struct supported_conversion_from_type { typedef value_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef expect_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef expect_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef like_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef fillchararray_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef lcase_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + template<> struct supported_conversion_to_type { typedef ucase_type_tag type; }; + template<> struct supported_iterator_type { enum { value = true }; }; + + #define strtk_register_truncint_type_tag(T) \ + template<> struct supported_conversion_to_type > { typedef truncint_type_tag type; };\ + template<> struct supported_iterator_type > { enum { value = true }; }; + + #define strtk_register_inrange_type_tag(T) \ + template<> struct supported_conversion_to_type > { typedef inrange_type_tag type; };\ + template<> struct supported_iterator_type > { enum { value = true }; }; + + #define strtk_register_trim_type_tag(T) \ + template<> struct supported_conversion_to_type > { typedef trim_type_tag type; };\ + template<> struct supported_iterator_type > { enum { value = true }; }; + + #define strtk_register_stdstring_range_type_tag(T) \ + template<> struct supported_conversion_to_type< std::pair >{ typedef stdstring_range_type_tag type; }; + + #define strtk_register_sink_type_tag(T) \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_to_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; }; \ + template<> struct supported_conversion_from_type > > { typedef sink_type_tag type; };\ + + #define strtk_register_stl_container_to_string_conv_type_tag(T) \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; }; \ + template<> struct supported_conversion_from_type > { typedef stl_seq_type_tag type; };\ + + template<> struct supported_conversion_to_type{ typedef ignore_token_type_tag type; }; + + #define strtk_register_sequence_iterator_type(sequence) \ + strtk_register_supported_iterator_type(sequence::iterator) \ + strtk_register_supported_iterator_type(sequence::const_iterator) \ + strtk_register_supported_iterator_type(sequence::iterator) \ + strtk_register_supported_iterator_type(sequence::const_iterator)\ + + strtk_register_unsigned_type_tag(unsigned short) + strtk_register_unsigned_type_tag(unsigned int) + strtk_register_unsigned_type_tag(unsigned long) + strtk_register_unsigned_type_tag(unsigned long long int) + + strtk_register_signed_type_tag(short) + strtk_register_signed_type_tag(int) + strtk_register_signed_type_tag(long) + strtk_register_signed_type_tag(long long) + + strtk_register_real_type_tag(float) + strtk_register_real_type_tag(double) + strtk_register_real_type_tag(long double) + + strtk_register_byte_type_tag(unsigned char) + strtk_register_byte_type_tag(signed char) + strtk_register_byte_type_tag(char) + + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + strtk_register_hex_number_type_tag(hex_to_number_sink) + + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + strtk_register_base64_type_tag(base64_to_number_sink) + + strtk_register_stdstring_range_type_tag(std::string::iterator) + strtk_register_stdstring_range_type_tag(std::string::const_iterator) + strtk_register_stdstring_range_type_tag(char*) + strtk_register_stdstring_range_type_tag(signed char*) + strtk_register_stdstring_range_type_tag(unsigned char*) + strtk_register_stdstring_range_type_tag(const char*) + strtk_register_stdstring_range_type_tag(const unsigned char*) + + strtk_register_supported_iterator_type(char*) + strtk_register_supported_iterator_type(signed char*) + strtk_register_supported_iterator_type(unsigned char*) + strtk_register_supported_iterator_type(const char*) + strtk_register_supported_iterator_type(const signed char*) + strtk_register_supported_iterator_type(const unsigned char*) + strtk_register_supported_iterator_type(std::string::iterator) + strtk_register_supported_iterator_type(std::string::const_iterator) + + strtk_register_sequence_iterator_type(std::vector) + strtk_register_sequence_iterator_type(std::deque) + + strtk_register_sink_type_tag(float) + strtk_register_sink_type_tag(double) + strtk_register_sink_type_tag(long double) + strtk_register_sink_type_tag(signed char) + strtk_register_sink_type_tag(char) + strtk_register_sink_type_tag(short) + strtk_register_sink_type_tag(int) + strtk_register_sink_type_tag(long) + strtk_register_sink_type_tag(long long) + strtk_register_sink_type_tag(unsigned char) + strtk_register_sink_type_tag(unsigned short) + strtk_register_sink_type_tag(unsigned int) + strtk_register_sink_type_tag(unsigned long) + strtk_register_sink_type_tag(unsigned long long int) + strtk_register_sink_type_tag(std::string) + + strtk_register_stl_container_to_string_conv_type_tag(float) + strtk_register_stl_container_to_string_conv_type_tag(double) + strtk_register_stl_container_to_string_conv_type_tag(long double) + strtk_register_stl_container_to_string_conv_type_tag(signed char) + strtk_register_stl_container_to_string_conv_type_tag(char) + strtk_register_stl_container_to_string_conv_type_tag(short) + strtk_register_stl_container_to_string_conv_type_tag(int) + strtk_register_stl_container_to_string_conv_type_tag(long) + strtk_register_stl_container_to_string_conv_type_tag(long long) + strtk_register_stl_container_to_string_conv_type_tag(unsigned char) + strtk_register_stl_container_to_string_conv_type_tag(unsigned short) + strtk_register_stl_container_to_string_conv_type_tag(unsigned int) + strtk_register_stl_container_to_string_conv_type_tag(unsigned long) + strtk_register_stl_container_to_string_conv_type_tag(unsigned long long int) + strtk_register_stl_container_to_string_conv_type_tag(std::string) + + strtk_register_inrange_type_tag(float) + strtk_register_inrange_type_tag(double) + strtk_register_inrange_type_tag(long double) + strtk_register_inrange_type_tag(signed char) + strtk_register_inrange_type_tag(char) + strtk_register_inrange_type_tag(short) + strtk_register_inrange_type_tag(int) + strtk_register_inrange_type_tag(long) + strtk_register_inrange_type_tag(long long) + strtk_register_inrange_type_tag(unsigned char) + strtk_register_inrange_type_tag(unsigned short) + strtk_register_inrange_type_tag(unsigned int) + strtk_register_inrange_type_tag(unsigned long) + strtk_register_inrange_type_tag(unsigned long long int) + strtk_register_inrange_type_tag(std::string) + + strtk_register_trim_type_tag(float) + strtk_register_trim_type_tag(double) + strtk_register_trim_type_tag(long double) + strtk_register_trim_type_tag(signed char) + strtk_register_trim_type_tag(char) + strtk_register_trim_type_tag(short) + strtk_register_trim_type_tag(int) + strtk_register_trim_type_tag(long) + strtk_register_trim_type_tag(long long) + strtk_register_trim_type_tag(unsigned char) + strtk_register_trim_type_tag(unsigned short) + strtk_register_trim_type_tag(unsigned int) + strtk_register_trim_type_tag(unsigned long) + strtk_register_trim_type_tag(unsigned long long int) + strtk_register_trim_type_tag(std::string) + + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + strtk_register_trim_type_tag(truncated_int) + + strtk_register_truncint_type_tag(short) + strtk_register_truncint_type_tag(int) + strtk_register_truncint_type_tag(long) + strtk_register_truncint_type_tag(long long) + strtk_register_truncint_type_tag(unsigned short) + strtk_register_truncint_type_tag(unsigned int) + strtk_register_truncint_type_tag(unsigned long) + strtk_register_truncint_type_tag(unsigned long long int) + + #define strtk_register_userdef_type_sink(T) \ + namespace strtk { namespace details { strtk_register_sink_type_tag(T) }} + + #undef strtk_register_unsigned_type_tag + #undef strtk_register_signed_type_tag + #undef strtk_register_real_type_tag + #undef strtk_register_byte_type_tag + #undef strtk_register_hex_number_type_tag + #undef strtk_register_base64_type_tag + #undef strtk_register_supported_iterator_type + #undef strtk_register_stdstring_range_type_tag + #undef strtk_register_sequence_iterator_type + #undef strtk_register_stl_container_to_string_conv_type_tag + #undef strtk_register_inrange_type_tag + #undef strtk_register_trim_type_tag + #undef strtk_register_truncint_type_tag + + template + struct precision + { static void set(std::iostream&) {} }; + + #define strtk_register_iostream_precision(T) \ + template<> struct precision { static void set(std::iostream& s, const std::streamsize& p = 10) { s.precision(p);} }; + + strtk_register_iostream_precision(float) + strtk_register_iostream_precision(double) + strtk_register_iostream_precision(long double) + + #undef strtk_register_iostream_precision + + template + inline bool string_to_type_converter_impl(Iterator& begin, const Iterator end, T& t, not_supported_type_tag) + { + #ifdef strtk_enable_lexical_cast + try + { + t = boost::lexical_cast(std::string(begin,end)); + } + catch (const boost::bad_lexical_cast&) + { + return false; + } + begin = end; + return true; + #else + try + { + std::stringstream ss(std::string(begin,end)); + ss >> t; + } + catch (const std::exception&) + { + return false; + } + begin = end; + return true; + #endif + } + + template + inline bool string_to_type_converter_impl(Iterator& begin, const Iterator end, strtk::util::value& v, value_type_tag) + { + return v(begin,end); + } + + template + inline bool string_to_type_converter_impl(Iterator& begin, const Iterator end, std::string& t, stdstring_type_tag) + { + t.assign(begin,end); + begin = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, Expect& t, expect_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, Like& t, like_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, InRange& t, inrange_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, TrimToken& t, trim_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, CaseToken& t, lcase_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, CaseToken& t, ucase_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, Array& t, fillchararray_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, TruncatedInt& t, truncint_type_tag) + { + if (!t(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr_external, const Iterator end, T& result, unsigned_type_tag) + { + if (end == itr_external) return false; + + Iterator itr = itr_external; + + if ('+' == (*itr)) + ++itr; + + if (end == itr) + return false; + + while ((end != itr) && ('0' == (*itr))) ++itr; + const std::size_t length = std::distance(itr,end); + + if (length > numeric::length) + return false; + + static const std::size_t bound_length = numeric::bound_length; + T t = 0; + + if (0 != length) + { + std::size_t interim_length = std::min(bound_length,length); + const Iterator interim_end = itr + interim_length; + unsigned int digit[8]; + T t0 = 0; + T t1 = 0; + T t2 = 0; + T t3 = 0; + + //Needed for incompetent and broken msvc compiler versions + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + + while (interim_length > 7) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9) || + ((digit[2] = (itr[2] - '0')) > 9) || + ((digit[3] = (itr[3] - '0')) > 9) || + ((digit[4] = (itr[4] - '0')) > 9) || + ((digit[5] = (itr[5] - '0')) > 9) || + ((digit[6] = (itr[6] - '0')) > 9) || + ((digit[7] = (itr[7] - '0')) > 9)) + return false; + else + { + t0 = static_cast(digit[0] * 10000000 + digit[1] * 1000000); + t1 = static_cast(digit[2] * 100000 + digit[3] * 10000); + t2 = static_cast(digit[4] * 1000 + digit[5] * 100); + t3 = static_cast(digit[6] * 10 + digit[7] ); + t = t0 + t1 + t2 + t3 + static_cast(t * 100000000); + itr += 8; + interim_length -= 8; + } + } + + while (interim_length > 3) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9) || + ((digit[2] = (itr[2] - '0')) > 9) || + ((digit[3] = (itr[3] - '0')) > 9)) + return false; + else + { + t1 = static_cast(digit[0] * 1000 + digit[1] * 100); + t2 = static_cast(digit[2] * 10 + digit[3] ); + t3 = static_cast(t * 10000 ); + t = t1 + t2 + t3; + itr += 4; + interim_length -= 4; + } + } + + while (interim_length > 1) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9)) + return false; + else + { + t1 = static_cast(digit[0] * 10 + digit[1]); + t2 = static_cast(t * 100 ); + t = t1 + t2; + itr += 2; + interim_length -= 2; + } + } + + //Needed for incompetent and broken msvc compiler versions. + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + if (interim_length) + { + if ((digit[0] = (itr[0] - '0')) < 10) + { + t = static_cast(digit[0] + t * 10); + ++itr; + } + else + return false; + } + + if (interim_end != end) + { + if (1 == std::distance(interim_end,end)) + { + typedef unsigned long long int num_type; + static const num_type max = static_cast(std::numeric_limits::max()); + static const num_type penultimate_bound = static_cast(max / 10); + static const num_type final_digit = static_cast(max % 10); + + digit[0] = static_cast(*itr - '0'); + if (digit[0] <= 9) + { + if (t > penultimate_bound) + return false; + else if ((penultimate_bound == t) && (final_digit < digit[0])) + return false; + t = static_cast(digit[0] + t * 10); + } + else + return false; + } + else + return false; + } + } + + result = static_cast(t); + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr_external, const Iterator end, T& result, signed_type_tag) + { + if (end == itr_external) return false; + + Iterator itr = itr_external; + + bool negative = false; + + if ('+' == (*itr)) + ++itr; + else if ('-' == (*itr)) + { + ++itr; + negative = true; + } + + if (end == itr) return false; + + while ((end != itr) && ('0' == (*itr))) ++itr; + + const std::size_t length = std::distance(itr,end); + + if (length > numeric::length) + return false; + + static const std::size_t bound_length = numeric::bound_length; + T t = 0; + + if (0 != length) + { + std::size_t interim_length = std::min(bound_length,length); + const Iterator interim_end = itr + interim_length; + unsigned int digit[8]; + T t0 = 0; + T t1 = 0; + T t2 = 0; + T t3 = 0; + + //Needed for incompetent and broken msvc compiler versions + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + + while (interim_length > 7) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9) || + ((digit[2] = (itr[2] - '0')) > 9) || + ((digit[3] = (itr[3] - '0')) > 9) || + ((digit[4] = (itr[4] - '0')) > 9) || + ((digit[5] = (itr[5] - '0')) > 9) || + ((digit[6] = (itr[6] - '0')) > 9) || + ((digit[7] = (itr[7] - '0')) > 9) ) + return false; + else + { + t0 = static_cast(digit[0] * 10000000 + digit[1] * 1000000); + t1 = static_cast(digit[2] * 100000 + digit[3] * 10000); + t2 = static_cast(digit[4] * 1000 + digit[5] * 100); + t3 = static_cast(digit[6] * 10 + digit[7] ); + t = t0 + t1 + t2 + t3 + static_cast(t * 100000000); + itr += 8; + interim_length -= 8; + } + } + + while (interim_length > 3) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9) || + ((digit[2] = (itr[2] - '0')) > 9) || + ((digit[3] = (itr[3] - '0')) > 9) ) + return false; + else + { + t0 = static_cast(digit[0] * 1000 + digit[1] * 100); + t1 = static_cast(digit[2] * 10 + digit[3] ); + t = t0 + t1 + static_cast(t * 10000); + itr += 4; + interim_length -= 4; + } + } + + while (interim_length > 2) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9) || + ((digit[2] = (itr[2] - '0')) > 9)) + return false; + else + { + t0 = static_cast(digit[0] * 100 + digit[1] * 10); + t1 = static_cast(t * 1000 + digit[2] ); + t = t0 + t1; + itr += 3; + interim_length -= 3; + } + } + + while (interim_length > 1) + { + if (((digit[0] = (itr[0] - '0')) > 9) || + ((digit[1] = (itr[1] - '0')) > 9)) + return false; + else + { + t0 = static_cast(digit[0] * 10 + digit[1]); + t = t0 + static_cast(t * 100); + itr += 2; + interim_length -= 2; + } + } + + //Needed for incompetent and broken msvc compiler versions. + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + if (interim_length) + { + if ((digit[0] = (itr[0] - '0')) < 10) + { + t = static_cast(digit[0] + t * 10); + ++itr; + } + else + return false; + } + + if (interim_end != end) + { + if (1 == std::distance(interim_end,end)) + { + typedef unsigned long long int num_type; + static const num_type max = static_cast(std::numeric_limits::max()); + static const num_type min = static_cast(static_cast(-1) * std::numeric_limits::min()); + static const num_type positive_penultimate_bound = static_cast(max / 10); + static const num_type negative_penultimate_bound = static_cast(min / 10); + static const num_type positive_final_digit = static_cast(max % 10); + static const num_type negative_final_digit = static_cast(min % 10); + + digit[0] = static_cast(*itr - '0'); + + if (digit[0] < 10) + { + if (negative) + { + if (static_cast(t) > negative_penultimate_bound) + return false; + else if ( + (negative_penultimate_bound == static_cast(t)) && + (negative_final_digit < digit[0]) + ) + return false; + } + else + { + if (static_cast(t) > positive_penultimate_bound) + return false; + else if ( + (positive_penultimate_bound == static_cast(t)) && + (positive_final_digit < digit[0]) + ) + return false; + } + t = static_cast(digit[0] + t * 10); + } + else + return false; + } + else + return false; + } + } + itr_external = itr; + result = static_cast((negative) ? -t : t); + return true; + } + + template + inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result, signed_type_tag) + { + if (end == itr) return false; + + T t = 0; + bool negative = false; + + if ('+' == (*itr)) + ++itr; + else if ('-' == (*itr)) + { + ++itr; + negative = true; + } + + if (end == itr) + return false; + + unsigned int digit_count = 0; + while ((end != itr) && ('0' == (*itr))) ++itr; + + bool return_result = true; + while (end != itr) + { + const unsigned char digit = (*itr - '0'); + if (digit > 9) + { + return_result = false; + break; + } + + if ((++digit_count) <= numeric::bound_length) + { + t *= 10; + t += digit; + } + else + { + typedef unsigned long long int base_type; + static const base_type max_limit = +std::numeric_limits::max(); + static const base_type min_limit = -std::numeric_limits::min(); + base_type tmp = static_cast(t) * 10 + digit; + if (negative && static_cast(tmp) > min_limit) + return_result = false; + else if (static_cast(tmp) > max_limit) + return_result = false; + t = static_cast(tmp); + } + ++itr; + } + + result = static_cast((negative) ? -t : t); + return return_result; + } + + template + inline bool parse_nan(Iterator& itr, const Iterator end, T& t) + { + typedef typename std::iterator_traits::value_type type; + static const std::size_t nan_length = 3; + if (std::distance(itr,end) != static_cast(nan_length)) + return false; + if (static_cast('n') == (*itr)) + { + if ((static_cast('a') != *(itr + 1)) || (static_cast('n') != *(itr + 2))) + { + return false; + } + } + else if ((static_cast('A') != *(itr + 1)) || (static_cast('N') != *(itr + 2))) + { + return false; + } + t = std::numeric_limits::quiet_NaN(); + return true; + } + + template + inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative) + { + static const char inf_uc[] = "INFINITY"; + static const char inf_lc[] = "infinity"; + static const std::size_t inf_length = 8; + const std::size_t length = std::distance(itr,end); + if ((3 != length) && (inf_length != length)) + return false; + const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + while (end != itr) + { + if (*inf_itr == static_cast(*itr)) + { + ++itr; + ++inf_itr; + continue; + } + else + return false; + } + if (negative) + t = -std::numeric_limits::infinity(); + else + t = std::numeric_limits::infinity(); + return true; + } + + template struct real_type {}; + template <> struct real_type { typedef double type; }; + template <> struct real_type { typedef double type; }; + template <> struct real_type { typedef long double type; }; + + template + inline bool string_to_type_converter_impl(Iterator& itr_external, const Iterator end, T& t, real_type_tag) + { + typedef typename real_type::type real_t; + if (end == itr_external) return false; + Iterator itr = itr_external; + real_t d = real_t(0); + bool negative = false; + if ('+' == (*itr)) + ++itr; + else if ('-' == (*itr)) + { + ++itr; + negative = true; + } + + if (end == itr) + return false; + + if (('I' <= (*itr)) && ((*itr) <= 'n')) + { + if (('i' == (*itr)) || ('I' == (*itr))) + { + return parse_inf(itr,end,t,negative); + } + else if (('n' == (*itr)) || ('N' == (*itr))) + { + return parse_nan(itr,end,t); + } + else + return false; + } + + bool instate = false; + int pre_decimal = 0; + + if ('.' != (*itr)) + { + const Iterator curr = itr; + while ((end != itr) && ('0' == (*itr))) ++itr; + const Iterator post_zero_cull_itr = itr; + unsigned char digit = 0; + + #define parse_digit_1 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= real_t(10); d += digit; } else break; if (end == ++itr) break; \ + + #define parse_digit_2 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= real_t(10); d += digit; } else break; ++itr;\ + + while (end != itr) + { + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_2 + } + #undef parse_digit_1 + #undef parse_digit_2 + if (curr != itr) instate = true; + pre_decimal = static_cast(std::distance(post_zero_cull_itr,itr)); + } + + int exponent = 0; + + if (end != itr) + { + if ('.' == (*itr)) + { + ++itr; + const Iterator curr = itr; + unsigned char digit = 0; + + #define parse_digit_1 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= real_t(10); d += digit; } else break; if (end == ++itr) break; \ + + #define parse_digit_2 \ + if ((digit = static_cast((*itr) - '0')) < 10) { d *= real_t(10); d += digit; } else break; ++itr;\ + + while (end != itr) + { + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_1 + parse_digit_2 + } + #undef parse_digit_1 + #undef parse_digit_2 + if (curr != itr) instate = true; + exponent -= static_cast(std::distance(curr,itr)); + } + + if (end != itr) + { + typename std::iterator_traits::value_type c = (*itr); + + if (('e' == c) || ('E' == c)) + { + ++itr; + int exp = 0; + if (!details::string_to_type_converter_impl_ref(itr,end,exp,details::signed_type_tag())) + { + if (end == itr) + return false; + else + c = (*itr); + } + + if ((exp < numeric::min_exp) || (numeric::max_exp < exp)) + return false; + + exponent += exp; + } + + if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) + ++itr; + else if ('#' == c) + { + ++itr; + if (end == itr) + return false; + if ((10.0 != d) || (exponent != -1)) + return false; + if (('I' <= (*itr)) && ((*itr) <= 'n')) + { + if (('i' == (*itr)) || ('I' == (*itr))) + { + return parse_inf(itr,end,t,negative); + } + else if (('n' == (*itr)) || ('N' == (*itr))) + { + return parse_nan(itr,end,t); + } + else + return false; + } + return false; + } + } + } + + if ((end != itr) || (!instate)) + return false; + + if (0 != exponent) + { + if ( + (std::numeric_limits::max_exponent10 < (exponent + pre_decimal)) || + (std::numeric_limits::min_exponent10 > (exponent + pre_decimal)) + ) + { + return false; + } + + const int e = std::abs(exponent); + static const double fract10[] = + { + 0.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, + 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, + 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, + 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, + 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, + 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, + 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, + 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, + 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, + 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, + 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, + 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, + 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, + 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, + 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, + 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, + 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, + 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, + 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, + 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, + 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, + 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, + 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, + 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, + 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, + 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, + 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, + 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, + 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, + 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, + 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 + }; + + static const std::size_t fract10_size = sizeof(fract10) / sizeof(double); + + if (d != real_t(0)) + { + if (static_cast(e) < fract10_size) + { + if (exponent > 0) + d *= fract10[e]; + else + d /= fract10[e]; + } + else + d *= std::pow(real_t(10), real_t(10) * exponent); + } + } + + t = static_cast((negative) ? -d : d); + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, T& t, byte_type_tag) + { + if (1 != std::distance(itr,end)) + return false; + t = static_cast(*itr); + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, bool& t, bool_type_tag) + { + if (1 != std::distance(itr,end)) + return false; + t = (('0' == (*itr)) ? false : true); + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, IgnoreTokenType&, ignore_token_type_tag) + { + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, HexSinkType& t, hex_number_type_tag) + { + t = std::pair(itr,end); + if (!t.valid()) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, HexSinkType& t, hex_string_type_tag) + { + t = std::pair(itr,end); + if (!t.valid()) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, Base64SinkType& t, base64_type_tag) + { + t = std::pair(itr,end); + if (!t.valid()) + return false; + itr = end; + return true; + } + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, SinkType& t, sink_type_tag) + { + if (!t.parse(itr,end)) + return false; + itr = end; + return true; + } + + template + inline bool type_to_string_converter_impl(const T& t, std::string& s, not_supported_type_tag) + { + #ifdef strtk_enable_lexical_cast + try + { + s = boost::lexical_cast(t); + } + catch (const boost::bad_lexical_cast&) + { + return false; + } + #else + try + { + std::stringstream ss; + precision::set(ss); + ss << t; + s = ss.str(); + } + catch (const std::exception&) + { + return false; + } + #endif + return true; + } + + template + inline bool type_to_string_converter_impl(T value, std::string& result, unsigned_type_tag) + { + static const std::size_t radix = 10; + static const std::size_t radix_sqr = radix * radix; + static const std::size_t radix_cube = radix * radix * radix; + static const std::size_t buffer_size = ((strtk::details::numeric::size < 16) ? 16 : 32); + unsigned char buffer[buffer_size]; + unsigned char* itr = buffer + buffer_size; + + if (value) + { + while (value >= static_cast(radix_sqr)) + { + itr -= 3; + T temp_v = value / radix_cube; + memcpy(itr,&details::rev_3digit_lut[3 * (value - (temp_v * radix_cube))],3); + value = temp_v; + } + + while (value >= static_cast(radix)) + { + itr -= 2; + T temp_v = value / radix_sqr; + memcpy(itr,&details::rev_2digit_lut[2 * (value - (temp_v * radix_sqr))],2); + value = temp_v; + } + + if (value) + { + *(--itr) = static_cast('0' + value); + } + } + else + *(--itr) = '0'; + + result.assign(reinterpret_cast(itr), (buffer + buffer_size) - itr); + return true; + } + + template + struct tsci_type {}; + + #define define_tsci_type(Type,ReType) \ + template <> \ + struct tsci_type \ + { \ + typedef ReType type; \ + }; \ + + define_tsci_type(short ,unsigned short ) + define_tsci_type(int ,unsigned int ) + define_tsci_type(long ,unsigned long ) + define_tsci_type(long long,unsigned long long) + + #undef define_tsci_type + + template + inline bool type_to_string_converter_impl(T valuex, std::string& result, signed_type_tag) + { + static const std::size_t radix = 10; + static const std::size_t radix_sqr = radix * radix; + static const std::size_t radix_cube = radix * radix * radix; + static const std::size_t buffer_size = ((strtk::details::numeric::size < 16) ? 16 : 32); + unsigned char buffer[buffer_size]; + unsigned char* itr = buffer + buffer_size; + bool negative = (valuex < 0); + typedef typename tsci_type::type TT; + TT value = (negative) ? -valuex : valuex; + + if (value) + { + while (value >= static_cast(radix_sqr)) + { + itr -= 3; + T temp_v = value / radix_cube; + memcpy(itr,&details::rev_3digit_lut[3 * (value - (temp_v * radix_cube))],3); + value = temp_v; + } + + while (value >= static_cast(radix)) + { + itr -= 2; + T temp_v = value / radix_sqr; + memcpy(itr,&details::rev_2digit_lut[2 * (value - (temp_v * radix_sqr))],2); + value = temp_v; + } + + if (value) + { + *(--itr) = static_cast('0' + value); + } + + if (negative) + { + *(--itr) = '-'; + } + } + else + *(--itr) = '0'; + + result.assign(reinterpret_cast(itr), (buffer + buffer_size) - itr); + return true; + } + + template + inline bool type_to_string_converter_impl(const T& value, std::string& result, byte_type_tag) + { + result.resize(1); + result[0] = static_cast(value); + return true; + } + + inline bool type_to_string_converter_impl(const bool& value, std::string& result, bool_type_tag) + { + result.resize(1); + result[0] = value ? '1' : '0'; + return true; + } + + inline bool type_to_string_converter_impl(const std::string& value, std::string& result, stdstring_type_tag) + { + result = value; + return true; + } + + template + inline bool type_to_string_converter_impl(const std::pair& range, std::string& result, stdstring_range_type_tag) + { + result.assign(range.first,range.second); + return true; + } + + template + inline bool type_to_string_converter_impl(const SinkType&, std::string&, sink_type_tag) + { + //Generic conversion not supported for sinks. Use joins or custom converters. + return false; + } + + template + inline bool type_to_string_converter_impl(const STLContainerType&, std::string&, stl_seq_type_tag) + { + //Generic conversion not supported for stl containers. Use joins or custom converters. + return false; + } + + template + inline std::string type_name() + { + static const std::string s("Unknown"); + return s; + } + + #define strtk_register_type_name(Type) \ + template <> inline std::string type_name() { static const std::string s(#Type); return s; } + + strtk_register_type_name(signed char) + strtk_register_type_name(unsigned char) + strtk_register_type_name(short) + strtk_register_type_name(int) + strtk_register_type_name(long) + strtk_register_type_name(long long) + strtk_register_type_name(unsigned short) + strtk_register_type_name(unsigned int) + strtk_register_type_name(unsigned long) + strtk_register_type_name(unsigned long long int) + strtk_register_type_name(double) + strtk_register_type_name(float) + strtk_register_type_name(long double) + strtk_register_type_name(std::string) + + #undef strtk_register_type_name + + template + inline std::string type_name(const T&) + { + static const std::string s = type_name(); + return s; + } + + template + inline std::string type_name(const std::pair& p) + { + static const std::string s = std::string("std::pair<" + + type_name(p.first) + + "," + + type_name(p.second) + + ">"); + return s; + } + + template + inline std::size_t type_length() + { + return numeric::length; + } + + template + inline std::size_t type_length(const T&) + { + return type_length(); + } + + inline std::size_t type_length(const std::string& s) + { + return s.size(); + } + + template + inline std::size_t type_length(const std::pair&) + { + return type_length() + type_length(); + } + + } // namespace details + + template + inline std::string type_name(const T& t) + { + static const std::string s = details::type_name(t); + return s; + } + + template + inline std::string type_name(const T(&)[N]) + { + static const std::string s = details::type_name() + + std::string("[") + type_to_string(N) + std::string("]"); + return s; + } + + template + inline std::string type_name(const std::pair& p) + { + static const std::string s = std::string("std::pair<" + + type_name(p.first) + + "," + + type_name(p.second) + + ">"); + return s; + } + + #define strtk_register_sequence_type_name(Type) \ + template \ + inline std::string type_name(const Type&) \ + { \ + static const std::string s = std::string(#Type) + std::string("<" + details::type_name() + ">");\ + return s; \ + } \ + + #define strtk_register_set_type_name(Type) \ + template \ + inline std::string type_name(const Type&) \ + { \ + static const std::string s = std::string(#Type) + std::string("<" + details::type_name() + ">");\ + return s; \ + } \ + + strtk_register_sequence_type_name(std::vector) + strtk_register_sequence_type_name(std::deque) + strtk_register_sequence_type_name(std::list) + strtk_register_set_type_name(std::set) + strtk_register_set_type_name(std::multiset) + + template + inline std::size_t type_length() + { + return details::type_length(); + } + + template + inline std::size_t type_length(const T&) + { + return type_length(); + } + + class ext_string + { + public: + + explicit ext_string() + {} + + explicit ext_string(const std::string& s) + : s_(s) + {} + + explicit ext_string(const char* s) + : s_(s) + {} + + explicit ext_string(const range::adapter& r) + : s_(r.begin(),r.end()) + {} + + ext_string(const ext_string& es) + : s_(es.s_) + {} + + template + inline ext_string& operator << (const T& t) + { + s_ += type_to_string(t); + return (*this); + } + + inline operator std::string () const + { + return s_; + } + + inline std::string clone() const + { + return s_; + } + + inline const std::string& as_string() const + { + return s_; + } + + inline std::string& as_string() + { + return s_; + } + + template + inline T as_type() const + { + return string_to_type_converter(s_); + } + + template + inline bool as_type(T& t) const + { + return string_to_type_converter(s_,t); + } + + inline bool imatch(const std::string& s) const + { + return strtk::imatch(s_,s); + } + + inline bool imatch(const ext_string& es) const + { + return strtk::imatch(s_,es.s_); + } + + inline ext_string& to_lowercase() + { + convert_to_lowercase(s_); + return (*this); + } + + inline ext_string& to_uppercase() + { + convert_to_uppercase(s_); + return (*this); + } + + template + inline ext_string& remove_leading(const Predicate& p) + { + if (s_.empty()) return (*this); + strtk::remove_leading(p,s_); + return (*this); + } + + inline ext_string& remove_leading(const std::string& removal_set) + { + if (removal_set.empty()) + return (*this); + else if (1 == removal_set.size()) + strtk::remove_leading(single_delimiter_predicate(removal_set[0]),s_); + else + strtk::remove_leading(multiple_char_delimiter_predicate(removal_set),s_); + return (*this); + } + + template + inline ext_string& remove_trailing(const Predicate& p) + { + if (s_.empty()) return (*this); + strtk::remove_trailing(p,s_); + return (*this); + } + + inline ext_string& remove_trailing(const std::string& removal_set) + { + if (removal_set.empty()) + return (*this); + else if (1 == removal_set.size()) + strtk::remove_trailing(single_delimiter_predicate(removal_set[0]),s_); + else + strtk::remove_trailing(multiple_char_delimiter_predicate(removal_set),s_); + return (*this); + } + + template + inline ext_string& operator += (const T& t) + { + s_.append(type_to_string(t)); + return (*this); + } + + inline ext_string& operator -= (const std::string& pattern) + { + replace(pattern,""); + return (*this); + } + + inline ext_string& operator *= (const std::size_t& n) + { + strtk::replicate_inplace(n,s_); + return (*this); + } + + inline void replace(const std::string& pattern, const std::string& replace_pattern) + { + std::string result; + result.reserve(s_.size()); + strtk::replace_pattern(s_,pattern,replace_pattern,result); + s_.assign(result); + } + + template + inline std::size_t split(const DelimiterPredicate& p, + OutputIterator out, + const split_options::type split_option = split_options::default_mode) const + { + return strtk::split(p,s_,out,split_option); + } + + template class Sequence> + inline std::size_t split(const DelimiterPredicate& p, + Sequence& seq, + const split_options::type split_option = split_options::default_mode) const + { + return strtk::split(p,s_,range_to_type_back_inserter(seq),split_option); + } + + template + inline std::size_t split_n(const DelimiterPredicate& p, + const std::size_t& n, + OutputIterator out, + const split_options::type split_option = split_options::default_mode) const + { + return strtk::split_n(p,s_,n,out,split_option); + } + + template class Sequence> + inline std::size_t split_n(const DelimiterPredicate& p, + const std::size_t& n, + Sequence& seq, + const split_options::type split_option = split_options::default_mode) const + { + return strtk::split_n(p,s_,n,range_to_type_back_inserter(seq),split_option); + } + + template class Sequence> + inline std::size_t parse(const std::string& delimiters, Sequence& seq) const + { + return strtk::parse(s_,delimiters,seq); + } + + template class Sequence> + inline std::size_t parse(const char* delimiters, Sequence& seq) const + { + return parse(std::string(delimiters),seq); + } + + friend inline ext_string operator * (const std::size_t& n, const ext_string& s); + friend inline ext_string operator * (const ext_string& s, const std::size_t& n); + + template + friend inline ext_string operator + (const ext_string& s, const T& t); + + template + friend inline ext_string operator + (const T& t, const ext_string& s); + + friend inline ext_string operator - (const ext_string& s, const std::string& pattern); + friend inline ext_string operator - (const ext_string& s, const char* pattern); + friend inline ext_string operator - (const ext_string& s, const ext_string& pattern); + + static inline ext_string all_digits() + { + static const ext_string digits("0123456789"); + return digits; + } + + static inline ext_string all_letters() + { + static const ext_string letters("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + return letters; + } + + static inline ext_string all_lowercase_letters() + { + static const ext_string letters("abcdefghijklmnopqrstuvwxyz"); + return letters; + } + + static inline ext_string all_uppercase_letters() + { + static const ext_string letters("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + return letters; + } + + static inline ext_string all_chars() + { + ext_string s; + s.as_string().resize(256); + strtk::iota(s.as_string().begin(), + s.as_string().end(), + static_cast(0x00)); + return s; + } + + private: + + std::string s_; + }; + + inline ext_string operator * (const std::size_t& n, const ext_string& s) + { + return ext_string(replicate(n, s.s_)); + } + + inline ext_string operator * (const ext_string& s, const std::size_t& n) + { + return ext_string(replicate(n, s.s_)); + } + + template + inline ext_string operator + (const ext_string& s, const T& t) + { + return ext_string(s.s_ + type_to_string(t)); + } + + template + inline ext_string operator + (const T& t, const ext_string& s) + { + return ext_string(type_to_string(t) + s.s_); + } + + inline ext_string operator - (const ext_string& s, const std::string& pattern) + { + std::string tmp; + tmp.reserve(s.s_.size()); + remove_pattern(s,pattern,tmp); + return ext_string(tmp); + } + + inline ext_string operator - (const ext_string& s, const char* pattern) + { + return s - std::string(pattern); + } + + inline ext_string operator - (const ext_string& s, const ext_string& pattern) + { + return s - std::string(pattern.as_string()); + } + + static inline std::ostream& operator<<(std::ostream& os, const ext_string& es) + { + return (os << es.as_string()); + } + + namespace fileio + { + + inline bool file_exists(const std::string& file_name) + { + std::ifstream file(file_name.c_str(), std::ios::binary); + return ((!file) ? false : true); + } + + inline std::size_t file_size(const std::string& file_name) + { + std::ifstream file(file_name.c_str(),std::ios::binary); + if (!file) return 0; + file.seekg (0, std::ios::end); + return static_cast(file.tellg()); + } + + inline bool load_file(const std::string& file_name, char* buffer, std::size_t buffer_size) + { + std::ifstream in_stream(file_name.c_str(),std::ios::binary); + if (!in_stream) return false; + in_stream.read(buffer,static_cast(buffer_size)); + in_stream.close(); + return true; + } + + inline bool load_file(const std::string& file_name, std::string& buffer) + { + buffer.resize(file_size(file_name)); + return load_file(file_name,const_cast(buffer.data()),buffer.size()); + } + + inline bool write_file(const std::string& file_name, char* buffer, const std::size_t& buffer_size) + { + std::ofstream out_stream(file_name.c_str(),std::ios::binary); + if (!out_stream) return false; + out_stream.write(buffer,static_cast(buffer_size)); + out_stream.close(); + return true; + } + + inline bool write_file(const std::string& file_name, const std::string& buffer) + { + return write_file(file_name,const_cast(buffer.data()),buffer.size()); + } + + inline bool copy_file(const std::string& src_file_name, const std::string& dest_file_name) + { + std::ifstream src_file(src_file_name.c_str(),std::ios::binary); + std::ofstream dest_file(dest_file_name.c_str(),std::ios::binary); + if (!src_file) return false; + if (!dest_file) return false; + + static const std::size_t block_size = 16 * one_kilobyte; + char buffer[block_size]; + + std::size_t remaining_bytes = file_size(src_file_name); + + while (remaining_bytes >= block_size) + { + src_file.read(&buffer[0],static_cast(block_size)); + dest_file.write(&buffer[0],static_cast(block_size)); + remaining_bytes -= block_size; + } + + if (remaining_bytes > 0) + { + src_file.read(&buffer[0],static_cast(remaining_bytes)); + dest_file.write(&buffer[0],static_cast(remaining_bytes)); + remaining_bytes = 0; + } + + src_file.close(); + dest_file.close(); + return true; + } + + inline bool concatenate(const std::string& file_name1, + const std::string& file_name2, + const std::string& output_file_name) + { + std::ifstream file1(file_name1.c_str(),std::ios::binary); + std::ifstream file2(file_name2.c_str(),std::ios::binary); + std::ofstream out_file(output_file_name.c_str(),std::ios::binary); + + if (!file1 || !file2 || !out_file) return false; + + static const std::size_t block_size = 16 * one_kilobyte; + char buffer[block_size]; + unsigned int round = 0; + std::size_t remaining_bytes = 0; + + while (round < 2) + { + std::ifstream& input_stream = ((0 == round) ? file1 : file2); + remaining_bytes = ((0 == round) ? file_size(file_name1) : file_size(file_name2)); + + while (remaining_bytes >= block_size) + { + input_stream.read(&buffer[0],static_cast(block_size)); + out_file.write(&buffer[0],static_cast(block_size)); + remaining_bytes -= block_size; + } + + if (remaining_bytes > 0) + { + input_stream.read(&buffer[0],static_cast(remaining_bytes)); + out_file.write(&buffer[0],static_cast(remaining_bytes)); + remaining_bytes = 0; + } + + input_stream.close(); + ++round; + } + out_file.close(); + return true; + } + + inline bool files_identical(const std::string& file_name1, const std::string& file_name2) + { + std::ifstream file1(file_name1.c_str(),std::ios::binary); + std::ifstream file2(file_name2.c_str(),std::ios::binary); + if (!file1) return false; + if (!file2) return false; + if (file_size(file_name1) != file_size(file_name2)) return false; + + static const std::size_t block_size = 16 * one_kilobyte; + char buffer1[block_size]; + char buffer2[block_size]; + + std::size_t remaining_bytes = file_size(file_name1); + + while (remaining_bytes >= block_size) + { + file1.read(&buffer1[0],static_cast(block_size)); + file2.read(&buffer2[0],static_cast(block_size)); + if (0 != std::memcmp(buffer1,buffer2,block_size)) + return false; + remaining_bytes -= block_size; + } + + if (remaining_bytes > 0) + { + file1.read(&buffer1[0],static_cast(remaining_bytes)); + file2.read(&buffer2[0],static_cast(remaining_bytes)); + if (0 != std::memcmp(buffer1,buffer2,remaining_bytes)) + return false; + remaining_bytes = 0; + } + + file1.close(); + file2.close(); + + return true; + } + + namespace details + { + template + inline bool read_pod_proxy(std::ifstream& stream, T& t) + { + return (false == stream.read(reinterpret_cast(&t), + static_cast(sizeof(T))).fail()); + } + + template + inline bool write_pod_proxy(std::ofstream& stream, const T& t) + { + return (false == stream.write(reinterpret_cast(&t), + static_cast(sizeof(T))).fail()); + } + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10) + { + return details::read_pod_proxy(stream, t1) && + details::read_pod_proxy(stream, t2) && + details::read_pod_proxy(stream, t3) && + details::read_pod_proxy(stream, t4) && + details::read_pod_proxy(stream, t5) && + details::read_pod_proxy(stream, t6) && + details::read_pod_proxy(stream, t7) && + details::read_pod_proxy(stream, t8) && + details::read_pod_proxy(stream, t9) && + details::read_pod_proxy(stream,t10); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3) && + details::read_pod_proxy(stream,t4) && + details::read_pod_proxy(stream,t5) && + details::read_pod_proxy(stream,t6) && + details::read_pod_proxy(stream,t7) && + details::read_pod_proxy(stream,t8) && + details::read_pod_proxy(stream,t9); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3) && + details::read_pod_proxy(stream,t4) && + details::read_pod_proxy(stream,t5) && + details::read_pod_proxy(stream,t6) && + details::read_pod_proxy(stream,t7) && + details::read_pod_proxy(stream,t8); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3) && + details::read_pod_proxy(stream,t4) && + details::read_pod_proxy(stream,t5) && + details::read_pod_proxy(stream,t6) && + details::read_pod_proxy(stream,t7); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3) && + details::read_pod_proxy(stream,t4) && + details::read_pod_proxy(stream,t5) && + details::read_pod_proxy(stream,t6); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3) && + details::read_pod_proxy(stream,t4) && + details::read_pod_proxy(stream,t5); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3, T4& t4) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3) && + details::read_pod_proxy(stream,t4); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2, T3& t3) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2) && + details::read_pod_proxy(stream,t3); + } + + template + inline bool read_pod(std::ifstream& stream, + T1& t1, T2& t2) + { + return details::read_pod_proxy(stream,t1) && + details::read_pod_proxy(stream,t2); + } + + template + inline bool read_pod(std::ifstream& stream, T& t) + { + return details::read_pod_proxy(stream,t); + } + + template + inline bool read_pod(std::ifstream& stream, T (&t)[N]) + { + return (false != stream.read(reinterpret_cast(&t[0]),sizeof(T) * N).fail()); + } + + template class Sequence> + inline bool read_pod(std::ifstream& stream, + const std::size_t& count, + Sequence& sequence) + { + T t; + for (std::size_t i = 0; i < count; ++i) + { + if (details::read_pod_proxy(stream,t)) + sequence.push_back(t); + else + return false; + } + return true; + } + + template + inline bool read_pod(std::ifstream& stream, + const std::size_t& count, + std::set& set) + { + T t; + for (std::size_t i = 0; i < count; ++i) + { + if (details::read_pod_proxy(stream,t)) + set.insert(t); + else + return false; + } + return true; + } + + template + inline bool read_pod(std::ifstream& stream, + const std::size_t& count, + std::multiset& multiset) + { + T t; + for (std::size_t i = 0; i < count; ++i) + { + if (details::read_pod_proxy(stream,t)) + multiset.insert(t); + else + return false; + } + return true; + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10) + { + return details::write_pod_proxy(stream, t1) && + details::write_pod_proxy(stream, t2) && + details::write_pod_proxy(stream, t3) && + details::write_pod_proxy(stream, t4) && + details::write_pod_proxy(stream, t5) && + details::write_pod_proxy(stream, t6) && + details::write_pod_proxy(stream, t7) && + details::write_pod_proxy(stream, t8) && + details::write_pod_proxy(stream, t9) && + details::write_pod_proxy(stream,t10); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3) && + details::write_pod_proxy(stream,t4) && + details::write_pod_proxy(stream,t5) && + details::write_pod_proxy(stream,t6) && + details::write_pod_proxy(stream,t7) && + details::write_pod_proxy(stream,t8) && + details::write_pod_proxy(stream,t9); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3) && + details::write_pod_proxy(stream,t4) && + details::write_pod_proxy(stream,t5) && + details::write_pod_proxy(stream,t6) && + details::write_pod_proxy(stream,t7) && + details::write_pod_proxy(stream,t8); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3) && + details::write_pod_proxy(stream,t4) && + details::write_pod_proxy(stream,t5) && + details::write_pod_proxy(stream,t6) && + details::write_pod_proxy(stream,t7); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3) && + details::write_pod_proxy(stream,t4) && + details::write_pod_proxy(stream,t5) && + details::write_pod_proxy(stream,t6); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3) && + details::write_pod_proxy(stream,t4) && + details::write_pod_proxy(stream,t5); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3) && + details::write_pod_proxy(stream,t4); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2, const T3& t3) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2) && + details::write_pod_proxy(stream,t3); + } + + template + inline bool write_pod(std::ofstream& stream, + const T1& t1, const T2& t2) + { + return details::write_pod_proxy(stream,t1) && + details::write_pod_proxy(stream,t2); + } + + template + inline bool write_pod(std::ofstream& stream, const T& t) + { + return details::write_pod_proxy(stream,t); + } + + template + inline bool write_pod(std::ofstream& stream, T (&t)[N]) + { + return (false != stream.write(reinterpret_cast(&t[0]),sizeof(T) * N).fail()); + } + + template class Sequence> + inline bool write_pod(std::ofstream& stream, + const Sequence& sequence) + { + typename Sequence::iterator itr = sequence.begin(); + typename Sequence::iterator end = sequence.end(); + while (end != itr) + { + if (details::write_pod_proxy(stream,*itr)) + ++itr; + else + return false; + } + } + + template + inline bool write_pod(std::ofstream& stream, + const std::set& set) + { + typename std::set::iterator itr = set.begin(); + typename std::set::iterator end = set.end(); + while (end != itr) + { + if (details::write_pod_proxy(stream,*itr)) + ++itr; + else + return false; + } + } + + template + inline bool write_pod(std::ofstream& stream, + const std::multiset& multiset) + { + typename std::multiset::iterator itr = multiset.begin(); + typename std::multiset::iterator end = multiset.end(); + while (end != itr) + { + if (details::write_pod_proxy(stream,*itr)) + ++itr; + else + return false; + } + } + + inline bool read_at_offset(std::ifstream& stream, + const std::size_t& offset, + char* buffer, + const std::size_t& buffer_size) + { + if (!stream) return false; + stream.seekg(static_cast(offset),std::ios_base::beg); + if (stream.fail()) return false; + stream.read(buffer,static_cast(buffer_size)); + if (stream.fail()) return false; + stream.close(); + return true; + } + + inline bool read_at_offset(const std::string& file_name, + const std::size_t& offset, + char* buffer, + const std::size_t& buffer_size) + { + std::ifstream stream(file_name.c_str(), std::ios::in | std::ios::binary); + if (!stream) return false; + return read_at_offset(stream,offset,buffer,buffer_size); + } + + inline bool read_at_offset(const std::string& file_name, + const std::size_t& offset, + std::string& buffer, + const std::size_t& buffer_size) + { + std::ifstream stream(file_name.c_str(), std::ios::in | std::ios::binary); + if (!stream) return false; + buffer.resize(buffer_size); + return read_at_offset(stream, + offset, + const_cast(buffer.data()), + buffer_size); + } + + } // namespace fileio + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10, T11& t11, T12& t12) + { + t1 = (*reinterpret_cast< T1*>(data)); data += sizeof( T1); + t2 = (*reinterpret_cast< T2*>(data)); data += sizeof( T2); + t3 = (*reinterpret_cast< T3*>(data)); data += sizeof( T3); + t4 = (*reinterpret_cast< T4*>(data)); data += sizeof( T4); + t5 = (*reinterpret_cast< T5*>(data)); data += sizeof( T5); + t6 = (*reinterpret_cast< T6*>(data)); data += sizeof( T6); + t7 = (*reinterpret_cast< T7*>(data)); data += sizeof( T7); + t8 = (*reinterpret_cast< T8*>(data)); data += sizeof( T8); + t9 = (*reinterpret_cast< T9*>(data)); data += sizeof( T9); + t10 = (*reinterpret_cast(data)); data += sizeof(T10); + t11 = (*reinterpret_cast(data)); data += sizeof(T11); + t12 = (*reinterpret_cast(data)); data += sizeof(T12); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10, T11& t11) + { + t1 = (*reinterpret_cast< T1*>(data)); data += sizeof( T1); + t2 = (*reinterpret_cast< T2*>(data)); data += sizeof( T2); + t3 = (*reinterpret_cast< T3*>(data)); data += sizeof( T3); + t4 = (*reinterpret_cast< T4*>(data)); data += sizeof( T4); + t5 = (*reinterpret_cast< T5*>(data)); data += sizeof( T5); + t6 = (*reinterpret_cast< T6*>(data)); data += sizeof( T6); + t7 = (*reinterpret_cast< T7*>(data)); data += sizeof( T7); + t8 = (*reinterpret_cast< T8*>(data)); data += sizeof( T8); + t9 = (*reinterpret_cast< T9*>(data)); data += sizeof( T9); + t10 = (*reinterpret_cast(data)); data += sizeof(T10); + t11 = (*reinterpret_cast(data)); data += sizeof(T11); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9, T10& t10) + { + t1 = (*reinterpret_cast< T1*>(data)); data += sizeof( T1); + t2 = (*reinterpret_cast< T2*>(data)); data += sizeof( T2); + t3 = (*reinterpret_cast< T3*>(data)); data += sizeof( T3); + t4 = (*reinterpret_cast< T4*>(data)); data += sizeof( T4); + t5 = (*reinterpret_cast< T5*>(data)); data += sizeof( T5); + t6 = (*reinterpret_cast< T6*>(data)); data += sizeof( T6); + t7 = (*reinterpret_cast< T7*>(data)); data += sizeof( T7); + t8 = (*reinterpret_cast< T8*>(data)); data += sizeof( T8); + t9 = (*reinterpret_cast< T9*>(data)); data += sizeof( T9); + t10 = (*reinterpret_cast(data)); data += sizeof(T10); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + t4 = (*reinterpret_cast(data)); data += sizeof(T4); + t5 = (*reinterpret_cast(data)); data += sizeof(T5); + t6 = (*reinterpret_cast(data)); data += sizeof(T6); + t7 = (*reinterpret_cast(data)); data += sizeof(T7); + t8 = (*reinterpret_cast(data)); data += sizeof(T8); + t9 = (*reinterpret_cast(data)); data += sizeof(T9); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + t4 = (*reinterpret_cast(data)); data += sizeof(T4); + t5 = (*reinterpret_cast(data)); data += sizeof(T5); + t6 = (*reinterpret_cast(data)); data += sizeof(T6); + t7 = (*reinterpret_cast(data)); data += sizeof(T7); + t8 = (*reinterpret_cast(data)); data += sizeof(T8); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + t4 = (*reinterpret_cast(data)); data += sizeof(T4); + t5 = (*reinterpret_cast(data)); data += sizeof(T5); + t6 = (*reinterpret_cast(data)); data += sizeof(T6); + t7 = (*reinterpret_cast(data)); data += sizeof(T7); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + t4 = (*reinterpret_cast(data)); data += sizeof(T4); + t5 = (*reinterpret_cast(data)); data += sizeof(T5); + t6 = (*reinterpret_cast(data)); data += sizeof(T6); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + t4 = (*reinterpret_cast(data)); data += sizeof(T4); + t5 = (*reinterpret_cast(data)); data += sizeof(T5); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3, T4& t4) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + t4 = (*reinterpret_cast(data)); data += sizeof(T4); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2, T3& t3) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + t3 = (*reinterpret_cast(data)); data += sizeof(T3); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1, T2& t2) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + t2 = (*reinterpret_cast(data)); data += sizeof(T2); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, + T1& t1) + { + t1 = (*reinterpret_cast(data)); data += sizeof(T1); + return data; + } + + template + inline unsigned char* read_pod(unsigned char* data, T (&t)[N]) + { + T* begin = reinterpret_cast(data); + T* end = begin + N; + std::copy(begin,end,&t[0]); + return data + (N * sizeof(T)); + } + + template class Sequence> + inline unsigned char* read_pod(unsigned char* data, + const std::size_t& n, + const Sequence& sequence) + { + T* ptr = reinterpret_cast(data); + std::copy(ptr, ptr + n, std::back_inserter(sequence)); + return data + (sequence.size() * sizeof(T)); + } + + template + inline unsigned char* read_pod(unsigned char* data, + const std::size_t& n, + const std::set& set) + { + T* ptr = reinterpret_cast(data); + std::copy(ptr, ptr + n, std::inserter(set,set.begin())); + return data + (set.size() * sizeof(T)); + } + + template + inline unsigned char* read_pod(unsigned char* data, + const std::size_t& n, + const std::multiset& multiset) + { + T* ptr = reinterpret_cast(data); + std::copy(ptr, ptr + n, std::inserter(multiset,multiset.begin())); + return data + (multiset.size() * sizeof(T)); + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10, const T11& t11, const T12& t12) + { + (*reinterpret_cast< T1*>(data)) = t1; data += sizeof( T1); + (*reinterpret_cast< T2*>(data)) = t2; data += sizeof( T2); + (*reinterpret_cast< T3*>(data)) = t3; data += sizeof( T3); + (*reinterpret_cast< T4*>(data)) = t4; data += sizeof( T4); + (*reinterpret_cast< T5*>(data)) = t5; data += sizeof( T5); + (*reinterpret_cast< T6*>(data)) = t6; data += sizeof( T6); + (*reinterpret_cast< T7*>(data)) = t7; data += sizeof( T7); + (*reinterpret_cast< T8*>(data)) = t8; data += sizeof( T8); + (*reinterpret_cast< T9*>(data)) = t9; data += sizeof( T9); + (*reinterpret_cast(data)) = t10; data += sizeof(T10); + (*reinterpret_cast(data)) = t11; data += sizeof(T11); + (*reinterpret_cast(data)) = t12; data += sizeof(T12); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10, const T11& t11) + { + (*reinterpret_cast< T1*>(data)) = t1; data += sizeof( T1); + (*reinterpret_cast< T2*>(data)) = t2; data += sizeof( T2); + (*reinterpret_cast< T3*>(data)) = t3; data += sizeof( T3); + (*reinterpret_cast< T4*>(data)) = t4; data += sizeof( T4); + (*reinterpret_cast< T5*>(data)) = t5; data += sizeof( T5); + (*reinterpret_cast< T6*>(data)) = t6; data += sizeof( T6); + (*reinterpret_cast< T7*>(data)) = t7; data += sizeof( T7); + (*reinterpret_cast< T8*>(data)) = t8; data += sizeof( T8); + (*reinterpret_cast< T9*>(data)) = t9; data += sizeof( T9); + (*reinterpret_cast(data)) = t10; data += sizeof(T10); + (*reinterpret_cast(data)) = t11; data += sizeof(T11); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9, const T10& t10) + { + (*reinterpret_cast< T1*>(data)) = t1; data += sizeof( T1); + (*reinterpret_cast< T2*>(data)) = t2; data += sizeof( T2); + (*reinterpret_cast< T3*>(data)) = t3; data += sizeof( T3); + (*reinterpret_cast< T4*>(data)) = t4; data += sizeof( T4); + (*reinterpret_cast< T5*>(data)) = t5; data += sizeof( T5); + (*reinterpret_cast< T6*>(data)) = t6; data += sizeof( T6); + (*reinterpret_cast< T7*>(data)) = t7; data += sizeof( T7); + (*reinterpret_cast< T8*>(data)) = t8; data += sizeof( T8); + (*reinterpret_cast< T9*>(data)) = t9; data += sizeof( T9); + (*reinterpret_cast(data)) = t10; data += sizeof(T10); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8, + const T9& t9) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + (*reinterpret_cast(data)) = t4; data += sizeof(T4); + (*reinterpret_cast(data)) = t5; data += sizeof(T5); + (*reinterpret_cast(data)) = t6; data += sizeof(T6); + (*reinterpret_cast(data)) = t7; data += sizeof(T7); + (*reinterpret_cast(data)) = t8; data += sizeof(T8); + (*reinterpret_cast(data)) = t9; data += sizeof(T9); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + (*reinterpret_cast(data)) = t4; data += sizeof(T4); + (*reinterpret_cast(data)) = t5; data += sizeof(T5); + (*reinterpret_cast(data)) = t6; data += sizeof(T6); + (*reinterpret_cast(data)) = t7; data += sizeof(T7); + (*reinterpret_cast(data)) = t8; data += sizeof(T8); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + (*reinterpret_cast(data)) = t4; data += sizeof(T4); + (*reinterpret_cast(data)) = t5; data += sizeof(T5); + (*reinterpret_cast(data)) = t6; data += sizeof(T6); + (*reinterpret_cast(data)) = t7; data += sizeof(T7); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + (*reinterpret_cast(data)) = t4; data += sizeof(T4); + (*reinterpret_cast(data)) = t5; data += sizeof(T5); + (*reinterpret_cast(data)) = t6; data += sizeof(T6); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + (*reinterpret_cast(data)) = t4; data += sizeof(T4); + (*reinterpret_cast(data)) = t5; data += sizeof(T5); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + (*reinterpret_cast(data)) = t4; data += sizeof(T4); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2, const T3& t3) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + (*reinterpret_cast(data)) = t3; data += sizeof(T3); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1, const T2& t2) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + (*reinterpret_cast(data)) = t2; data += sizeof(T2); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, + const T1& t1) + { + (*reinterpret_cast(data)) = t1; data += sizeof(T1); + return data; + } + + template + inline unsigned char* write_pod(unsigned char* data, const T (&t)[N]) + { + T* ptr = reinterpret_cast(data); + std::copy(t,t + N,ptr); + return data + (N * sizeof(T)); + } + + template class Sequence> + inline unsigned char* write_pod(unsigned char* data, + const Sequence& sequence) + { + T* ptr = reinterpret_cast(data); + std::copy(sequence.begin(),sequence.end(),ptr); + return data + (sequence.size() * sizeof(T)); + } + + template + inline unsigned char* write_pod(unsigned char* data, + const std::set& set) + { + T* ptr = reinterpret_cast(data); + std::copy(set.begin(),set.end(),ptr); + return data + (set.size() * sizeof(T)); + } + + template + inline unsigned char* write_pod(unsigned char* data, + const std::multiset& multiset) + { + T* ptr = reinterpret_cast(data); + std::copy(multiset.begin(),multiset.end(),ptr); + return data + (multiset.size() * sizeof(T)); + } + + class string_condition + { + private: + + typedef const unsigned char* itr_type; + + inline bool condition_equal(const itr_type begin, const itr_type end) const + { + if (s.size() == static_cast(std::distance(begin,end))) + { + return std::equal(s_begin,s_end,begin); + } + else + return false; + } + + inline bool condition_notequal(const itr_type begin, const itr_type end) const + { + if (s.size() == static_cast(std::distance(begin,end))) + { + return !std::equal(s_begin,s_end,begin); + } + else + return true; + } + + inline bool condition_like(const itr_type begin, const itr_type end) const + { + return match(s_begin,s_end,begin,end,(unsigned char)'*',(unsigned char)'?'); + } + + inline bool condition_begins_with(const itr_type begin, const itr_type end) const + { + if (s.size() == static_cast(std::distance(begin,end))) + { + return strtk::begins_with(s_begin,s_end,begin,end); + } + else + return false; + } + + inline bool condition_ends_with(const itr_type begin, const itr_type end) const + { + if (s.size() == static_cast(std::distance(begin,end))) + { + return strtk::ends_with(s_begin,s_end,begin,end); + } + else + return false; + } + + inline bool condition_within(const itr_type begin, const itr_type end) const + { + if (s.size() <= static_cast(std::distance(begin,end))) + { + return (end != std::search(begin,end,s_begin,s_end)); + } + else + return false; + } + + inline bool condition_notwithin(const itr_type begin, const itr_type end) const + { + if (s.size() <= static_cast(std::distance(begin,end))) + { + return (end == std::search(begin,end,s_begin,s_end)); + } + else + return true; + } + + typedef bool (string_condition::*condition_method)(const itr_type begin, const itr_type end) const; + + public: + + enum condition_type + { + equal = 0, + notequal = 1, + like = 2, + begins_with = 4, + ends_with = 8, + within = 16, + notwithin = 32 + }; + + inline explicit string_condition(condition_type cond_type, const std::string& str) + : cond_type_(cond_type), + s(str), + s_begin(reinterpret_cast(s.data())), + s_end(reinterpret_cast(s.data() + str.size())), + condition_method_(0) + { + switch (cond_type_) + { + case equal : condition_method_ = &string_condition::condition_equal; + break; + case notequal : condition_method_ = &string_condition::condition_notequal; + break; + case like : condition_method_ = &string_condition::condition_like; + break; + case begins_with : condition_method_ = &string_condition::condition_begins_with; + break; + case ends_with : condition_method_ = &string_condition::condition_ends_with; + break; + case within : condition_method_ = &string_condition::condition_within; + break; + case notwithin : condition_method_ = &string_condition::condition_notwithin; + break; + } + } + + template + inline bool operator()(const Iterator begin, const Iterator end) + { + return ((*this).*condition_method_)(begin,end); + } + + inline bool operator()(const std::string& str) + { + return operator()(reinterpret_cast(str.data()), + reinterpret_cast(str.data() + str.size())); + } + + private: + + condition_type cond_type_; + std::string s; + const unsigned char* s_begin; + const unsigned char* s_end; + condition_method condition_method_; + }; + + namespace trie + { + template + class prefix + { + + template ::value_type> + struct node + { + public: + + typedef KeyValue key_value_t; + typedef Value value_t; + + typedef node node_t; + typedef node_t* node_ptr; + typedef const node_ptr const_node_ptr; + + typedef std::vector node_list_t; + typedef typename node_list_t::const_iterator node_list_iterator; + + explicit node(const key_value_t& key_value) + : key_value_(key_value), + value_holder_(false) + {} + + node(const key_value_t& key_value, const value_t& v) + : key_value_(key_value), + value_holder_(true), + value_(v) + {} + + ~node() + { + if (!node_list_.empty()) + { + node_list_iterator itr = node_list_.begin(); + node_list_iterator end = node_list_.end(); + while (end != itr) + { + delete (*itr); + ++itr; + } + } + } + + inline node_ptr get_node(const key_value_t& key_value) + { + if (node_list_.empty()) + return 0; + node_list_iterator itr = node_list_.begin(); + const node_list_iterator end = node_list_.end(); + while (end != itr) + { + if (key_value == (*itr)->key_value_) + return (*itr); + else + ++itr; + } + return 0; + } + + inline void assign_value(const value_t& v) + { + value_ = v; + value_holder_ = true; + } + + inline void add_node(node_ptr n) + { + node_list_.push_back(n); + } + + inline bool value_holder() const + { + return value_holder_; + } + + inline const value_t& value() const + { + return value_; + } + + inline const key_value_t& key() const + { + return key_value_; + } + + private: + + node(const node_t& n); + node_t& operator=(const node_t& n); + + key_value_t key_value_; + bool value_holder_; + value_t value_; + node_list_t node_list_; + }; + + public: + + //typedef KeyIterator key_iterator_t; + typedef typename std::iterator_traits::value_type key_value_t; + typedef ValueType value_t; + + typedef node node_t; + typedef node_t* node_ptr; + + prefix() + : head_(0) + {} + + template + inline void insert(const key_iterator_t begin, + const key_iterator_t end, + const value_t& v) + { + if (0 == std::distance(begin,end)) + return; + + key_iterator_t itr = begin; + key_value_t key = (*itr); + node_ptr parent = 0; + node_ptr next_node = 0; + node_ptr n = head_ = ((0 == head_) ? new node_t(*itr) : head_); + + while (end != itr) + { + key = (*itr); + if (0 == (next_node = n->get_node(key))) + { + n->add_node(next_node = new node_t(key)); + } + parent = n; + n = next_node; + ++itr; + } + + parent->assign_value(v); + } + + template + inline bool find(const key_iterator_t begin, + const key_iterator_t end, + value_t& v) const + { + if ((0 == head_) || (0 == std::distance(begin,end))) + return false; + key_iterator_t itr = begin; + node_ptr parent = head_; + node_ptr n = head_; + while (end != itr) + { + node_ptr next_node = n->get_node(*itr); + if (0 == next_node) + return false; + parent = n; + n = next_node; + ++itr; + } + if (!parent->value_holder()) + return false; + v = parent->value(); + return true; + } + + template + inline bool find_prefix(const key_iterator_t begin, const key_iterator_t end) const + { + if ((0 == head_) || (0 == std::distance(begin,end))) + return false; + + key_iterator_t itr = begin; + node_ptr n = head_; + + while (end != itr) + { + if (0 == (n = n->get_node(*itr))) + return false; + ++itr; + } + + return true; + } + + ~prefix() + { + delete head_; + } + + private: + + node_ptr head_; + }; + + template + inline void insert(prefix& trie, + const std::string& key, + const Value& value = Value(0)) + { + trie.insert(key.begin(),key.end(),value); + } + + template + inline void insert(prefix& trie, + const char* key, + const Value& value = Value(0)) + { + trie.insert(std::string(key),value); + } + + template + inline bool find(prefix& trie, + const std::string& key, + Value& v) + { + return trie.find(key.begin(),key.end(),v); + } + + template + inline bool find(prefix& trie, + const char* key, + Value& v) + { + return trie.find_prefix(trie,std::string(key),v); + } + + template + inline bool find_prefix(prefix& trie, + const std::string& key) + { + return trie.find_prefix(key.begin(),key.end()); + } + + template + inline bool find_prefix(prefix& trie, + const char* key) + { + return trie.find_prefix(trie,std::string(key)); + } + + } // namespace trie + + template + struct prefix_trie + { + typedef trie::prefix type; + typedef trie::prefix std_string; + typedef trie::prefix char_ptr; + typedef trie::prefix const_char_ptr; + typedef trie::prefix uchar_ptr; + typedef trie::prefix const_uchar_ptr; + }; + + namespace bloom + { + + static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned) + static const unsigned char bit_mask[bits_per_char] = { + 0x01, //00000001 + 0x02, //00000010 + 0x04, //00000100 + 0x08, //00001000 + 0x10, //00010000 + 0x20, //00100000 + 0x40, //01000000 + 0x80 //10000000 + }; + + class parameters + { + public: + + parameters() + : minimum_size(1), + maximum_size(std::numeric_limits::max()), + minimum_number_of_hashes(1), + maximum_number_of_hashes(std::numeric_limits::max()), + projected_element_count(10000), + false_positive_probability(1.0 / projected_element_count), + random_seed(0xA5A5A5A55A5A5A5AULL) + {} + + virtual ~parameters() + {} + + inline bool operator!() + { + return (minimum_size > maximum_size) || + (minimum_number_of_hashes > maximum_number_of_hashes) || + (minimum_number_of_hashes < 1) || + (0 == maximum_number_of_hashes) || + (0 == projected_element_count) || + (false_positive_probability < 0.0) || + (std::numeric_limits::infinity() == std::abs(false_positive_probability)) || + (0 == random_seed) || + (0xFFFFFFFFFFFFFFFFULL == random_seed); + } + + //Allowed min/max size of the bloom filter in bits + unsigned long long int minimum_size; + unsigned long long int maximum_size; + + //Allowed min/max number of hash functions + unsigned int minimum_number_of_hashes; + unsigned int maximum_number_of_hashes; + + //The approximate number of elements to be inserted + //into the bloom filter, should be within one order + //of magnitude. The default is 10000. + unsigned long long int projected_element_count; + + //The approximate false positive probability expected + //from the bloom filter. The default is the reciprocal + //of the projected_element_count. + double false_positive_probability; + + unsigned long long int random_seed; + + inline bool operator()(strtk::binary::reader& reader) + { + return reader(minimum_size) && + reader(maximum_size) && + reader(minimum_number_of_hashes) && + reader(maximum_number_of_hashes) && + reader(projected_element_count) && + reader(false_positive_probability) && + reader(random_seed); + } + + inline bool operator()(strtk::binary::writer& writer) + { + return writer(minimum_size) && + writer(maximum_size) && + writer(minimum_number_of_hashes) && + writer(maximum_number_of_hashes) && + writer(projected_element_count) && + writer(false_positive_probability) && + writer(random_seed); + } + + struct optimal_parameters_t + { + optimal_parameters_t() + : number_of_hashes(0), + table_size(0) + {} + + unsigned int number_of_hashes; + unsigned long long int table_size; + }; + + optimal_parameters_t optimal_parameters; + + virtual bool compute_optimal_parameters() + { + /* + Note: + The following will attempt to find the number of hash functions + and minimum amount of storage bits required to construct a bloom + filter consistent with the user defined false positive probability + and estimated element insertion count. + */ + + if (!(*this)) + return false; + + double min_m = std::numeric_limits::infinity(); + double min_k = 0.0; + double curr_m = 0.0; + double k = 1.0; + + while (k < 1000.0) + { + double numerator = -k * projected_element_count; + double denominator = std::log(1.0 - std::pow(false_positive_probability, 1.0 / k)); + curr_m = numerator / denominator; + if (curr_m < min_m) + { + min_m = curr_m; + min_k = k; + } + k += 1.0; + } + + optimal_parameters_t& optp = optimal_parameters; + + optp.number_of_hashes = static_cast(min_k); + optp.table_size = static_cast(min_m); + optp.table_size += (((optp.table_size % bits_per_char) != 0) ? (bits_per_char - (optp.table_size % bits_per_char)) : 0); + + if (optp.number_of_hashes < minimum_number_of_hashes) + optp.number_of_hashes = minimum_number_of_hashes; + else if (optp.number_of_hashes > maximum_number_of_hashes) + optp.number_of_hashes = maximum_number_of_hashes; + + if (optp.table_size < minimum_size) + optp.table_size = minimum_size; + else if (optp.table_size > maximum_size) + optp.table_size = maximum_size; + + return true; + } + + }; + + class filter + { + protected: + + typedef unsigned int bloom_type; + typedef unsigned char cell_type; + + public: + + filter() + : bit_table_(0), + salt_count_(0), + table_size_(0), + raw_table_size_(0), + projected_element_count_(0), + inserted_element_count_(0), + random_seed_(0), + desired_false_positive_probability_(0.0) + {} + + filter(const parameters& p) + : bit_table_(0), + projected_element_count_(p.projected_element_count), + inserted_element_count_(0), + random_seed_((p.random_seed * 0xA5A5A5A5) + 1), + desired_false_positive_probability_(p.false_positive_probability) + { + salt_count_ = p.optimal_parameters.number_of_hashes; + table_size_ = p.optimal_parameters.table_size; + generate_unique_salt(); + raw_table_size_ = table_size_ / bits_per_char; + bit_table_ = new cell_type[static_cast(raw_table_size_)]; + std::fill_n(bit_table_,raw_table_size_,0x00); + } + + filter(const filter& filter) + { + this->operator=(filter); + } + + inline bool operator == (const filter& f) const + { + if (this != &f) + { + return + (salt_count_ == f.salt_count_) && + (table_size_ == f.table_size_) && + (raw_table_size_ == f.raw_table_size_) && + (projected_element_count_ == f.projected_element_count_) && + (inserted_element_count_ == f.inserted_element_count_) && + (random_seed_ == f.random_seed_) && + (desired_false_positive_probability_ == f.desired_false_positive_probability_) && + (salt_ == f.salt_) && + std::equal(f.bit_table_,f.bit_table_ + raw_table_size_,bit_table_); + } + else + return true; + } + + inline bool operator != (const filter& f) const + { + return !operator==(f); + } + + inline filter& operator = (const filter& f) + { + if (this != &f) + { + salt_count_ = f.salt_count_; + table_size_ = f.table_size_; + raw_table_size_ = f.raw_table_size_; + projected_element_count_ = f.projected_element_count_; + inserted_element_count_ = f.inserted_element_count_; + random_seed_ = f.random_seed_; + desired_false_positive_probability_ = f.desired_false_positive_probability_; + delete[] bit_table_; + bit_table_ = new cell_type[static_cast(raw_table_size_)]; + std::copy(f.bit_table_,f.bit_table_ + raw_table_size_,bit_table_); + salt_ = f.salt_; + } + return *this; + } + + virtual ~filter() + { + delete[] bit_table_; + } + + inline bool operator!() const + { + return (0 == table_size_); + } + + inline void clear() + { + std::fill_n(bit_table_,raw_table_size_,0x00); + inserted_element_count_ = 0; + } + + inline void insert(const unsigned char* key_begin, const std::size_t& length) + { + std::size_t bit_index = 0; + std::size_t bit = 0; + for (std::size_t i = 0; i < salt_.size(); ++i) + { + compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit); + bit_table_[bit_index / bits_per_char] |= bit_mask[bit]; + } + ++inserted_element_count_; + } + + template + inline void insert(const T& t) + { + // Note: T must be a C++ POD type. + insert(reinterpret_cast(&t),sizeof(T)); + } + + inline void insert(const std::string& key) + { + insert(reinterpret_cast(key.data()),key.size()); + } + + inline void insert(const char* data, const std::size_t& length) + { + insert(reinterpret_cast(data),length); + } + + template + inline void insert(const InputIterator begin, const InputIterator end) + { + InputIterator itr = begin; + while (end != itr) + { + insert(*(itr++)); + } + } + + inline virtual bool contains(const unsigned char* key_begin, const std::size_t length) const + { + std::size_t bit_index = 0; + std::size_t bit = 0; + for (std::size_t i = 0; i < salt_.size(); ++i) + { + compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit); + if ((bit_table_[bit_index / bits_per_char] & bit_mask[bit]) != bit_mask[bit]) + { + return false; + } + } + return true; + } + + template + inline bool contains(const T& t) const + { + return contains(reinterpret_cast(&t),static_cast(sizeof(T))); + } + + inline bool contains(const std::string& key) const + { + return contains(reinterpret_cast(key.data()),key.size()); + } + + inline bool contains(const char* data, const std::size_t& length) const + { + return contains(reinterpret_cast(data),length); + } + + template + inline InputIterator contains_all(const InputIterator begin, const InputIterator end) const + { + InputIterator itr = begin; + while (end != itr) + { + if (!contains(*itr)) + { + return itr; + } + ++itr; + } + return end; + } + + template + inline InputIterator contains_none(const InputIterator begin, const InputIterator end) const + { + InputIterator itr = begin; + while (end != itr) + { + if (contains(*itr)) + { + return itr; + } + ++itr; + } + return end; + } + + inline virtual unsigned long long int size() const + { + return table_size_; + } + + inline std::size_t element_count() const + { + return inserted_element_count_; + } + + inline double effective_fpp() const + { + /* + Note: + The effective false positive probability is calculated using the + designated table size and hash function count in conjunction with + the current number of inserted elements - not the user defined + predicated/expected number of inserted elements. + */ + return std::pow(1.0 - std::exp(-1.0 * salt_.size() * inserted_element_count_ / size()), 1.0 * salt_.size()); + } + + inline filter& operator &= (const filter& f) + { + /* intersection */ + if ( + (salt_count_ == f.salt_count_) && + (table_size_ == f.table_size_) && + (random_seed_ == f.random_seed_) + ) + { + for (std::size_t i = 0; i < raw_table_size_; ++i) + { + bit_table_[i] &= f.bit_table_[i]; + } + } + return *this; + } + + inline filter& operator |= (const filter& f) + { + /* union */ + if ( + (salt_count_ == f.salt_count_) && + (table_size_ == f.table_size_) && + (random_seed_ == f.random_seed_) + ) + { + for (std::size_t i = 0; i < raw_table_size_; ++i) + { + bit_table_[i] |= f.bit_table_[i]; + } + } + return *this; + } + + inline filter& operator ^= (const filter& f) + { + /* difference */ + if ( + (salt_count_ == f.salt_count_) && + (table_size_ == f.table_size_) && + (random_seed_ == f.random_seed_) + ) + { + for (std::size_t i = 0; i < raw_table_size_; ++i) + { + bit_table_[i] ^= f.bit_table_[i]; + } + } + return *this; + } + + inline const cell_type* table() const + { + return bit_table_; + } + + inline bool write_to_file(const std::string& file_name) const + { + if (0 == table_size_) + return false; + const std::size_t buffer_size = sizeof( salt_count_) + + sizeof( table_size_) + + sizeof( raw_table_size_) + + sizeof( projected_element_count_) + + sizeof( inserted_element_count_) + + sizeof( random_seed_) + + sizeof(desired_false_positive_probability_) + + salt_count_ * sizeof( bloom_type) + + static_cast(raw_table_size_) * + sizeof(cell_type) + + 64; // handle array sizes etc. + std::ofstream ostream(file_name.c_str(),std::ios::binary); + if (!ostream) + return false; + unsigned char* buffer = new unsigned char[buffer_size]; + strtk::binary::writer writer(buffer,buffer_size); + writer.reset(true); + bool result = writer(salt_count_) && + writer(table_size_) && + writer(raw_table_size_) && + writer(projected_element_count_) && + writer(inserted_element_count_) && + writer(random_seed_) && + writer(desired_false_positive_probability_) && + writer(salt_) && + writer(bit_table_,raw_table_size_); + if (result) + { + writer(ostream); + } + ostream.close(); + delete[] buffer; + return result; + } + + inline bool read_from_file(const std::string& file_name) + { + std::ifstream istream(file_name.c_str(),std::ios::binary); + if (!istream) + return false; + salt_count_ = 0; + table_size_ = 0; + raw_table_size_ = 0; + projected_element_count_ = 0; + inserted_element_count_ = 0; + random_seed_ = 0; + desired_false_positive_probability_ = 0.0; + salt_.clear(); + if (0 != bit_table_) + delete [] bit_table_; + bit_table_= 0; + const std::size_t buffer_size = strtk::fileio::file_size(file_name); + unsigned char* buffer = new unsigned char[buffer_size]; + strtk::binary::reader reader(buffer,buffer_size); + reader.reset(true); + reader(istream,buffer_size); + istream.close(); + bool result = reader(salt_count_) && + reader(table_size_) && + reader(raw_table_size_) && + reader(projected_element_count_) && + reader(inserted_element_count_) && + reader(random_seed_) && + reader(desired_false_positive_probability_) && + reader(salt_) && + reader(bit_table_,raw_table_size_); + delete[] buffer; + return result; + } + + inline std::size_t hash_count() + { + return salt_.size(); + } + + protected: + + inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const + { + bit_index = static_cast(hash % table_size_); + bit = bit_index % bits_per_char; + } + + void generate_unique_salt() + { + /* + Note: + A distinct hash function need not be implementation-wise + distinct. In the current implementation "seeding" a common + hash function with different values seems to be adequate. + */ + const unsigned int predef_salt_count = 128; + static const bloom_type predef_salt[predef_salt_count] = + { + 0xAAAAAAAA, 0x55555555, 0x33333333, 0xCCCCCCCC, + 0x66666666, 0x99999999, 0xB5B5B5B5, 0x4B4B4B4B, + 0xAA55AA55, 0x55335533, 0x33CC33CC, 0xCC66CC66, + 0x66996699, 0x99B599B5, 0xB54BB54B, 0x4BAA4BAA, + 0xAA33AA33, 0x55CC55CC, 0x33663366, 0xCC99CC99, + 0x66B566B5, 0x994B994B, 0xB5AAB5AA, 0xAAAAAA33, + 0x555555CC, 0x33333366, 0xCCCCCC99, 0x666666B5, + 0x9999994B, 0xB5B5B5AA, 0xFFFFFFFF, 0xFFFF0000, + 0xB823D5EB, 0xC1191CDF, 0xF623AEB3, 0xDB58499F, + 0xC8D42E70, 0xB173F616, 0xA91A5967, 0xDA427D63, + 0xB1E8A2EA, 0xF6C0D155, 0x4909FEA3, 0xA68CC6A7, + 0xC395E782, 0xA26057EB, 0x0CD5DA28, 0x467C5492, + 0xF15E6982, 0x61C6FAD3, 0x9615E352, 0x6E9E355A, + 0x689B563E, 0x0C9831A8, 0x6753C18B, 0xA622689B, + 0x8CA63C47, 0x42CC2884, 0x8E89919B, 0x6EDBD7D3, + 0x15B6796C, 0x1D6FDFE4, 0x63FF9092, 0xE7401432, + 0xEFFE9412, 0xAEAEDF79, 0x9F245A31, 0x83C136FC, + 0xC3DA4A8C, 0xA5112C8C, 0x5271F491, 0x9A948DAB, + 0xCEE59A8D, 0xB5F525AB, 0x59D13217, 0x24E7C331, + 0x697C2103, 0x84B0A460, 0x86156DA9, 0xAEF2AC68, + 0x23243DA5, 0x3F649643, 0x5FA495A8, 0x67710DF8, + 0x9A6C499E, 0xDCFB0227, 0x46A43433, 0x1832B07A, + 0xC46AFF3C, 0xB9C8FFF0, 0xC9500467, 0x34431BDF, + 0xB652432B, 0xE367F12B, 0x427F4C1B, 0x224C006E, + 0x2E7E5A89, 0x96F99AA5, 0x0BEB452A, 0x2FD87C39, + 0x74B2E1FB, 0x222EFD24, 0xF357F60C, 0x440FCB1E, + 0x8BBE030F, 0x6704DC29, 0x1144D12F, 0x948B1355, + 0x6D8FD7E9, 0x1C11A014, 0xADD1592F, 0xFB3C712E, + 0xFC77642F, 0xF9C4CE8C, 0x31312FB9, 0x08B0DD79, + 0x318FA6E7, 0xC040D23D, 0xC0589AA7, 0x0CA5C075, + 0xF874B172, 0x0CF914D5, 0x784D3280, 0x4E8CFEBC, + 0xC569F575, 0xCDB2A091, 0x2CC016B4, 0x5C5F4421 + }; + + if (salt_count_ <= predef_salt_count) + { + std::copy(predef_salt, + predef_salt + salt_count_, + std::back_inserter(salt_)); + for (unsigned int i = 0; i < salt_.size(); ++i) + { + /* + Note: + This is done to integrate the user defined random seed, + so as to allow for the generation of unique bloom filter + instances. + */ + salt_[i] = salt_[i] * salt_[(i + 3) % salt_.size()] + static_cast(random_seed_); + } + } + else + { + std::copy(predef_salt,predef_salt + predef_salt_count,std::back_inserter(salt_)); + srand(static_cast(random_seed_)); + while (salt_.size() < salt_count_) + { + bloom_type current_salt = static_cast(rand()) * static_cast(rand()); + if (0 == current_salt) continue; + if (salt_.end() == std::find(salt_.begin(), salt_.end(), current_salt)) + { + salt_.push_back(current_salt); + } + } + } + } + + inline bloom_type hash_ap(const unsigned char* begin, std::size_t remaining_length, bloom_type hash) const + { + const unsigned char* itr = begin; + unsigned int loop = 0; + while (remaining_length >= 8) + { + const unsigned int& i1 = *(reinterpret_cast(itr)); itr += sizeof(unsigned int); + const unsigned int& i2 = *(reinterpret_cast(itr)); itr += sizeof(unsigned int); + hash ^= (hash << 7) ^ i1 * (hash >> 3) ^ + (~((hash << 11) + (i2 ^ (hash >> 5)))); + remaining_length -= 8; + } + if (remaining_length) + { + if (remaining_length >= 4) + { + const unsigned int& i = *(reinterpret_cast(itr)); + if (loop & 0x01) + hash ^= (hash << 7) ^ i * (hash >> 3); + else + hash ^= (~((hash << 11) + (i ^ (hash >> 5)))); + ++loop; + remaining_length -= 4; + itr += sizeof(unsigned int); + } + if (remaining_length >= 2) + { + const unsigned short& i = *(reinterpret_cast(itr)); + if (loop & 0x01) + hash ^= (hash << 7) ^ i * (hash >> 3); + else + hash ^= (~((hash << 11) + (i ^ (hash >> 5)))); + ++loop; + remaining_length -= 2; + itr += sizeof(unsigned short); + } + if (remaining_length) + { + hash += ((*itr) ^ (hash * 0xA5A5A5A5)) + loop; + } + } + return hash; + } + + std::vector salt_; + unsigned char* bit_table_; + unsigned int salt_count_; + unsigned long long int table_size_; + unsigned long long int raw_table_size_; + unsigned long long int projected_element_count_; + unsigned int inserted_element_count_; + unsigned long long int random_seed_; + double desired_false_positive_probability_; + }; + + inline filter operator & (const filter& a, const filter& b) + { + filter result = a; + result &= b; + return result; + } + + inline filter operator | (const filter& a, const filter& b) + { + filter result = a; + result |= b; + return result; + } + + inline filter operator ^ (const filter& a, const filter& b) + { + filter result = a; + result ^= b; + return result; + } + + class compressible_filter : public filter + { + public: + + compressible_filter(const parameters& p) + : filter(p) + { + size_list.push_back(table_size_); + } + + inline virtual unsigned long long int size() const + { + return size_list.back(); + } + + inline bool compress(const double& percentage) + { + if ((0.0 >= percentage) || (percentage >= 100.0)) + { + return false; + } + + unsigned long long int original_table_size = size_list.back(); + unsigned long long int new_table_size = static_cast((size_list.back() * (1.0 - (percentage / 100.0)))); + new_table_size -= (((new_table_size % bits_per_char) != 0) ? (new_table_size % bits_per_char) : 0); + + if ((bits_per_char > new_table_size) || (new_table_size >= original_table_size)) + { + return false; + } + + desired_false_positive_probability_ = effective_fpp(); + cell_type* tmp = new cell_type[static_cast(new_table_size / bits_per_char)]; + std::copy(bit_table_, bit_table_ + (new_table_size / bits_per_char), tmp); + cell_type* itr = bit_table_ + (new_table_size / bits_per_char); + cell_type* end = bit_table_ + (original_table_size / bits_per_char); + cell_type* itr_tmp = tmp; + + while (end != itr) + { + *(itr_tmp++) |= (*itr++); + } + + delete[] bit_table_; + bit_table_ = tmp; + size_list.push_back(new_table_size); + + return true; + } + + private: + + inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const + { + bit_index = hash; + for (std::size_t i = 0; i < size_list.size(); ++i) + { + bit_index %= size_list[i]; + } + bit = bit_index % bits_per_char; + } + + std::vector size_list; + }; + + } + + namespace details + { + + inline void compute_pod_hash(const char data[], unsigned int& hash) + { + hash ^= ((hash << 7) ^ data[0] * (hash >> 3)); + hash ^= ~((hash << 11) + (data[1] ^ (hash >> 5))); + } + + inline void compute_pod_hash(const unsigned char data[], unsigned int& hash) + { + hash ^= ((hash << 7) ^ data[0] * (hash >> 3)); + hash ^= ~((hash << 11) + (data[1] ^ (hash >> 5))); + } + + inline void compute_pod_hash(const int& data, unsigned int& hash) + { + const unsigned char* itr = reinterpret_cast(&data); + hash ^= ((hash << 7) ^ itr[0] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[1] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[2] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[3] ^ (hash >> 5))); + } + + inline void compute_pod_hash(const unsigned int& data, unsigned int& hash) + { + compute_pod_hash(static_cast(data),hash); + } + + inline void compute_pod_hash(const unsigned long long int& data, unsigned int& hash) + { + const unsigned char* itr = reinterpret_cast(&data); + hash ^= ((hash << 7) ^ itr[0] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[1] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[2] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[3] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[4] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[5] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[6] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[7] ^ (hash >> 5))); + } + + inline void compute_pod_hash(const double& data, unsigned int& hash) + { + const unsigned char* itr = reinterpret_cast(&data); + hash ^= ((hash << 7) ^ itr[0] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[1] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[2] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[3] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[4] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[5] ^ (hash >> 5))); + hash ^= ((hash << 7) ^ itr[6] * (hash >> 3)); + hash ^= ~((hash << 11) + (itr[7] ^ (hash >> 5))); + } + + template + inline void compute_block(Iterator itr, std::size_t& length, unsigned int& hash) + { + while (length >= block_size) + { + for (std::size_t i = 0; i < block_size; ++i, ++itr) + { + compute_pod_hash((*itr),hash); + } + length -= block_size; + } + } + + template + inline void compute_block(unsigned char* itr, std::size_t& length, unsigned int& hash) + { + unsigned int local_hash = hash; + while (length >= block_size) + { + for (std::size_t i = 0; i < block_size; ++i, ++itr) + { + compute_pod_hash((*itr),local_hash); + } + length -= block_size; + } + hash = local_hash; + } + + template + inline void compute_block(char* itr, std::size_t& length, unsigned int& hash) + { + compute_block(reinterpret_cast(itr),length,hash); + } + + static const unsigned int hash_seed = 0xAAAAAAAA; + + template + inline void hash(const Iterator itr, std::size_t length, unsigned int& hash_value) + { + if (length >= 64) compute_block<64>(itr,length,hash_value); + if (length >= 32) compute_block<32>(itr,length,hash_value); + if (length >= 16) compute_block<16>(itr,length,hash_value); + if (length >= 8) compute_block< 8>(itr,length,hash_value); + if (length >= 4) compute_block< 4>(itr,length,hash_value); + if (length >= 2) compute_block< 2>(itr,length,hash_value); + if (length == 0) compute_block< 1>(itr,length,hash_value); + } + + } // namespace details + + template + inline unsigned int hash(const Iterator itr, + std::size_t length, + unsigned int seed = details::hash_seed) + { + unsigned int hash_value = seed; + details::hash(itr,length,hash_value); + return hash_value; + } + + inline unsigned int hash(const std::string& s, unsigned int seed = details::hash_seed) + { + unsigned int hash_value = seed; + return hash(s.begin(),s.size(),hash_value); + } + + template class Sequence> + inline unsigned int hash(const Sequence& sequence, unsigned int seed = details::hash_seed) + { + unsigned int hash_value = seed; + return hash(sequence.begin(),sequence.size(),hash_value); + } + + namespace util + { + template + class scoped_restore + { + public: + + scoped_restore(T& t, const bool restore = true) + : restore_(restore), + reference_(t), + copy_(t) + {} + + ~scoped_restore() + { + if (restore_) + { + reference_ = copy_; + } + } + + inline bool& restore() + { + return restore_; + } + + private: + + scoped_restore(const scoped_restore&); + scoped_restore& operator=(const scoped_restore&); + + bool restore_; + T& reference_; + T copy_; + }; + + template + class attribute + { + public: + + attribute() + : initialised_(false) + {} + + attribute(const T& t) + { + assign(t); + prev_t_ = t; + } + + inline attribute& operator=(const T& t) + { + prev_t_ = t_; + assign(t); + return *this; + } + + inline bool operator==(const T& t) + { + return initialised_ && (t_ == t); + } + + template + inline bool operator!=(const TConvertibleType& t) + { + return !(operator==(t)); + } + + inline T& operator()() + { + return t_; + } + + inline const T& operator()() const + { + return t_; + } + + inline operator T() const + { + return t_; + } + + inline operator T() + { + return t_; + } + + inline bool initialised() const + { + return initialised_; + } + + inline bool& initialised() + { + return initialised_; + } + + inline bool changed() const + { + return (initialised_ && (t_ != prev_t_)); + } + + inline const T& value() const + { + return t_; + } + + inline T& value() + { + return t_; + } + + inline const T& previous() const + { + return prev_t_; + } + + inline T& previous() + { + return prev_t_; + } + + private: + + inline void assign(const T& t) + { + t_ = t; + initialised_ = true; + } + + T t_; + T prev_t_; + bool initialised_; + }; + + inline bool operator==(const char* s, const attribute& attrib) + { + return attrib.value() == s; + } + + inline bool operator!=(const char* s, const attribute& attrib) + { + return !(s == attrib.value()); + } + + template + static inline std::ostream& operator<<(std::ostream& os, const attribute& attrib) + { + return (os << attrib.value()); + } + + class semantic_action_impl + { + private: + + class function_holder_base + { + public: + + typedef const unsigned char* itr_type; + + virtual ~function_holder_base(){} + + virtual bool operator()(itr_type begin, itr_type end) const = 0; + + inline bool operator()(const char* begin, const char* end) const + { + return operator()(reinterpret_cast(begin), + reinterpret_cast(end)); + } + + template + inline bool operator()(const std::pair& p) const + { + return operator()(p.first,p.second); + } + }; + + template + class function_holder : public function_holder_base + { + public: + + explicit function_holder(Function& f) + : function_(&f) + {} + + inline virtual bool operator()(itr_type begin, itr_type end) const + { + return (*function_)(begin,end); + } + + private: + + Function* function_; + }; + + public: + + semantic_action_impl() + : function_holder_(0) + { + std::fill_n(function_holder_buffer_,sizeof(function_holder_buffer_),0x00); + } + + template + inline explicit semantic_action_impl(const Function& f) + { + std::fill_n(function_holder_buffer_,sizeof(function_holder_buffer_),0x00); + assign(f); + } + + inline bool operator!() const + { + return (0 == function_holder_); + } + + inline bool operator==(const semantic_action_impl& sa) const + { + return (0 != function_holder_) && + (0 != sa.function_holder_) && + (function_holder_ == sa.function_holder_); + } + + template + inline bool operator()(InputIterator begin, InputIterator end) const + { + if (0 != function_holder_) + return (*function_holder_).operator()(begin,end); + else + return false; + } + + template + inline bool operator()(const std::pair& r) const + { + return operator()(r.first,r.second); + } + + inline bool operator()(const std::string& s) const + { + return operator()(s.data(),s.data() + s.size()); + } + + template + inline void assign(Function& f) + { + static const std::size_t type_size = sizeof(function_holder(f)); + function_holder_ = construct::type(f,function_holder_buffer_); + } + + inline semantic_action_impl& ref() + { + return (*this); + } + + private: + + typedef function_holder_base* function_holder_ptr; + + inline semantic_action_impl& operator=(const semantic_action_impl&); + + template + struct construct + { + inline static function_holder_ptr type(Function&, unsigned char*) + { + return reinterpret_cast(0); + } + }; + + template + struct construct + { + inline static function_holder_ptr type(Function& f, unsigned char* buffer) + { + return new(buffer)function_holder(f); + } + }; + + function_holder_ptr function_holder_; + enum { function_holder_buffer_size = 64 }; + unsigned char function_holder_buffer_[function_holder_buffer_size]; + }; + + template + inline semantic_action_impl semantic_action(Function& f) + { + return semantic_action_impl(f); + } + + } // namespace util + + namespace details + { + #define strtk_register_attribute_type_tag(T) \ + template<> struct supported_conversion_to_type< strtk::util::attribute >{ typedef attribute_type_tag type; }; \ + template<> struct supported_conversion_from_type< strtk::util::attribute > { typedef attribute_type_tag type; };\ + + strtk_register_attribute_type_tag(unsigned short) + strtk_register_attribute_type_tag(unsigned int) + strtk_register_attribute_type_tag(unsigned long) + strtk_register_attribute_type_tag(unsigned long long int) + strtk_register_attribute_type_tag(short) + strtk_register_attribute_type_tag(int) + strtk_register_attribute_type_tag(long) + strtk_register_attribute_type_tag(long long) + strtk_register_attribute_type_tag(float) + strtk_register_attribute_type_tag(double) + strtk_register_attribute_type_tag(long double) + strtk_register_attribute_type_tag(unsigned char) + strtk_register_attribute_type_tag(signed char) + strtk_register_attribute_type_tag(char) + strtk_register_attribute_type_tag(std::string) + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, strtk::util::attribute& result, attribute_type_tag) + { + if (strtk::string_to_type_converter(itr,end,result.value())) + { + result.initialised() = true; + return true; + } + else + return false; + } + + template + inline bool type_to_string_converter_impl(const strtk::util::attribute& attrib, std::string& result, attribute_type_tag) + { + if (!attrib.initialised()) + return false; + return strtk::type_to_string(attrib.value(),result); + } + + #undef strtk_register_attribute_type_tag + + template<> struct supported_conversion_to_type < strtk::util::semantic_action_impl > { typedef semantic_action_type_tag type; }; + template<> struct supported_conversion_from_type< strtk::util::semantic_action_impl > { typedef semantic_action_type_tag type; }; + + template + inline bool string_to_type_converter_impl(Iterator& itr, const Iterator end, strtk::util::semantic_action_impl& result, semantic_action_type_tag) + { + return result(itr,end); + } + + inline bool type_to_string_converter_impl(const strtk::util::semantic_action_impl&, std::string& result, semantic_action_type_tag) + { + static std::string result_str = "semantic_action"; + result = result_str; + return true; + } + + } // namespace details + + namespace util + { + class value + { + private: + + class type_holder_base + { + public: + + typedef const unsigned char* itr_type; + + virtual ~type_holder_base(){} + + virtual bool operator()(itr_type begin, itr_type end) const = 0; + + virtual bool to_string(std::string& s) const = 0; + + inline bool operator()(const char* begin, const char* end) const + { + return operator()(reinterpret_cast(begin), + reinterpret_cast(end)); + } + + template + inline bool operator()(const std::pair& p) const + { + return operator()(p.first,p.second); + } + }; + + template + class type_holder : public type_holder_base + { + public: + + typedef T* type_ptr; + + explicit type_holder(T& t) + : value_ptr_(&t) + {} + + inline virtual bool operator()(itr_type begin, itr_type end) const + { + return strtk::string_to_type_converter(begin,end,(*value_ptr_)); + } + + inline virtual bool to_string(std::string& s) const + { + return strtk::type_to_string((*value_ptr_),s); + } + + inline operator T() const + { + return (*value_ptr_); + } + + private: + + type_ptr value_ptr_; + }; + + public: + + value() + : type_holder_(0) + { + std::fill_n(type_holder_buffer_,sizeof(type_holder_buffer_),0x00); + } + + template + inline explicit value(T& t) + { + std::fill_n(type_holder_buffer_,sizeof(type_holder_buffer_),0x00); + assign(t); + } + + inline bool operator!() const + { + return (0 == type_holder_); + } + + inline bool operator==(const value& v) const + { + return (0 != type_holder_) && + (0 != v.type_holder_) && + (type_holder_ == v.type_holder_); + } + + inline value& operator=(const value& v) + { + if (&v != this) + { + if (0 != v.type_holder_) + { + std::copy(v.type_holder_buffer_, + v.type_holder_buffer_ + type_holder_buffer_size, + type_holder_buffer_); + type_holder_ = reinterpret_cast(type_holder_buffer_); + } + } + return *this; + } + + template + inline bool operator()(InputIterator begin, InputIterator end) const + { + if (0 != type_holder_) + return (*type_holder_).operator()(begin,end); + else + return false; + } + + template + inline bool operator()(const std::pair& r) const + { + return operator()(r.first,r.second); + } + + inline bool operator()(const std::string& s) const + { + return operator()(s.data(),s.data() + s.size()); + } + + template + inline void assign(T& t) + { + static const std::size_t type_size = sizeof(type_holder(t)); + type_holder_ = construct::type(t,type_holder_buffer_); + } + + inline bool to_string(std::string& s) const + { + if (0 != type_holder_) + return (*type_holder_).to_string(s); + else + return false; + } + + template + inline operator T() const + { + if (0 != type_holder_) + return (*type_holder_); + else + return T(); + } + + private: + + typedef type_holder_base* type_holder_ptr; + + template + struct construct + { + inline static type_holder_ptr type(T&, unsigned char*) + { + return reinterpret_cast(0); + } + }; + + template + struct construct + { + inline static type_holder_ptr type(T& t, unsigned char* buffer) + { + return new(buffer)type_holder(t); + } + }; + + type_holder_ptr type_holder_; + enum { type_holder_buffer_size = 2 * sizeof(type_holder) }; + unsigned char type_holder_buffer_[type_holder_buffer_size]; + }; + + template + inline void make_key_list(const std::map& map, + OutputIterator out) + { + if (map.empty()) return; + typedef typename std::map map_type; + typename map_type::const_iterator itr = map.begin(); + typename map_type::const_iterator end = map.end(); + while (end != itr) + { + *out++ = (itr++)->first; + } + } + + template + inline void make_key_list(const std::map& map, + std::set& set) + { + make_key_list(map,std::inserter(set,set.begin())); + } + + template + inline void make_key_list(const std::map& map, + std::multiset& multiset) + { + make_key_list(map,std::inserter(multiset,multiset.begin())); + } + + template class Sequence> + inline void make_key_list(const std::map& map, + Sequence& sequence) + { + make_key_list(map,std::back_inserter(sequence)); + } + + template + inline void make_value_list(const std::multimap& map, + const Key& key, + OutputIterator out) + { + if (map.empty()) return; + typedef typename std::multimap map_type; + typename map_type::const_iterator itr = map.find(key); + typename map_type::const_iterator end = map.end(); + while ((end != itr) && (key == itr->first)) + { + *out++ = (itr++)->second; + } + } + + template class Sequence> + inline void make_value_list(const std::multimap& map, + const Key& key, + Sequence& sequence) + { + make_value_list(map,key,std::back_inserter(sequence)); + } + + template class Sequence> + inline void delete_all(Sequence& sequence) + { + typename Sequence::iterator itr = sequence.begin(); + typename Sequence::iterator end = sequence.end(); + while (end != itr) + { + delete (*itr); + ++itr; + } + sequence.clear(); + } + + template + inline void delete_all(std::map& cont) + { + typename std::map::iterator itr = cont.begin(); + typename std::map::iterator end = cont.end(); + while (end != itr) + { + delete (*itr).second; + ++itr; + } + cont.clear(); + } + + template + inline void delete_all(std::multimap& cont) + { + typename std::multimap::iterator itr = cont.begin(); + typename std::multimap::iterator end = cont.end(); + while (end != itr) + { + delete (*itr).second; + ++itr; + } + cont.clear(); + } + + template + inline void delete_all(std::set& cont) + { + typename std::set::iterator itr = cont.begin(); + typename std::set::iterator end = cont.end(); + while (end != itr) + { + delete (*itr); + ++itr; + } + cont.clear(); + } + + template + inline void delete_all(std::multiset& cont) + { + typename std::multiset::iterator itr = cont.begin(); + typename std::multiset::iterator end = cont.end(); + while (end != itr) + { + delete (*itr); + ++itr; + } + cont.clear(); + } + + template class Sequence> + inline void delete_if(const Predicate& p, + Sequence& sequence) + { + typename Sequence::iterator itr = sequence.begin(); + while (sequence.end() != itr) + { + if (p(*itr)) + { + delete (*itr); + itr = sequence.erase(itr); + } + else + ++itr; + } + } + + template + inline void delete_if(const Predicate& p, + std::map& cont) + { + typename std::map::iterator itr = cont.begin(); + while (cont.end() != itr) + { + if (p(*itr)) + { + delete (*itr).second; + itr = cont.erase(itr); + } + else + ++itr; + } + } + + template + inline void delete_if(const Predicate& p, + std::multimap& cont) + { + typename std::multimap::iterator itr = cont.begin(); + while (cont.end() != itr) + { + if (p(*itr)) + { + delete (*itr).second; + itr = cont.erase(itr); + } + else + ++itr; + } + } + + template + inline void delete_if(const Predicate& p, + std::set& cont) + { + typename std::set::iterator itr = cont.begin(); + while (cont.end() != itr) + { + if (p(*itr)) + { + delete (*itr).second; + itr = cont.erase(itr); + } + else + ++itr; + } + } + + template + inline void delete_if(const Predicate& p, + std::multiset& cont) + { + typename std::multiset::iterator itr = cont.begin(); + while (cont.end() != itr) + { + if (p(*itr)) + { + delete (*itr).second; + itr = cont.erase(itr); + } + else + ++itr; + } + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9, const T& v10, const T& v11) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); sequence.push_back(v6); + sequence.push_back(v7); sequence.push_back(v8); + sequence.push_back(v9); sequence.push_back(v10); + sequence.push_back(v11); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9, const T& v10) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); sequence.push_back(v6); + sequence.push_back(v7); sequence.push_back(v8); + sequence.push_back(v9); sequence.push_back(v10); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); sequence.push_back(v6); + sequence.push_back(v7); sequence.push_back(v8); + sequence.push_back(v9); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); sequence.push_back(v6); + sequence.push_back(v7); sequence.push_back(v8); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); sequence.push_back(v6); + sequence.push_back(v7); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); sequence.push_back(v6); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + sequence.push_back(v5); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3, const T& v4) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); sequence.push_back(v4); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2, const T& v3) + { + sequence.push_back(v1); sequence.push_back(v2); + sequence.push_back(v3); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1, const T& v2) + { + sequence.push_back(v1); sequence.push_back(v2); + } + + template class Sequence> + inline void push_back(Sequence& sequence, + const T& v1) + { + sequence.push_back(v1); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9, const T& v10) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); set.insert(v8); + set.insert(v9); set.insert(v10); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); set.insert(v8); + set.insert(v9); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); set.insert(v8); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3, const T& v4) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2, const T& v3) + { + set.insert(v1); set.insert(v2); + set.insert(v3); + } + + template + inline void push_back(std::set& set, + const T& v1, const T& v2) + { + set.insert(v1); set.insert(v2); + } + + template + inline void push_back(std::set& set, + const T& v1) + { + set.insert(v1); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9, const T& v10) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); set.insert(v8); + set.insert(v9); set.insert(v10); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, + const T& v9) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); set.insert(v8); + set.insert(v9); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); set.insert(v8); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + set.insert(v7); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); set.insert(v6); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + set.insert(v5); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3, const T& v4) + { + set.insert(v1); set.insert(v2); + set.insert(v3); set.insert(v4); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2, const T& v3) + { + set.insert(v1); set.insert(v2); + set.insert(v3); + } + + template + inline void push_back(std::multiset& set, + const T& v1, const T& v2) + { + set.insert(v1); set.insert(v2); + } + + template + inline void push_back(std::multiset& set, + const T& v1) + { + set.insert(v1); + } + + template class Sequence> + inline void clear(Sequence& sequence) + { + sequence.clear(); + } + + template + inline void clear(std::set& set) + { + std::set null_set; + std::swap(set,null_set); + } + + template + inline void clear(std::multiset& multiset) + { + std::multiset null_set; + std::swap(multiset,null_set); + } + + template + inline void clear(std::queue& queue) + { + std::queue null_que; + std::swap(queue,null_que); + } + + template + inline void clear(std::stack& stack) + { + std::stack null_stack; + std::swap(stack,null_stack); + } + + template + inline void clear(std::priority_queue& priority_queue) + { + std::priority_queue null_pqueue; + std::swap(priority_queue,null_pqueue); + } + + } // namespace util + + namespace details + { + template + struct column_list_impl + { + enum { size = N }; + std::size_t index_list[N]; + }; + + template + class column_selector_base + { + public: + + typedef column_selector_base csb_t; + typedef column_list_impl column_list_t; + + column_selector_base(const column_list_t& column_list) + : column_list_(column_list), + current_index_(0), + target_index_(column_list_.index_list[0]), + col_list_index_(0), + error_count_(0) + {} + + inline csb_t& operator*() + { + return (*this); + } + + inline csb_t& operator++() + { + return (*this); + } + + inline csb_t operator++(int) + { + return (*this); + } + + template + inline csb_t& operator=(const std::pair& r) + { + process(r); + return (*this); + } + + void reset() + { + current_index_ = 0; + col_list_index_ = 0; + target_index_ = column_list_.index_list[0]; + error_count_ = 0; + } + + protected: + + class colsel_value_list + { + public: + + typedef std::pair value_t; + + colsel_value_list() + : current_index(0) + { + static const value_t null_value(strtk::util::value(),false); + std::fill_n(value_list,N,null_value); + } + + template + inline void register_value(T& t) + { + if (current_index < N) + { + value_list[current_index].first.assign(t); + value_list[current_index].second = false; + ++current_index; + } + } + + std::size_t current_index; + value_t value_list[N]; + }; + + template + inline void process(const std::pair& r) + { + if (current_index_ > target_index_) + return; + else if (current_index_ == target_index_) + { + typename colsel_value_list::value_t& v = cvl_.value_list[col_list_index_]; + if (true != (v.second = v.first(r.first,r.second))) + { + ++error_count_; + } + ++col_list_index_; + if (col_list_index_ < column_list_t::size) + target_index_ = column_list_.index_list[col_list_index_]; + else + target_index_ = std::numeric_limits::max(); + } + ++current_index_; + } + + inline colsel_value_list& cvl() + { + return cvl_; + } + + const column_list_t& column_list_; + std::size_t current_index_; + std::size_t target_index_; + std::size_t col_list_index_; + std::size_t error_count_; + colsel_value_list cvl_; + + private: + + csb_t& operator=(const csb_t& csb); + }; + + template + class column_selector_impl + : public column_selector_base,12> + { + public: + + typedef column_selector_base,12> csb_t; + typedef column_list_impl<12> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, + T10& t10, T11& t11) + : csb_t(column_list) + { + csb_t::cvl().register_value( t0); csb_t::cvl().register_value( t1); + csb_t::cvl().register_value( t2); csb_t::cvl().register_value( t3); + csb_t::cvl().register_value( t4); csb_t::cvl().register_value( t5); + csb_t::cvl().register_value( t6); csb_t::cvl().register_value( t7); + csb_t::cvl().register_value( t8); csb_t::cvl().register_value( t9); + csb_t::cvl().register_value(t10); csb_t::cvl().register_value(t11); + } + }; + + template + class column_selector_impl + : public column_selector_base,11> + { + public: + + typedef column_selector_base,11> csb_t; + typedef column_list_impl<11> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, + T10& t10) + : csb_t(column_list) + { + csb_t::cvl().register_value( t0); csb_t::cvl().register_value( t1); + csb_t::cvl().register_value( t2); csb_t::cvl().register_value( t3); + csb_t::cvl().register_value( t4); csb_t::cvl().register_value( t5); + csb_t::cvl().register_value( t6); csb_t::cvl().register_value( t7); + csb_t::cvl().register_value( t8); csb_t::cvl().register_value( t9); + csb_t::cvl().register_value(t10); + } + }; + + template + class column_selector_impl + : public column_selector_base,10> + { + public: + + typedef column_selector_base,10> csb_t; + typedef column_list_impl<10> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, T9& t9) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + csb_t::cvl().register_value(t4); csb_t::cvl().register_value(t5); + csb_t::cvl().register_value(t6); csb_t::cvl().register_value(t7); + csb_t::cvl().register_value(t8); csb_t::cvl().register_value(t9); + } + }; + + template + class column_selector_impl + : public column_selector_base,9> + { + public: + + typedef column_selector_base,9> csb_t; + typedef column_list_impl<9> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + csb_t::cvl().register_value(t4); csb_t::cvl().register_value(t5); + csb_t::cvl().register_value(t6); csb_t::cvl().register_value(t7); + csb_t::cvl().register_value(t8); + } + }; + + template + class column_selector_impl + : public column_selector_base,8> + { + public: + + typedef column_selector_base,8> csb_t; + typedef column_list_impl<8> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + csb_t::cvl().register_value(t4); csb_t::cvl().register_value(t5); + csb_t::cvl().register_value(t6); csb_t::cvl().register_value(t7); + } + }; + + template + class column_selector_impl + : public column_selector_base,7> + { + public: + + typedef column_selector_base,7> csb_t; + typedef column_list_impl<7> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + csb_t::cvl().register_value(t4); csb_t::cvl().register_value(t5); + csb_t::cvl().register_value(t6); + } + }; + + template + class column_selector_impl + : public column_selector_base,6> + { + public: + + typedef column_selector_base,6> csb_t; + typedef column_list_impl<6> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, + T3& t3, T4& t4, T5& t5) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + csb_t::cvl().register_value(t4); csb_t::cvl().register_value(t5); + } + }; + + template + class column_selector_impl + : public column_selector_base,5> + { + public: + + typedef column_selector_base,5> csb_t; + typedef column_list_impl<5> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, + T3& t3, T4& t4) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + csb_t::cvl().register_value(t4); + } + }; + + template + class column_selector_impl + : public column_selector_base,4> + { + public: + + typedef column_selector_base,4> csb_t; + typedef column_list_impl<4> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2, T3& t3) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); csb_t::cvl().register_value(t3); + } + }; + + template + class column_selector_impl + : public column_selector_base,3> + { + public: + + typedef column_selector_base,3> csb_t; + typedef column_list_impl<3> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1, T2& t2) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + csb_t::cvl().register_value(t2); + } + }; + + template + class column_selector_impl + : public column_selector_base,2> + { + public: + + typedef column_selector_base,2> csb_t; + typedef column_list_impl<2> column_list_t; + + column_selector_impl(const column_list_t& column_list, + T1& t0, T1& t1) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); csb_t::cvl().register_value(t1); + } + }; + + template + class column_selector_impl + : public column_selector_base,1> + { + public: + + typedef column_selector_base,1> csb_t; + typedef column_list_impl<1> column_list_t; + + column_selector_impl(const column_list_t& column_list, T0& t0) + : csb_t(column_list) + { + csb_t::cvl().register_value(t0); + } + }; + + } + + inline details::column_list_impl<12> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5, + const std::size_t& idx6, const std::size_t& idx7, + const std::size_t& idx8, const std::size_t& idx9, + const std::size_t& idx10, const std::size_t& idx11) + { + details::column_list_impl<12> cli; + cli.index_list[ 0] = idx0; cli.index_list[ 1] = idx1; + cli.index_list[ 2] = idx2; cli.index_list[ 3] = idx3; + cli.index_list[ 4] = idx4; cli.index_list[ 5] = idx5; + cli.index_list[ 6] = idx6; cli.index_list[ 7] = idx7; + cli.index_list[ 8] = idx8; cli.index_list[ 9] = idx9; + cli.index_list[10] = idx10; cli.index_list[11] = idx11; + return cli; + } + + inline details::column_list_impl<11> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5, + const std::size_t& idx6, const std::size_t& idx7, + const std::size_t& idx8, const std::size_t& idx9, + const std::size_t& idx10) + { + details::column_list_impl<11> cli; + cli.index_list[ 0] = idx0; cli.index_list[1] = idx1; + cli.index_list[ 2] = idx2; cli.index_list[3] = idx3; + cli.index_list[ 4] = idx4; cli.index_list[5] = idx5; + cli.index_list[ 6] = idx6; cli.index_list[7] = idx7; + cli.index_list[ 8] = idx8; cli.index_list[9] = idx9; + cli.index_list[10] = idx10; + return cli; + } + + inline details::column_list_impl<10> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5, + const std::size_t& idx6, const std::size_t& idx7, + const std::size_t& idx8, const std::size_t& idx9) + { + details::column_list_impl<10> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + cli.index_list[4] = idx4; cli.index_list[5] = idx5; + cli.index_list[6] = idx6; cli.index_list[7] = idx7; + cli.index_list[8] = idx8; cli.index_list[9] = idx9; + return cli; + } + + inline details::column_list_impl<9> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5, + const std::size_t& idx6, const std::size_t& idx7, + const std::size_t& idx8) + { + details::column_list_impl<9> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + cli.index_list[4] = idx4; cli.index_list[5] = idx5; + cli.index_list[6] = idx6; cli.index_list[7] = idx7; + cli.index_list[8] = idx8; + return cli; + } + + inline details::column_list_impl<8> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5, + const std::size_t& idx6, const std::size_t& idx7) + { + details::column_list_impl<8> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + cli.index_list[4] = idx4; cli.index_list[5] = idx5; + cli.index_list[6] = idx6; cli.index_list[7] = idx7; + return cli; + } + + inline details::column_list_impl<7> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5, + const std::size_t& idx6) + { + details::column_list_impl<7> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + cli.index_list[4] = idx4; cli.index_list[5] = idx5; + cli.index_list[6] = idx6; + return cli; + } + + inline details::column_list_impl<6> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4, const std::size_t& idx5) + { + details::column_list_impl<6> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + cli.index_list[4] = idx4; cli.index_list[5] = idx5; + return cli; + } + + inline details::column_list_impl<5> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3, + const std::size_t& idx4) + { + details::column_list_impl<5> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + cli.index_list[4] = idx4; + return cli; + } + + inline details::column_list_impl<4> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2, const std::size_t& idx3) + { + details::column_list_impl<4> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; cli.index_list[3] = idx3; + return cli; + } + + inline details::column_list_impl<3> + column_list(const std::size_t& idx0, const std::size_t& idx1, + const std::size_t& idx2) + { + details::column_list_impl<3> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + cli.index_list[2] = idx2; + return cli; + } + + inline details::column_list_impl<2> + column_list(const std::size_t& idx0, const std::size_t& idx1) + { + details::column_list_impl<2> cli; + cli.index_list[0] = idx0; cli.index_list[1] = idx1; + return cli; + } + + inline details::column_list_impl<1> + column_list(const std::size_t& idx0) + { + details::column_list_impl<1> cli; + cli.index_list[0] = idx0; + return cli; + } + + inline details::column_list_impl<12> column_list(const std::size_t (&idx)[12]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5], + idx[6],idx[7],idx[8],idx[9],idx[10],idx[11]); + } + + inline details::column_list_impl<11> column_list(const std::size_t (&idx)[11]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5], + idx[6],idx[7],idx[8],idx[9],idx[10]); + } + + inline details::column_list_impl<10> column_list(const std::size_t (&idx)[10]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5], + idx[6],idx[7],idx[8],idx[9]); + } + + inline details::column_list_impl<9> column_list(const std::size_t (&idx)[9]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5], + idx[6],idx[7],idx[8]); + } + + inline details::column_list_impl<8> column_list(const std::size_t (&idx)[8]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5], + idx[6],idx[7]); + } + + inline details::column_list_impl<7> column_list(const std::size_t (&idx)[7]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5],idx[6]); + } + + inline details::column_list_impl<6> column_list(const std::size_t (&idx)[6]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4],idx[5]); + } + + inline details::column_list_impl<5> column_list(const std::size_t (&idx)[5]) + { + return column_list(idx[0],idx[1],idx[2],idx[3],idx[4]); + } + + inline details::column_list_impl<4> column_list(const std::size_t (&idx)[4]) + { + return column_list(idx[0],idx[1],idx[2],idx[3]); + } + + inline details::column_list_impl<3> column_list(const std::size_t (&idx)[3]) + { + return column_list(idx[0],idx[1],idx[2]); + } + + inline details::column_list_impl<2> column_list(const std::size_t (&idx)[2]) + { + return column_list(idx[0],idx[1]); + } + + inline details::column_list_impl<1> column_list(const std::size_t (&idx)[1]) + { + return column_list(idx[0]); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<11>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9, T10& t10, T11& t11) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<11>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9, T10& t10) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<10>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<9>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5,t6,t7,t8); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<8>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5,t6,t7); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<7>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5,t6); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<6>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4,t5); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<5>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3,t4); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<4>& col_list, + T0& t0, T1& t1, T2& t2, T3& t3) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2,t3); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<3>& col_list, + T0& t0, T1& t1, T2& t2) + { + return + details::column_selector_impl + + (col_list,t0,t1,t2); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<2>& col_list, + T0& t0, T1& t1) + { + return + details::column_selector_impl + + (col_list,t0,t1); + } + + template + inline typename details::column_selector_impl + column_selector(const details::column_list_impl<1>& col_list, T0& t0) + { + return + details::column_selector_impl + + (col_list,t0); + } + + namespace details + { + template + inline Iterator inc(Iterator itr, const std::size_t& n) + { + std::advance(itr,n); + return itr; + } + + //Single type column selectors + template + struct compose_st_selector_impl + {}; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<1> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<2> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<3> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<4> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<5> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3],seq[4]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3),*inc(b,4)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<6> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3],seq[4],seq[5]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3),*inc(b,4),*inc(b,5)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<7> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3],seq[4],seq[5],seq[6]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3),*inc(b,4),*inc(b,5),*inc(b,6)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<8> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3],seq[4],seq[5],seq[6],seq[7]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3),*inc(b,4),*inc(b,5),*inc(b,6),*inc(b,7)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<9> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3],seq[4],seq[5],seq[6],seq[7],seq[8]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3),*inc(b,4),*inc(b,5),*inc(b,6),*inc(b,7),*inc(b,8)); + } + }; + + template + struct compose_st_selector_impl + { + typedef column_selector_impl type; + typedef column_list_impl<10> column_list_t; + + template class Sequence> + static inline type create(const column_list_t& col_list, Sequence& seq) + { + return type(col_list,seq[0],seq[1],seq[2],seq[3],seq[4],seq[5],seq[6],seq[7],seq[8],seq[9]); + } + + template + static inline type create(const column_list_t& col_list, std::list& list) + { + typename std::list::iterator b = list.begin(); + return type(col_list,*(b),*inc(b,1),*inc(b,2),*inc(b,3),*inc(b,4),*inc(b,5),*inc(b,6),*inc(b,7),*inc(b,8),*inc(b,9)); + } + }; + + } + + template class Sequence> + inline typename details::compose_st_selector_impl::type + column_selector(const details::column_list_impl& col_list, Sequence& seq) + { + if (seq.size() >= N) + { + typedef typename details::compose_st_selector_impl composer_t; + return composer_t::create(col_list,seq); + } + else + throw std::invalid_argument("column_selector(sequence/list) - size < N!"); + } + + namespace details + { + + template + class column_selector_iterator_impl + { + public: + + typedef column_selector_iterator_impl csii_t; + typedef details::column_list_impl column_list_t; + typedef std::pair iterator_type; + typedef iterator_type* iterator_type_ptr; + + column_selector_iterator_impl(const details::column_list_impl& column_list,iterator_type (&token_list)[N]) + : column_list_(column_list), + token_list_(token_list), + current_index_(0), + target_index_(column_list_.index_list[0]), + col_list_index_(0) + {} + + inline csii_t& operator*() + { + return (*this); + } + + inline csii_t& operator++() + { + return (*this); + } + + inline csii_t operator++(int) + { + return (*this); + } + + template + inline csii_t& operator=(const std::pair& r) + { + if (current_index_ == target_index_) + { + token_list_[col_list_index_] = r; + ++col_list_index_; + if (col_list_index_ < column_list_t::size) + target_index_ = column_list_.index_list[col_list_index_]; + else + target_index_ = std::numeric_limits::max(); + } + ++current_index_; + return (*this); + } + + private: + + csii_t& operator=(const csii_t& csb); + + const column_list_t& column_list_; + iterator_type_ptr token_list_; + std::size_t current_index_; + std::size_t target_index_; + std::size_t col_list_index_; + }; + + } + + #define strtk_parse_col_token(Index) \ + if (!string_to_type_converter(token_list[Index].first,token_list[Index].second,t##Index)) return false; + + #define strtk_parse_col_token_seq(Index) \ + if (!string_to_type_converter(token_list[Index].first,token_list[Index].second,seq[Index])) return false; + + #define strtk_parse_columns_impl(NN) \ + static const std::size_t N = NN; \ + typedef typename details::is_valid_iterator::type itr_type; \ + typedef std::pair iterator_type; \ + typedef details::column_selector_iterator_impl csii_t; \ + const std::size_t token_count = (column_list.index_list[N - 1] + 1); \ + details::convert_type_assert(); \ + iterator_type token_list[N]; \ + csii_t csii(column_list,token_list); \ + const std::size_t parsed_token_count = split_n \ + (delimiters,begin,end,token_count,csii,split_options::compress_delimiters);\ + if (token_count > parsed_token_count) return false; \ + + #define strk_parse_col_seq \ + return parse_columns(data.data(),data.data() + data.size(),delimiters,column_list,seq); + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<12>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9, T10& t10, T11& t11) + { + strtk_parse_columns_impl(12) + strtk_parse_col_token( 0) strtk_parse_col_token( 1) + strtk_parse_col_token( 2) strtk_parse_col_token( 3) + strtk_parse_col_token( 4) strtk_parse_col_token( 5) + strtk_parse_col_token( 6) strtk_parse_col_token( 7) + strtk_parse_col_token( 8) strtk_parse_col_token( 9) + strtk_parse_col_token(10) strtk_parse_col_token(11) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<11>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9, T10& t10) + { + strtk_parse_columns_impl(11) + strtk_parse_col_token( 0) strtk_parse_col_token(1) + strtk_parse_col_token( 2) strtk_parse_col_token(3) + strtk_parse_col_token( 4) strtk_parse_col_token(5) + strtk_parse_col_token( 6) strtk_parse_col_token(7) + strtk_parse_col_token( 8) strtk_parse_col_token(9) + strtk_parse_col_token(10) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<10>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9) + { + strtk_parse_columns_impl(10) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + strtk_parse_col_token(4) strtk_parse_col_token(5) + strtk_parse_col_token(6) strtk_parse_col_token(7) + strtk_parse_col_token(8) strtk_parse_col_token(9) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<9>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, + T7& t7, T8& t8) + { + strtk_parse_columns_impl(9) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + strtk_parse_col_token(4) strtk_parse_col_token(5) + strtk_parse_col_token(6) strtk_parse_col_token(7) + strtk_parse_col_token(8) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<8>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7) + { + strtk_parse_columns_impl(8) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + strtk_parse_col_token(4) strtk_parse_col_token(5) + strtk_parse_col_token(6) strtk_parse_col_token(7) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<7>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) + { + strtk_parse_columns_impl(7) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + strtk_parse_col_token(4) strtk_parse_col_token(5) + strtk_parse_col_token(6) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<6>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) + { + strtk_parse_columns_impl(6) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + strtk_parse_col_token(4) strtk_parse_col_token(5) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<5>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4) + { + strtk_parse_columns_impl(5) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + strtk_parse_col_token(4) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<4>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3) + { + strtk_parse_columns_impl(4) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) strtk_parse_col_token(3) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<3>& column_list, + T0& t0, T1& t1, T2& t2) + { + strtk_parse_columns_impl(3) + strtk_parse_col_token(0) strtk_parse_col_token(1) + strtk_parse_col_token(2) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<2>& column_list, + T0& t0, T1& t1) + { + strtk_parse_columns_impl(2) + strtk_parse_col_token(0) strtk_parse_col_token(1) + return true; + } + + template + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<1>& column_list, + T0& t0) + { + strtk_parse_columns_impl(1) + strtk_parse_col_token(0) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<12>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(12) + strtk_parse_col_token_seq( 0) strtk_parse_col_token_seq( 1) + strtk_parse_col_token_seq( 2) strtk_parse_col_token_seq( 3) + strtk_parse_col_token_seq( 4) strtk_parse_col_token_seq( 5) + strtk_parse_col_token_seq( 6) strtk_parse_col_token_seq( 7) + strtk_parse_col_token_seq( 8) strtk_parse_col_token_seq( 9) + strtk_parse_col_token_seq(10) strtk_parse_col_token_seq(11) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<11>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(11) + strtk_parse_col_token_seq( 0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq( 2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq( 4) strtk_parse_col_token_seq(5) + strtk_parse_col_token_seq( 6) strtk_parse_col_token_seq(7) + strtk_parse_col_token_seq( 8) strtk_parse_col_token_seq(9) + strtk_parse_col_token_seq(10) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<10>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(10) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq(4) strtk_parse_col_token_seq(5) + strtk_parse_col_token_seq(6) strtk_parse_col_token_seq(7) + strtk_parse_col_token_seq(8) strtk_parse_col_token_seq(9) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<9>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(9) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq(4) strtk_parse_col_token_seq(5) + strtk_parse_col_token_seq(6) strtk_parse_col_token_seq(7) + strtk_parse_col_token_seq(8) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<8>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(8) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq(4) strtk_parse_col_token_seq(5) + strtk_parse_col_token_seq(6) strtk_parse_col_token_seq(7) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<7>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(7) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq(4) strtk_parse_col_token_seq(5) + strtk_parse_col_token_seq(6) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<6>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(6) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq(4) strtk_parse_col_token_seq(5) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<5>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(5) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + strtk_parse_col_token_seq(4) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<4>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(4) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) strtk_parse_col_token_seq(3) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<3>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(3) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + strtk_parse_col_token_seq(2) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<2>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(2) + strtk_parse_col_token_seq(0) strtk_parse_col_token_seq(1) + return true; + } + + template class Sequence> + inline bool parse_columns(const InputIterator begin, + const InputIterator end, + const std::string& delimiters, + const details::column_list_impl<1>& column_list, + Sequence& seq) + { + strtk_parse_columns_impl(1) + strtk_parse_col_token_seq(0) + return true; + } + + #undef strtk_parse_col_token + #undef strtk_parse_col_token_seq + #undef strtk_parse_columns_impl + + #define strtk_parse_col_begin() \ + return parse_columns(data.data(), \ + data.data() + data.size(),delimiters,\ + column_list, \ + + #define strtk_parse_col_end() ); + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<12>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, + T10& t10, T11& t11) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<11>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, T9& t9, + T10& t10) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<10>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8, + T9& t9) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5,t6,t7,t8,t9 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<9>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7, T8& t8) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5,t6,t7,t8 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<8>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6, T7& t7) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5,t6,t7 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<7>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5, T6& t6) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5,t6 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<6>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4, + T5& t5) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4,t5 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<5>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3, T4& t4) + { + strtk_parse_col_begin() + t0,t1,t2,t3,t4 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<4>& column_list, + T0& t0, T1& t1, T2& t2, T3& t3) + { + strtk_parse_col_begin() + t0,t1,t2,t3 + strtk_parse_col_end(); + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<3>& column_list, + T0& t0, T1& t1, T2& t2) + { + strtk_parse_col_begin() + t0,t1,t2 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<2>& column_list, + T0& t0, T1& t1) + { + strtk_parse_col_begin() + t0,t1 + strtk_parse_col_end() + } + + template + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<1>& column_list, + T& t) + { + strtk_parse_col_begin() + t + strtk_parse_col_end() + } + + #undef strtk_parse_col_begin + #undef strtk_parse_col_end + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<12>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<11>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<10>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<9>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<8>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<7>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<6>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<5>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<4>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<3>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<2>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + template class Sequence> + inline bool parse_columns(const std::string& data, + const std::string& delimiters, + const details::column_list_impl<1>& column_list, + Sequence& seq) + { + strk_parse_col_seq + } + + #undef strk_parse_col_seq + + namespace details + { + typedef const unsigned char* ptr; + + template + bool cmpimpl(ptr c1, ptr c2) { return (*reinterpret_cast(c1)) == (*reinterpret_cast(c2)); } + + template + struct size_impl { static inline bool cmp(ptr,ptr) { return true; } }; + + template <> + struct size_impl<8> { static inline bool cmp(ptr c1, ptr c2) { return cmpimpl(c1,c2); } }; + + template <> + struct size_impl<4> { static inline bool cmp(ptr c1, ptr c2) { return cmpimpl(c1,c2); } }; + + template <> + struct size_impl<2> { static inline bool cmp(ptr c1, ptr c2) { return cmpimpl(c1,c2); } }; + + template <> + struct size_impl<1> { static inline bool cmp(ptr c1, ptr c2) { return cmpimpl(c1,c2); } }; + + template + struct next_size { enum { size = (N >= 8) ? 8 : ((N >= 4) ? 4 : ((N >= 2) ? 2 : 1)) }; }; + + template + struct memcmp_n_impl + { + static inline bool process(details::ptr c1, details::ptr c2) + { + static const std::size_t size = details::next_size::size; + return details::size_impl::cmp(c1,c2) && memcmp_n_impl::process(c1 + size, c2 + size); + } + + static inline bool process(const char* c1, const char* c2) + { + return memcmp_n_impl::process(reinterpret_cast(c1),reinterpret_cast(c2)); + } + + template + static inline bool process(const unsigned char (&c1)[K1], const unsigned char (&c2)[K2]) + { + return memcmp_n_impl::process(static_cast(c1),static_cast(c2)); + } + }; + + template<> struct memcmp_n_impl<0> { static inline bool process(ptr,ptr) { return true; } }; + } + + template + inline bool memcmp_n(details::ptr c1, details::ptr c2) + { + return details::memcmp_n_impl::process(c1,c2); + } + + template + inline bool memcmp_n(const char* c1, const char* c2) + { + return details::memcmp_n_impl::process(c1,c2); + } + + template + inline bool memcmp_n(const unsigned char (&c1)[K1], const unsigned char (&c2)[K2]) + { + return details::memcmp_n_impl::process(c1,c2); + } + + namespace details + { + inline bool type_to_string_converter_impl(const strtk::util::value& v, std::string& result, value_type_tag) + { + return v.to_string(result); + } + } + + template + inline std::size_t distance(const std::pair& p) + { + return std::distance(p.first,p.second); + } + + template + inline std::pair make_pair(const std::string& s) + { + return std::make_pair( + reinterpret_cast(const_cast(s.data())), + reinterpret_cast(const_cast(s.data() + s.size()))); + } + + template + inline std::pair make_pair(const std::pair p) + { + return std::make_pair( + reinterpret_cast(const_cast(p.first)), + reinterpret_cast(const_cast(p.second))); + } + + template + inline std::pair make_pair(const std::string& s) + { + return make_pair(s); + } + + template + inline std::pair make_pair(const std::pair& p) + { + return make_pair(p); + } + + template + inline std::pair make_pair(const strtk::range::string& range) + { + return std::make_pair( + reinterpret_cast(const_cast(range.begin())), + reinterpret_cast(const_cast(range.end()))); + } + + template + inline std::string make_string(const unsigned char (&s)[N], const std::size_t& length = N) + { + static const std::string null_string; + if (N < length) + return null_string; + else + return std::string(&s[0],&s[0] + length); + } + + template + inline std::string make_string(const char (&s)[N], const std::size_t& length = N) + { + static const std::string null_string; + if (N < length) + return null_string; + else + return std::string(&s[0],&s[0] + length); + } + + inline std::string make_string(const std::pair& range) + { + return std::string(range.first,range.second); + } + + template + inline bool clear_array(T (&a)[N], const T& t, const std::size_t& length = N) + { + if (N < length) + return false; + else + std::fill_n(&a[0],length,t); + return true; + } + + template + inline bool set_array(unsigned char (&a)[N], + const std::string& s, + const bool pad = false, + const unsigned char padding = '0') + { + if (N < s.size()) + return false; + std::copy(s.data(),s.data() + s.size(), &a[0]); + if ((s.size() < N) && pad) + std::fill_n(&a[s.size()],N - s.size(),padding); + return true; + } + + template + inline bool set_array(unsigned char (&dest)[N], + unsigned char (&src)[M], + const bool pad = false, + const unsigned char padding = '0') + { + if (N < M) + return false; + std::copy(src,src + N, &dest[0]); + if ((M < N) && pad) + std::fill_n(&dest[M],N - M,padding); + return true; + } + + inline void reverse(const std_string::iterator_type& range) + { + char* begin = const_cast(range.first); + char* end = const_cast(range.second); + std::reverse(begin,end); + } + + template + inline void reverse(const range::adapter& r) + { + T* begin = const_cast(r.begin()); + T* end = const_cast(r.end()); + std::reverse(begin,end); + } + + template + inline void reverse(const range::adapter& r) + { + T* begin = const_cast(r.begin()); + T* end = const_cast(r.end()); + std::reverse(begin,end); + } + + inline void reverse(std::string& s) + { + std::reverse(s.begin(),s.end()); + } + + inline void fill(std::string& s, const std::string::value_type v) + { + std::fill(const_cast(s.data()),const_cast(s.data() + s.size()), v); + } + + inline void fill(const std::pair& range, char v) + { + char* begin = const_cast(range.first); + char* end = const_cast(range.second); + std::fill(begin,end,v); + } + + template + inline void fill(const range::adapter& r, const typename range::adapter::value_type& v) + { + char* begin = const_cast(r.begin()); + char* end = const_cast(r.end()); + std::fill(begin,end,v); + } + + inline void fill(const std_string::iterator_type& range, const std::string::value_type& v) + { + char* begin = const_cast(range.first); + char* end = const_cast(range.second); + std::fill(begin,end,v); + } + + template class Sequence> + inline void fill(Sequence& seq, const T& t) + { + if (seq.empty()) + return; + std::fill_n(seq.begin(),seq.size(),t); + } + + namespace keyvalue + { + template + struct options + { + typedef CharType char_type; + + options() + : pair_block_delimiter(0), + pair_delimiter(0) + {} + + char_type pair_block_delimiter; + char_type pair_delimiter; + }; + + template + class parser + { + public: + + typedef unsigned char char_type; + typedef std::pair range_type; + + template + parser(const Options& opts) + : options_(opts), + kv_map_(opts), + pair_block_sdp_(options_.pair_block_delimiter), + pair_delimiter_sdp_(options_.pair_delimiter) + { + const std::size_t pair_list_default_size = 32; + pair_list_.reserve(pair_list_default_size); + } + + template + inline bool register_keyvalue(const typename KeyValueMap::key_type& key, T& t) + { + return kv_map_.register_keyvalue(key,t); + } + + inline bool operator()(const range_type& data, const bool ignore_failures = false) + { + if (!ignore_failures) + { + pair_list_.clear(); + const std::size_t pair_count = split(pair_block_sdp_, + data.first, + data.second, + std::back_inserter(pair_list_)); + + if (0 == pair_count) + return false; + + range_type key_range; + range_type value_range; + + for (std::size_t i = 0; i < pair_count; ++i) + { + const range_type& r = pair_list_[i]; + if (0 == std::distance(r.first,r.second)) + continue; + else if (!split_pair(r.first,r.second, + pair_delimiter_sdp_, + key_range,value_range)) + return false; + else if (!kv_map_(key_range,value_range)) + return false; + } + return true; + } + else + { + parse_failures_ = 0; + pair_token_processor processor(*this); + split(pair_block_sdp_, + data.first, + data.second, + strtk::functional_inserter(processor)); + return true; + } + } + + inline bool operator()(const std::string& s, const bool ignore_failures = false) + { + return operator()(strtk::make_pair(s),ignore_failures); + } + + inline std::size_t failure_count() const + { + return parse_failures_; + } + + private: + + class pair_token_processor + { + public: + + pair_token_processor(parser& p) + : parser_(p) + {} + + inline void operator()(const range_type& r) + { + if (r.first == r.second) + return; + if (split_pair(r.first,r.second, + parser_.pair_delimiter_sdp_, + key_range, + value_range)) + { + if (parser_.kv_map_(key_range,value_range)) + return; + } + ++parser_.parse_failures_; + } + + private: + + pair_token_processor operator=(const pair_token_processor&); + + parser& parser_; + range_type key_range; + range_type value_range; + }; + + options options_; + std::size_t parse_failures_; + KeyValueMap kv_map_; + single_delimiter_predicate pair_block_sdp_; + single_delimiter_predicate pair_delimiter_sdp_; + std::vector pair_list_; + }; + + class uintkey_map + { + private: + + typedef unsigned char char_type; + typedef strtk::keyvalue::options general_options; + + public: + + typedef unsigned int key_type; + + struct options : public general_options + { + options() + : general_options(), + key_count(0) + {} + + std::size_t key_count; + }; + + template + uintkey_map(const Options& options) + { + value_lut_.resize(options.key_count,strtk::util::value()); + } + + virtual ~uintkey_map() + {} + + template + inline bool operator()(const Range& key_range, const Range& value_range) + { + std::size_t key = 0; + if (!fast::numeric_convert(distance(key_range),key_range.first,key,true)) + return false; + if (key >= value_lut_.size()) + return false; + const strtk::util::value& v = value_lut_[key]; + if (!v) + return false; + else + return v(value_range); + } + + template + inline bool register_keyvalue(const key_type& key, T& t) + { + if (key < value_lut_.size()) + { + strtk::util::value& v = value_lut_[key]; + if (!v) + v = strtk::util::value(t); + else + v.assign(t); + return true; + } + else + return false; + } + + private: + + std::vector value_lut_; + }; + + namespace details + { + template + struct keygen + { + static inline KType transform(const Range&) + { + return KType(); + } + }; + + template + struct keygen + { + static inline std::string transform(const Range& key_range) + { + return std::string(key_range.first,key_range.second); + } + }; + + template + struct keygen + { + static inline unsigned int transform(const Range& key_range) + { + unsigned int result = 0; + if (strtk::fast::numeric_convert(std::distance(key_range.first,key_range.second),key_range.first,result,true)) + return result; + else + return std::numeric_limits::max(); + } + }; + + struct no_op_validator + { + template + inline bool operator()(const Range&) + { + return true; + } + }; + } + + template , + typename KeyValidator = details::no_op_validator, + typename ValueValidator = details::no_op_validator> + class key_map + { + public: + + typedef KeyType key_type; + typedef MapType map_type; + typedef KeyValidator key_validator_type; + typedef ValueValidator value_validator_type; + + template + key_map(const Options&) + {} + + virtual ~key_map() + {} + + template + inline bool operator()(const Range& key_range, const Range& value_range) + { + if (!key_validator_(key_range)) + return false; + if (!val_validator_(value_range)) + return false; + typename map_type::iterator itr = value_map_.find(details::keygen::transform(key_range)); + if (value_map_.end() == itr) + return false; + const util::value& v = (*itr).second; + if (!v) + return false; + else + return v(value_range); + } + + template + inline bool register_keyvalue(const key_type& key, T& t) + { + strtk::util::value& v = value_map_[key]; + if (!v) + v = strtk::util::value(t); + else + v.assign(t); + return true; + } + + private: + + map_type value_map_; + key_validator_type key_validator_; + value_validator_type val_validator_; + }; + + typedef key_map stringkey_map; + + } +} // namespace strtk + +namespace +{ + + static inline std::ostream& operator<<(std::ostream& os, + const strtk::std_string::tokenizer >::type::iterator& range) + { + os << std::string((*range).first,(*range).second); + return os; + } + + static inline std::ostream& operator<<(std::ostream& os, + const strtk::std_string::tokenizer >::type::iterator& range) + { + os << std::string((*range).first,(*range).second); + return os; + } + + static inline std::ostream& operator<<(std::ostream& os, + const strtk::std_string::tokenizer::type::iterator& range) + { + os << std::string((*range).first,(*range).second); + return os; + } + + #define strtk_register_pair_to_ostream(Iterator) \ + static inline std::ostream& operator<<(std::ostream& os, const std::pair& range)\ + { os << std::string(range.first,range.second); return os; } \ + static inline std::ostream& operator<<(std::ostream& os, std::pair& range) \ + { os << std::string(range.first,range.second); return os; } \ + + strtk_register_pair_to_ostream(char*) + strtk_register_pair_to_ostream(unsigned char*) + strtk_register_pair_to_ostream(const char*) + strtk_register_pair_to_ostream(const unsigned char*) + strtk_register_pair_to_ostream(std::string::iterator) + strtk_register_pair_to_ostream(std::string::const_iterator) + strtk_register_pair_to_ostream(const std::string::iterator) + strtk_register_pair_to_ostream(const std::string::const_iterator) + + #undef strtk_register_pair_to_ostream + +} // namespace anonymous + +#if 0 + +#ifdef WIN32 + #ifndef NOMINMAX + #define NOMINMAX + #endif + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #include +#else + #include + #include +#endif +namespace strtk +{ + namespace util + { + class timer + { + public: + + #ifdef WIN32 + timer() + : in_use_(false) + { + QueryPerformanceFrequency(&clock_frequency_); + } + + inline void start() + { + in_use_ = true; + QueryPerformanceCounter(&start_time_); + } + + inline void stop() + { + QueryPerformanceCounter(&stop_time_); + in_use_ = false; + } + + inline double time() const + { + return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); + } + + #else + + timer() + : in_use_(false) + { + start_time_.tv_sec = 0; + start_time_.tv_usec = 0; + stop_time_.tv_sec = 0; + stop_time_.tv_usec = 0; + } + + inline void start() + { + in_use_ = true; + gettimeofday(&start_time_,0); + } + + inline void stop() + { + gettimeofday(&stop_time_, 0); + in_use_ = false; + } + + inline unsigned long long int usec_time() const + { + if (!in_use_) + { + if (stop_time_.tv_sec >= start_time_.tv_sec) + { + return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) + + (stop_time_.tv_usec - start_time_.tv_usec); + } + else + return std::numeric_limits::max(); + } + else + return std::numeric_limits::max(); + } + + inline double time() const + { + return usec_time() * 0.000001; + } + + #endif + + inline bool in_use() const + { + return in_use_; + } + + private: + + bool in_use_; + + #ifdef WIN32 + LARGE_INTEGER start_time_; + LARGE_INTEGER stop_time_; + LARGE_INTEGER clock_frequency_; + #else + struct timeval start_time_; + struct timeval stop_time_; + #endif + }; + + class scoped_timer + { + public: + + scoped_timer(double& time_value) + : time_value_(time_value) + { + t_.start(); + } + + ~scoped_timer() + { + t_.stop(); + time_value_ = t_.time(); + } + + private: + + scoped_timer(const scoped_timer&); + scoped_timer& operator=(const scoped_timer&); + + double& time_value_; + timer t_; + }; + + } // namespace util + + namespace information + { + static const char* library = "String Toolkit"; + static const char* version = "2.718281828459045235360287471352662497757247093699959574"; + static const char* date = "20140118"; + + static inline std::string data() + { + static const std::string info_str = std::string(library) + + std::string(" v") + std::string(version) + + std::string(" (") + date + std::string(")"); + return info_str; + } + + } // namespace information + +} // namespace strtk + +#endif + +#endif \ No newline at end of file From 46eeb46a61872b6573a7d816ac5bdba82ac86075 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 17 Jul 2014 02:26:20 +0800 Subject: [PATCH 2/6] Implemented faster itoa with bit counting and reverse write --- include/rapidjson/rapidjson.h | 1 + test/perftest/misctest.cpp | 558 ++++++++++++++++++++++++++++++---- 2 files changed, 501 insertions(+), 58 deletions(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 1608ce899..80ddce012 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -362,6 +362,7 @@ struct GenericInsituStringStream { // Write Ch* PutBegin() { return dst_ = src_; } void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + Ch* Allocate(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } void Flush() {} size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index 94c2ef2d1..cc2cc3399 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -3,14 +3,23 @@ #if TEST_MISC #define __STDC_FORMAT_MACROS +#include "rapidjson/stringbuffer.h" + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4996) +#endif #define strtk_no_tr1_or_boost #include "strtk/strtk.hpp" -#include "rapidjson/stringbuffer.h" + +#ifdef _MSC_VER +#pragma warning (pop) +#endif #ifdef _MSC_VER #pragma warning (push) -#pragma warning (disable: 4245; disable: 4512) +#pragma warning (disable: 4245; disable: 4512; disable: 4996) #endif #include "cppformat/format.h" @@ -76,6 +85,154 @@ TEST_F(Misc, Hoehrmann_IsUTF8) { } } +//////////////////////////////////////////////////////////////////////////////// +// CountDecimalDigit: Count number of decimal places + +inline unsigned CountDecimalDigit_naive(unsigned n) { + unsigned count = 1; + while (n >= 10) { + n /= 10; + count++; + } + return count; +} + +inline unsigned CountDecimalDigit_enroll4(unsigned n) { + unsigned count = 1; + while (n >= 10000) { + n /= 10000u; + count += 4; + } + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + return count + 3; +} + +inline unsigned CountDecimalDigit64_enroll4(uint64_t n) { + unsigned count = 1; + while (n >= 10000) { + n /= 10000u; + count += 4; + } + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + return count + 3; +} + +inline unsigned CountDecimalDigit_fast(unsigned n) { + static const uint32_t powers_of_10[] = { + 0, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + }; + + unsigned long i = 0; + // uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; + _BitScanReverse(&i, n | 1); + uint32_t t = (i + 1) * 1233 >> 12; + return t - (n < powers_of_10[t]) + 1; +} + +inline unsigned CountDecimalDigit64_fast(uint64_t n) { + static const uint64_t powers_of_10[] = { + 0, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U + }; + + unsigned long i = 0; + // uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; + +#if _M_IX86 + uint64_t m = n | 1; + if (_BitScanReverse(&i, m >> 32)) + i += 32; + else + _BitScanReverse(&i, m & 0xFFFFFFFF); +#elif _M_X64 + _BitScanReverse64(&i, n | 1); +#else +#error +#endif + + uint32_t t = (i + 1) * 1233 >> 12; + return t - (n < powers_of_10[t]) + 1; +} + +#if 0 +// Exhaustive, very slow +TEST_F(Misc, CountDecimalDigit_Verify) { + unsigned i = 0; + do { + if (i % (65536 * 256) == 0) + printf("%u\n", i); + ASSERT_EQ(CountDecimalDigit_enroll4(i), CountDecimalDigit_fast(i)); + i++; + } while (i != 0); +} + +static const unsigned kDigits10Trial = 1000000000u; +TEST_F(Misc, CountDecimalDigit_naive) { + unsigned sum = 0; + for (unsigned i = 0; i < kDigits10Trial; i++) + sum += CountDecimalDigit_naive(i); + printf("%u\n", sum); +} + +TEST_F(Misc, CountDecimalDigit_enroll4) { + unsigned sum = 0; + for (unsigned i = 0; i < kDigits10Trial; i++) + sum += CountDecimalDigit_enroll4(i); + printf("%u\n", sum); +} + +TEST_F(Misc, CountDecimalDigit_fast) { + unsigned sum = 0; + for (unsigned i = 0; i < kDigits10Trial; i++) + sum += CountDecimalDigit_fast(i); + printf("%u\n", sum); +} +#endif + +TEST_F(Misc, CountDecimalDigit64_VerifyFast) { + uint64_t i = 1, j; + do { + printf("%" PRIu64 "\n", i); + ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i)); + j = i; + i *= 3; + } while (j < i); +} + +//////////////////////////////////////////////////////////////////////////////// +// integer-to-string conversion + // https://gist.github.com/anonymous/7179097 static const int randval[] ={ 936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064, @@ -185,6 +342,13 @@ static const int randval[] ={ static const size_t randvalCount = sizeof(randval) / sizeof(randval[0]); static const size_t kItoaTrialCount = 10000; +static const char digits[201] = +"0001020304050607080910111213141516171819" +"2021222324252627282930313233343536373839" +"4041424344454647484950515253545556575859" +"6061626364656667686970717273747576777879" +"8081828384858687888990919293949596979899"; + // Prevent code being optimized out #define OUTPUT_LENGTH(length) printf("", length) //#define OUTPUT_LENGTH(length) printf("%d\n", length) @@ -250,12 +414,22 @@ class Writer1 { OutputStream* os_; }; -static const char digits[201] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; +template<> +inline bool Writer1::WriteUint(unsigned u) { + char buffer[10]; + char* p = buffer; + do { + *p++ = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + + char* d = os_->Allocate(p - buffer); + do { + --p; + *d++ = *p; + } while (p != buffer); + return true; +} // Using digits LUT to reduce divsion/modulo template @@ -337,8 +511,254 @@ class Writer2 { OutputStream* os_; }; +// First pass to count digits +template +class Writer3 { +public: + Writer3() : os_() {} + Writer3(OutputStream& os) : os_(&os) {} + + void Reset(OutputStream& os) { + os_ = &os; + } + + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } + + bool WriteUint(unsigned u) { + char buffer[10]; + char *p = buffer; + do { + *p++ = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char *p = buffer; + do { + *p++ = char(u64 % 10) + '0'; + u64 /= 10; + } while (u64 > 0); + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + +private: + void WriteUintReverse(char* d, unsigned u) { + do { + *--d = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + } + + void WriteUint64Reverse(char* d, uint64_t u) { + do { + *--d = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + } + + OutputStream* os_; +}; + +template<> +inline bool Writer3::WriteUint(unsigned u) { + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Allocate(digit) + digit, u); + return true; +} + +template<> +inline bool Writer3::WriteUint(unsigned u) { + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Allocate(digit) + digit, u); + return true; +} + +template<> +inline bool Writer3::WriteUint64(uint64_t u) { + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Allocate(digit) + digit, u); + return true; +} + +template<> +inline bool Writer3::WriteUint64(uint64_t u) { + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Allocate(digit) + digit, u); + return true; +} + +// Using digits LUT to reduce divsion/modulo, two passes +template +class Writer4 { +public: + Writer4() : os_() {} + Writer4(OutputStream& os) : os_(&os) {} + + void Reset(OutputStream& os) { + os_ = &os; + } + + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } + + bool WriteUint(unsigned u) { + char buffer[10]; + char* p = buffer; + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u < 10) + *p++ = char(u) + '0'; + else { + const unsigned i = u << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* p = buffer; + while (u64 >= 100) { + const unsigned i = static_cast(u64 % 100) << 1; + u64 /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u64 < 10) + *p++ = char(u64) + '0'; + else { + const unsigned i = static_cast(u64) << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } + +private: + void WriteUintReverse(char* d, unsigned u) { + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *--d = digits[i + 1]; + *--d = digits[i]; + } + if (u < 10) { + *--d = char(u) + '0'; + } + else { + const unsigned i = u << 1; + *--d = digits[i + 1]; + *--d = digits[i]; + } + } + + void WriteUint64Reverse(char* d, uint64_t u) { + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *--d = digits[i + 1]; + *--d = digits[i]; + } + if (u < 10) { + *--d = char(u) + '0'; + } + else { + const unsigned i = u << 1; + *--d = digits[i + 1]; + *--d = digits[i]; + } + } + + OutputStream* os_; +}; + +template<> +inline bool Writer4::WriteUint(unsigned u) { + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Allocate(digit) + digit, u); + return true; +} + +template<> +inline bool Writer4::WriteUint(unsigned u) { + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Allocate(digit) + digit, u); + return true; +} + +template<> +inline bool Writer4::WriteUint64(uint64_t u) { + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Allocate(digit) + digit, u); + return true; +} + +template<> +inline bool Writer4::WriteUint64(uint64_t u) { + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Allocate(digit) + digit, u); + return true; +} + template -void itoa_Writer_Verify() { +void itoa_Writer_StringBufferVerify() { rapidjson::StringBuffer sb; Writer writer(sb); for (int j = 0; j < randvalCount; j++) { @@ -350,6 +770,23 @@ void itoa_Writer_Verify() { } } +template +void itoa_Writer_InsituStringStreamVerify() { + Writer writer; + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + sprintf(buffer, "%d", randval[j]); + char buffer2[32]; + rapidjson::InsituStringStream ss(buffer2); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt(randval[j]); + ss.Put('\0'); + ss.PutEnd(begin); + ASSERT_STREQ(buffer, buffer2); + } +} + template void itoa_Writer_StringBuffer() { size_t length = 0; @@ -386,7 +823,7 @@ void itoa_Writer_InsituStringStream() { }; template -void itoa64_Writer_Verify() { +void itoa64_Writer_StringBufferVerify() { rapidjson::StringBuffer sb; Writer writer(sb); for (int j = 0; j < randvalCount; j++) { @@ -399,6 +836,24 @@ void itoa64_Writer_Verify() { } } +template +void itoa64_Writer_InsituStringStreamVerify() { + Writer writer; + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + int64_t x = randval[j] * randval[j]; + sprintf(buffer, "%" PRIi64, x); + char buffer2[32]; + rapidjson::InsituStringStream ss(buffer2); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt64(x); + ss.Put('\0'); + ss.PutEnd(begin); + ASSERT_STREQ(buffer, buffer2); + } +} + template void itoa64_Writer_StringBuffer() { size_t length = 0; @@ -434,53 +889,39 @@ void itoa64_Writer_InsituStringStream() { OUTPUT_LENGTH(length); }; -TEST_F(Misc, itoa_Writer1_Verify) { - itoa_Writer_Verify >(); -} - -TEST_F(Misc, itoa_Writer2_Verify) { - itoa_Writer_Verify >(); -} - -TEST_F(Misc, itoa_Writer1_StringBuffer) { - itoa_Writer_StringBuffer >(); -} - -TEST_F(Misc, itoa_Writer1_InsituStringStream) { - itoa_Writer_InsituStringStream >(); -} - -TEST_F(Misc, itoa_Writer2_StringBuffer) { - itoa_Writer_StringBuffer >(); -} - -TEST_F(Misc, itoa_Writer2_InsituStringStream) { - itoa_Writer_InsituStringStream >(); -} - -TEST_F(Misc, itoa64_Writer1_Verify) { - itoa64_Writer_Verify >(); -} - -TEST_F(Misc, itoa64_Writer2_Verify) { - itoa64_Writer_Verify >(); -} - -TEST_F(Misc, itoa64_Writer1_StringBuffer) { - itoa64_Writer_StringBuffer >(); -} - -TEST_F(Misc, itoa64_Writer1_InsituStringStream) { - itoa64_Writer_InsituStringStream >(); -} - -TEST_F(Misc, itoa64_Writer2_StringBuffer) { - itoa64_Writer_StringBuffer >(); -} - -TEST_F(Misc, itoa64_Writer2_InsituStringStream) { - itoa64_Writer_InsituStringStream >(); -} +TEST_F(Misc, itoa_Writer1_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa_Writer2_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa_Writer3_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa_Writer4_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa_Writer1_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa_Writer2_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa_Writer3_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa_Writer4_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa_Writer1_StringBuffer) { itoa_Writer_StringBuffer >(); } +TEST_F(Misc, itoa_Writer2_StringBuffer) { itoa_Writer_StringBuffer >(); } +TEST_F(Misc, itoa_Writer3_StringBuffer) { itoa_Writer_StringBuffer >(); } +TEST_F(Misc, itoa_Writer4_StringBuffer) { itoa_Writer_StringBuffer >(); } +TEST_F(Misc, itoa_Writer1_InsituStringStream) { itoa_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa_Writer2_InsituStringStream) { itoa_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa_Writer3_InsituStringStream) { itoa_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa_Writer4_InsituStringStream) { itoa_Writer_InsituStringStream >(); } + +TEST_F(Misc, itoa64_Writer1_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa64_Writer2_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa64_Writer3_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa64_Writer4_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa64_Writer1_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa64_Writer2_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa64_Writer3_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa64_Writer4_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa64_Writer1_StringBuffer) { itoa64_Writer_StringBuffer >(); } +TEST_F(Misc, itoa64_Writer2_StringBuffer) { itoa64_Writer_StringBuffer >(); } +TEST_F(Misc, itoa64_Writer3_StringBuffer) { itoa64_Writer_StringBuffer >(); } +TEST_F(Misc, itoa64_Writer4_StringBuffer) { itoa64_Writer_StringBuffer >(); } +TEST_F(Misc, itoa64_Writer1_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa64_Writer2_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa64_Writer3_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa64_Writer4_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } TEST_F(Misc, itoa_sprintf) { size_t length = 0; @@ -498,7 +939,8 @@ TEST_F(Misc, itoa64_sprintf) { for (int i = 0; i < kItoaTrialCount; i++) { for (int j = 0; j < randvalCount; j++) { char buffer[32]; - length += sprintf(buffer, "%" PRIi64, randval[j] * randval[j]); + int64_t x = randval[j] * randval[j]; + length += sprintf(buffer, "%" PRIi64, x); } } OUTPUT_LENGTH(length); From e1cdf1229e69c9dab929eb9e033d5a4cc40c99da Mon Sep 17 00:00:00 2001 From: miloyip Date: Thu, 17 Jul 2014 13:28:40 +0800 Subject: [PATCH 3/6] Pass GCC compilation --- test/perftest/misctest.cpp | 73 +++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index cc2cc3399..f1be65904 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -80,7 +80,7 @@ static bool IsUTF8(unsigned char* s) { } TEST_F(Misc, Hoehrmann_IsUTF8) { - for (int i = 0; i < kTrialCount; i++) { + for (size_t i = 0; i < kTrialCount; i++) { EXPECT_TRUE(IsUTF8((unsigned char*)json_)); } } @@ -135,10 +135,15 @@ inline unsigned CountDecimalDigit_fast(unsigned n) { 1000000000 }; +#if defined(_M_IX86) || defined(_M_X64) unsigned long i = 0; - // uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; _BitScanReverse(&i, n | 1); uint32_t t = (i + 1) * 1233 >> 12; +#elif defined(__GNUC__) + uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; +#else +#error +#endif return t - (n < powers_of_10[t]) + 1; } @@ -166,22 +171,24 @@ inline unsigned CountDecimalDigit64_fast(uint64_t n) { 10000000000000000000U }; - unsigned long i = 0; - // uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; - -#if _M_IX86 +#if defined(_M_IX86) uint64_t m = n | 1; + unsigned long i = 0; if (_BitScanReverse(&i, m >> 32)) i += 32; else _BitScanReverse(&i, m & 0xFFFFFFFF); -#elif _M_X64 + uint32_t t = (i + 1) * 1233 >> 12; +#elif defined(_M_X64) + unsigned long i = 0; _BitScanReverse64(&i, n | 1); + uint32_t t = (i + 1) * 1233 >> 12; +#elif defined(__GNUC__) + uint32_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; #else #error #endif - uint32_t t = (i + 1) * 1233 >> 12; return t - (n < powers_of_10[t]) + 1; } @@ -223,7 +230,7 @@ TEST_F(Misc, CountDecimalDigit_fast) { TEST_F(Misc, CountDecimalDigit64_VerifyFast) { uint64_t i = 1, j; do { - printf("%" PRIu64 "\n", i); + //printf("%" PRIu64 "\n", i); ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i)); j = i; i *= 3; @@ -350,8 +357,8 @@ static const char digits[201] = "8081828384858687888990919293949596979899"; // Prevent code being optimized out -#define OUTPUT_LENGTH(length) printf("", length) -//#define OUTPUT_LENGTH(length) printf("%d\n", length) +//#define OUTPUT_LENGTH(length) printf("", length) +#define OUTPUT_LENGTH(length) printf("%d\n", length) template class Writer1 { @@ -794,8 +801,8 @@ void itoa_Writer_StringBuffer() { rapidjson::StringBuffer sb; Writer writer(sb); - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { writer.WriteInt(randval[j]); length += sb.GetSize(); sb.Clear(); @@ -810,8 +817,8 @@ void itoa_Writer_InsituStringStream() { char buffer[32]; Writer writer; - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { rapidjson::InsituStringStream ss(buffer); writer.Reset(ss); char* begin = ss.PutBegin(); @@ -826,7 +833,7 @@ template void itoa64_Writer_StringBufferVerify() { rapidjson::StringBuffer sb; Writer writer(sb); - for (int j = 0; j < randvalCount; j++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; int64_t x = randval[j] * randval[j]; sprintf(buffer, "%" PRIi64, x); @@ -839,7 +846,7 @@ void itoa64_Writer_StringBufferVerify() { template void itoa64_Writer_InsituStringStreamVerify() { Writer writer; - for (int j = 0; j < randvalCount; j++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; int64_t x = randval[j] * randval[j]; sprintf(buffer, "%" PRIi64, x); @@ -861,8 +868,8 @@ void itoa64_Writer_StringBuffer() { rapidjson::StringBuffer sb; Writer writer(sb); - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { writer.WriteInt64(randval[j] * randval[j]); length += sb.GetSize(); sb.Clear(); @@ -877,8 +884,8 @@ void itoa64_Writer_InsituStringStream() { char buffer[32]; Writer writer; - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { rapidjson::InsituStringStream ss(buffer); writer.Reset(ss); char* begin = ss.PutBegin(); @@ -925,8 +932,8 @@ TEST_F(Misc, itoa64_Writer4_InsituStringStream) { itoa64_Writer_InsituStringStre TEST_F(Misc, itoa_sprintf) { size_t length = 0; - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; length += sprintf(buffer, "%d", randval[j]); } @@ -936,8 +943,8 @@ TEST_F(Misc, itoa_sprintf) { TEST_F(Misc, itoa64_sprintf) { size_t length = 0; - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { char buffer[32]; int64_t x = randval[j] * randval[j]; length += sprintf(buffer, "%" PRIi64, x); @@ -950,8 +957,8 @@ TEST_F(Misc, itoa_strtk) { size_t length = 0; std::string s; s.reserve(32); - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { s = strtk::type_to_string(randval[j]); length += s.size(); } @@ -963,8 +970,8 @@ TEST_F(Misc, itoa64_strtk) { size_t length = 0; std::string s; s.reserve(32); - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { int64_t x = randval[j] * randval[j]; s = strtk::type_to_string(x); length += s.size(); @@ -976,8 +983,8 @@ TEST_F(Misc, itoa64_strtk) { TEST_F(Misc, itoa_cppformat) { size_t length = 0; char buffer[32]; - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { char* p = buffer; fmt::FormatDec(p, randval[j]); length += (p - buffer); @@ -989,8 +996,8 @@ TEST_F(Misc, itoa_cppformat) { TEST_F(Misc, itoa64_cppformat) { size_t length = 0; char buffer[32]; - for (int i = 0; i < kItoaTrialCount; i++) { - for (int j = 0; j < randvalCount; j++) { + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { char* p = buffer; int64_t x = randval[j] * randval[j]; fmt::FormatDec(p, x); From 74a135678a9994be50cab0cd9ef0b899b2753f57 Mon Sep 17 00:00:00 2001 From: miloyip Date: Thu, 17 Jul 2014 17:47:51 +0800 Subject: [PATCH 4/6] Add VC itoa perf comparison --- test/perftest/misctest.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index f1be65904..f844fb71e 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -422,7 +422,7 @@ class Writer1 { }; template<> -inline bool Writer1::WriteUint(unsigned u) { +bool Writer1::WriteUint(unsigned u) { char buffer[10]; char* p = buffer; do { @@ -953,6 +953,32 @@ TEST_F(Misc, itoa64_sprintf) { OUTPUT_LENGTH(length); } +#ifdef _MSC_VER +TEST_F(Misc, itoa_VC) { + size_t length = 0; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + _itoa(randval[j], buffer, 10); + length += strlen(buffer); + } + } + OUTPUT_LENGTH(length); +} + +TEST_F(Misc, itoa64_VC) { + size_t length = 0; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + _i64toa(randval[j] * randval[j], buffer, 10); + length += strlen(buffer); + } + } + OUTPUT_LENGTH(length); +} +#endif + TEST_F(Misc, itoa_strtk) { size_t length = 0; std::string s; From 86b2f51a58c0dd5cb9732f8d1f7edcc88b25ce0f Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 25 Jul 2014 00:08:24 +0800 Subject: [PATCH 5/6] Use branchlut implementation for itoa conversion. --- include/rapidjson/internal/itoa.h | 280 ++++++++++++++++++++++++++++++ include/rapidjson/rapidjson.h | 9 +- include/rapidjson/stringbuffer.h | 3 +- include/rapidjson/writer.h | 83 +++++---- test/perftest/misctest.cpp | 71 ++++++-- 5 files changed, 403 insertions(+), 43 deletions(-) create mode 100644 include/rapidjson/internal/itoa.h diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h new file mode 100644 index 000000000..7e040ef4e --- /dev/null +++ b/include/rapidjson/internal/itoa.h @@ -0,0 +1,280 @@ +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ + +namespace rapidjson { +namespace internal { + +// Modified from https://github.com/miloyip/itoa-benchmark/blob/master/src/branchlut.cpp +// API is changed to return the character passed the end of string, without writing '\0' + +inline const char* GetDigitsLut() { + static const char cDigitsLut[200] = { + '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' + }; + return cDigitsLut; +} + +inline char* u32toa(uint32_t value, char* buffer) { + const char* cDigitsLut = GetDigitsLut(); + + if (value < 10000) { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else if (value < 100000000) { + // value = bbbbcccc + const uint32_t b = value / 10000; + const uint32_t c = value % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + else { + // value = aabbbbcccc in decimal + + const uint32_t a = value / 100000000; // 1 to 42 + value %= 100000000; + + if (a >= 10) { + const unsigned i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + *buffer++ = '0' + static_cast(a); + + const uint32_t b = value / 10000; // 0 to 9999 + const uint32_t c = value % 10000; // 0 to 9999 + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + return buffer; +} + +inline char* i32toa(int32_t value, char* buffer) { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + + return u32toa(static_cast(value), buffer); +} + +inline char* u64toa(uint64_t value, char* buffer) { + const char* cDigitsLut = GetDigitsLut(); + + if (value < 100000000) { + uint32_t v = static_cast(value); + if (v < 10000) { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) + *buffer++ = cDigitsLut[d1]; + if (v >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (v >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else { + // value = bbbbcccc + const uint32_t b = v / 10000; + const uint32_t c = v % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + } + else if (value < 10000000000000000) { + const uint32_t v0 = static_cast(value / 100000000); + const uint32_t v1 = static_cast(value % 100000000); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + if (value >= 1000000000000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100000000000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10000000000000) + *buffer++ = cDigitsLut[d2]; + if (value >= 1000000000000) + *buffer++ = cDigitsLut[d2 + 1]; + if (value >= 100000000000) + *buffer++ = cDigitsLut[d3]; + if (value >= 10000000000) + *buffer++ = cDigitsLut[d3 + 1]; + if (value >= 1000000000) + *buffer++ = cDigitsLut[d4]; + if (value >= 100000000) + *buffer++ = cDigitsLut[d4 + 1]; + + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + else { + const uint32_t a = static_cast(value / 10000000000000000); // 1 to 1844 + value %= 10000000000000000; + + if (a < 10) + *buffer++ = '0' + static_cast(a); + else if (a < 100) { + const uint32_t i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else if (a < 1000) { + *buffer++ = '0' + static_cast(a / 100); + + const uint32_t i = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else { + const uint32_t i = (a / 100) << 1; + const uint32_t j = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + *buffer++ = cDigitsLut[j]; + *buffer++ = cDigitsLut[j + 1]; + } + + const uint32_t v0 = static_cast(value / 100000000); + const uint32_t v1 = static_cast(value % 100000000); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + + return buffer; +} + +inline char* i64toa(int64_t value, char* buffer) { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + + return u64toa(static_cast(value), buffer); +} + +} // namespace internal +} // namespace rapidjson + +#endif // RAPIDJSON_ITOA_ diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 80ddce012..903dee15e 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -360,11 +360,14 @@ struct GenericInsituStringStream { size_t Tell() { return static_cast(src_ - head_); } // Write - Ch* PutBegin() { return dst_ = src_; } void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } - Ch* Allocate(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } - void Flush() {} + + Ch* PutBegin() { return dst_ = src_; } size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} + + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } Ch* src_; Ch* dst_; diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h index 8c7eb4f17..0e89f959c 100644 --- a/include/rapidjson/stringbuffer.h +++ b/include/rapidjson/stringbuffer.h @@ -22,7 +22,8 @@ struct GenericStringBuffer { void Flush() {} void Clear() { stack_.Clear(); } - Ch* Allocate(size_t count) { return stack_.template Push(count); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetString() const { // Push and pop a null terminator. This is safe. diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 0b0be0876..c6cdfdd4c 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -4,6 +4,8 @@ #include "rapidjson.h" #include "internal/stack.h" #include "internal/strfunc.h" +#include "internal/itoa.h" +#include "stringbuffer.h" #include // snprintf() or _sprintf_s() #include // placement new @@ -44,6 +46,10 @@ class Writer { os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)), doublePrecision_(kDefaultDoublePrecision), hasRoot_(false) {} + Writer(Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), + doublePrecision_(kDefaultDoublePrecision), hasRoot_(false) {} + //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, @@ -208,49 +214,34 @@ class Writer { } bool WriteInt(int i) { - if (i < 0) { - os_->Put('-'); - i = -i; - } - return WriteUint((unsigned)i); + char buffer[11]; + const char* end = internal::i32toa(i, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; } bool WriteUint(unsigned u) { char buffer[10]; - char *p = buffer; - do { - *p++ = char(u % 10) + '0'; - u /= 10; - } while (u > 0); - - do { - --p; + const char* end = internal::u32toa(u, buffer); + for (const char* p = buffer; p != end; ++p) os_->Put(*p); - } while (p != buffer); return true; } bool WriteInt64(int64_t i64) { - if (i64 < 0) { - os_->Put('-'); - i64 = -i64; - } - WriteUint64((uint64_t)i64); + char buffer[21]; + const char* end = internal::i64toa(i64, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); return true; } bool WriteUint64(uint64_t u64) { - char buffer[20]; - char *p = buffer; - do { - *p++ = char(u64 % 10) + '0'; - u64 /= 10; - } while (u64 > 0); - - do { - --p; + char buffer[11]; + const char* end = internal::u64toa(u64, buffer); + for (const char* p = buffer; p != end; ++p) os_->Put(*p); - } while (p != buffer); return true; } @@ -378,6 +369,40 @@ class Writer { Writer& operator=(const Writer&); }; +// Full specialization for StringStream to prevent memory copying + +template<> +inline bool Writer::WriteInt(int i) { + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(11 - (end - buffer)); + return true; +} + +template<> +inline bool Writer::WriteUint(unsigned u) { + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(10 - (end - buffer)); + return true; +} + +template<> +inline bool Writer::WriteInt64(int64_t i64) { + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(21 - (end - buffer)); + return true; +} + +template<> +inline bool Writer::WriteUint64(uint64_t u) { + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(20 - (end - buffer)); + return true; +} + } // namespace rapidjson #ifdef _MSC_VER diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index f844fb71e..dfa50f839 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -29,6 +29,10 @@ #pragma warning (pop) #endif +#define protected public +#include "rapidjson/writer.h" +#undef private + class Misc : public PerfTest { }; @@ -358,7 +362,7 @@ static const char digits[201] = // Prevent code being optimized out //#define OUTPUT_LENGTH(length) printf("", length) -#define OUTPUT_LENGTH(length) printf("%d\n", length) +#define OUTPUT_LENGTH(length) printf("%u\n", (unsigned)length) template class Writer1 { @@ -430,7 +434,7 @@ bool Writer1::WriteUint(unsigned u) { u /= 10; } while (u > 0); - char* d = os_->Allocate(p - buffer); + char* d = os_->Push(p - buffer); do { --p; *d++ = *p; @@ -597,28 +601,28 @@ class Writer3 { template<> inline bool Writer3::WriteUint(unsigned u) { unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Allocate(digit) + digit, u); + WriteUintReverse(os_->Push(digit) + digit, u); return true; } template<> inline bool Writer3::WriteUint(unsigned u) { unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Allocate(digit) + digit, u); + WriteUintReverse(os_->Push(digit) + digit, u); return true; } template<> inline bool Writer3::WriteUint64(uint64_t u) { unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Allocate(digit) + digit, u); + WriteUint64Reverse(os_->Push(digit) + digit, u); return true; } template<> inline bool Writer3::WriteUint64(uint64_t u) { unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Allocate(digit) + digit, u); + WriteUint64Reverse(os_->Push(digit) + digit, u); return true; } @@ -739,28 +743,28 @@ class Writer4 { template<> inline bool Writer4::WriteUint(unsigned u) { unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Allocate(digit) + digit, u); + WriteUintReverse(os_->Push(digit) + digit, u); return true; } template<> inline bool Writer4::WriteUint(unsigned u) { unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Allocate(digit) + digit, u); + WriteUintReverse(os_->Push(digit) + digit, u); return true; } template<> inline bool Writer4::WriteUint64(uint64_t u) { unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Allocate(digit) + digit, u); + WriteUint64Reverse(os_->Push(digit) + digit, u); return true; } template<> inline bool Writer4::WriteUint64(uint64_t u) { unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Allocate(digit) + digit, u); + WriteUint64Reverse(os_->Push(digit) + digit, u); return true; } @@ -896,35 +900,82 @@ void itoa64_Writer_InsituStringStream() { OUTPUT_LENGTH(length); }; +// Full specialization for InsituStringStream to prevent memory copying +// (normally we will not use InsituStringStream for writing, just for testing) + +namespace rapidjson { + +template<> +bool rapidjson::Writer::WriteInt(int i) { + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(11 - (end - buffer)); + return true; +} + +template<> +bool Writer::WriteUint(unsigned u) { + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(10 - (end - buffer)); + return true; +} + +template<> +bool Writer::WriteInt64(int64_t i64) { + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(21 - (end - buffer)); + return true; +} + +template<> +bool Writer::WriteUint64(uint64_t u) { + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(20 - (end - buffer)); + return true; +} + +} // namespace rapidjson + +TEST_F(Misc, itoa_Writer_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa_Writer1_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa_Writer2_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa_Writer3_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa_Writer4_StringBufferVerify) { itoa_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa_Writer_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa_Writer1_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa_Writer2_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa_Writer3_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa_Writer4_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa_Writer_StringBuffer) { itoa_Writer_StringBuffer >(); } TEST_F(Misc, itoa_Writer1_StringBuffer) { itoa_Writer_StringBuffer >(); } TEST_F(Misc, itoa_Writer2_StringBuffer) { itoa_Writer_StringBuffer >(); } TEST_F(Misc, itoa_Writer3_StringBuffer) { itoa_Writer_StringBuffer >(); } TEST_F(Misc, itoa_Writer4_StringBuffer) { itoa_Writer_StringBuffer >(); } +TEST_F(Misc, itoa_Writer_InsituStringStream) { itoa_Writer_InsituStringStream >(); } TEST_F(Misc, itoa_Writer1_InsituStringStream) { itoa_Writer_InsituStringStream >(); } TEST_F(Misc, itoa_Writer2_InsituStringStream) { itoa_Writer_InsituStringStream >(); } TEST_F(Misc, itoa_Writer3_InsituStringStream) { itoa_Writer_InsituStringStream >(); } TEST_F(Misc, itoa_Writer4_InsituStringStream) { itoa_Writer_InsituStringStream >(); } +TEST_F(Misc, itoa64_Writer_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa64_Writer1_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa64_Writer2_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa64_Writer3_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } TEST_F(Misc, itoa64_Writer4_StringBufferVerify) { itoa64_Writer_StringBufferVerify >(); } +TEST_F(Misc, itoa64_Writer_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa64_Writer1_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa64_Writer2_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa64_Writer3_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } TEST_F(Misc, itoa64_Writer4_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify >(); } +TEST_F(Misc, itoa64_Writer_StringBuffer) { itoa64_Writer_StringBuffer >(); } TEST_F(Misc, itoa64_Writer1_StringBuffer) { itoa64_Writer_StringBuffer >(); } TEST_F(Misc, itoa64_Writer2_StringBuffer) { itoa64_Writer_StringBuffer >(); } TEST_F(Misc, itoa64_Writer3_StringBuffer) { itoa64_Writer_StringBuffer >(); } TEST_F(Misc, itoa64_Writer4_StringBuffer) { itoa64_Writer_StringBuffer >(); } +TEST_F(Misc, itoa64_Writer_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } TEST_F(Misc, itoa64_Writer1_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } TEST_F(Misc, itoa64_Writer2_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } TEST_F(Misc, itoa64_Writer3_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } From 6f1646138a35ad8ee24b6249c5a0eefb9c420fbe Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 25 Jul 2014 00:59:19 +0800 Subject: [PATCH 6/6] Fixes stack overflow --- include/rapidjson/writer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index c6cdfdd4c..d72d274d3 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -238,7 +238,7 @@ class Writer { } bool WriteUint64(uint64_t u64) { - char buffer[11]; + char buffer[20]; const char* end = internal::u64toa(u64, buffer); for (const char* p = buffer; p != end; ++p) os_->Put(*p);