unformat.cxx 1.2019.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CMakeLists.txt ADDED
@@ -0,0 +1,39 @@
1
+ cmake_minimum_required(VERSION 3.0)
2
+
3
+ project(Unformat)
4
+
5
+ set(CMAKE_CXX_STANDARD 11)
6
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
7
+
8
+ include(DownloadProject/DownloadProject.cmake)
9
+
10
+ # Functional test
11
+ download_project(PROJ googletest
12
+ GIT_REPOSITORY https://github.com/google/googletest.git
13
+ GIT_TAG release-1.8.0
14
+ ${UPDATE_DISCONNECTED_IF_AVAILABLE}
15
+ )
16
+ # Prevent GoogleTest from overriding our compiler/linker options
17
+ # when building with Visual Studio
18
+ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
19
+ add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
20
+ add_executable(unformat_test unformat.h unformat_test.cpp)
21
+ target_link_libraries(unformat_test gtest gmock_main)
22
+
23
+ # Benchmark
24
+ if (CMAKE_VERSION VERSION_LESS 3.2)
25
+ set(UPDATE_DISCONNECTED_IF_AVAILABLE "")
26
+ else()
27
+ set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
28
+ endif()
29
+
30
+ download_project(PROJ benchmark
31
+ GIT_REPOSITORY https://github.com/google/benchmark.git
32
+ GIT_TAG v1.3.0
33
+ ${UPDATE_DISCONNECTED_IF_AVAILABLE}
34
+ )
35
+
36
+ set(BENCHMARK_ENABLE_TESTING OFF)
37
+ add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR})
38
+ add_executable(unformat_benchmark unformat.h unformat_benchmark.cpp)
39
+ target_link_libraries(unformat_benchmark benchmark)
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org>
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ **[Source available on GitHub](https://github.com/adamyaxley/Unformat)**
2
+
3
+ # Unformat
4
+ Parsing and extraction of original data from brace style "{}" formatted strings. It basically _unformats_ what you thought was formatted for good. It is developed and maintained by [Adam Yaxley](https://github.com/adamyaxley).
5
+
6
+ ## Installation
7
+
8
+ Run:
9
+ ```bash
10
+ $ npm i unformat.cxx
11
+ ```
12
+
13
+ And then include `unformat.h` as follows:
14
+ ```cxx
15
+ #include "node_modules/unformat.cxx/unformat.h"
16
+ ```
17
+
18
+ ## Quick Example
19
+ Unformat is simple to use and works on all basic types. See the below example for extracting a `std::string` and an 'int'
20
+ ```c++
21
+ std::string name;
22
+ int age;
23
+
24
+ unformat("Harry is 18 years old.", "{} is {} years old.", name, age);
25
+ // name == "Harry" and age == 18
26
+ ```
27
+ As an optimisation, if the format string is known at compile time, it can be parsed into a constant expression by making use of `ay::make_format`. In tests, this increases runtime speed by a factor of 3 or 4.
28
+ ```c++
29
+ std::string name;
30
+ int age;
31
+
32
+ constexpr auto format = ay::make_format("{} is {} years old.");
33
+ unformat("Harry is 18 years old.", format, name, age);
34
+ // name == "Harry" and age == 18
35
+ ```
36
+
37
+ ## How do I use this library?
38
+ Unformat is a single-file header only library so integration is easy. All you need to do is copy `unformat.h` into your project, and away you go.
39
+
40
+ ## Public Domain
41
+ This software is completely open source and in the public domain. See LICENSE for details.
42
+
43
+ ## Contributing
44
+ Pull requests are very welcome. You may also create Issues and I will have a look into it as soon as I can.
45
+
46
+ ## Speed
47
+ Unformat is super awesome back to the future style lightning fast compared to traditional parsing methods. Below is the output from Google Benchmark on unformat_benchmark.cpp. Great Scott!
48
+ ```
49
+ Run on (16 X 2993 MHz CPU s)
50
+ 03/13/19 18:10:57
51
+ --------------------------------------------------------------------
52
+ Benchmark Time CPU Iterations
53
+ --------------------------------------------------------------------
54
+ Unformat 72 ns 71 ns 8960000
55
+ Unformat_ConstChar 69 ns 70 ns 8960000
56
+ Unformat_ConstexprMakeFormat 36 ns 35 ns 19478261
57
+ StdStringStream 844 ns 854 ns 896000
58
+ StdRegex 9975 ns 10010 ns 64000
59
+ StdScanf 1716 ns 1726 ns 407273
60
+ ```
61
+
62
+ <br>
63
+ <br>
64
+
65
+
66
+ [![ORG](https://img.shields.io/badge/org-nodef-green?logo=Org)](https://nodef.github.io)
67
+ ![](https://ga-beacon.deno.dev/G-RC63DPBH3P:SH3Eq-NoQ9mwgYeHWxu7cw/github.com/nodef/unformat.cxx)
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "unformat.cxx",
3
+ "version": "1.2019.3",
4
+ "description": "Fastest type-safe parsing library in the world for C++14 or C++17 (up to 300x faster than std::regex); Adam Yaxley (2017).",
5
+ "keywords": ["c", "library", "parsing", "formatting", "unformat", "unformatted", "fast", "safe", "type-safe", "cpp", "c++", "cxx"],
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/nodef/unformat.cxx.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/nodef/unformat.cxx/issues"
13
+ },
14
+ "homepage": "https://github.com/nodef/unformat.cxx#readme"
15
+ }
package/unformat.h ADDED
@@ -0,0 +1,341 @@
1
+ #pragma once
2
+
3
+ #ifdef _MSC_VER
4
+ #if _MSC_VER >= 1910 && _HAS_CXX17
5
+ #define UNFORMAT_CPP17
6
+ #endif
7
+ #endif
8
+
9
+ #include <string>
10
+ #ifdef UNFORMAT_CPP17
11
+ #include <string_view>
12
+ #endif
13
+
14
+ namespace
15
+ {
16
+ template <typename T>
17
+ void unformat_signed_int(const char* input, const char* inputEnd, T& output) noexcept
18
+ {
19
+ output = 0;
20
+ int sign = 1;
21
+ if (*input == '-')
22
+ {
23
+ sign = -1;
24
+ ++input;
25
+ }
26
+
27
+ #ifndef UNFORMAT_DISABLE_PLUS_SIGN
28
+ // Ignore plus
29
+ if (*input == '+')
30
+ {
31
+ ++input;
32
+ }
33
+ #endif
34
+
35
+ while (input != inputEnd)
36
+ {
37
+ output *= 10;
38
+ output += (*input - '0');
39
+ ++input;
40
+ }
41
+ output *= sign;
42
+ }
43
+
44
+ template <typename T>
45
+ void unformat_unsigned_int(const char* input, const char* inputEnd, T& output) noexcept
46
+ {
47
+ output = 0;
48
+ while (input != inputEnd)
49
+ {
50
+ output *= 10;
51
+ output += (*input - '0');
52
+ ++input;
53
+ }
54
+ }
55
+
56
+ template <typename T>
57
+ void unformat_real(const char* input, const char* inputEnd, T& output) noexcept
58
+ {
59
+ long double f = 0;
60
+
61
+ // Check for negative
62
+ if (*input == '-')
63
+ {
64
+ f = -f;
65
+ ++input;
66
+ }
67
+
68
+ #ifndef UNFORMAT_DISABLE_PLUS_SIGN
69
+ // Ignore plus
70
+ if (*input == '+')
71
+ {
72
+ ++input;
73
+ }
74
+ #endif
75
+
76
+ // Parse units
77
+ while (*input != '.' && input != inputEnd && *input != 'e')
78
+ {
79
+ f *= 10;
80
+ f += (*input - '0');
81
+ ++input;
82
+ }
83
+
84
+ // Parse decimal
85
+ if (*input == '.')
86
+ {
87
+ ++input;
88
+ long double decimal = 1.0L;
89
+ while (input != inputEnd && *input != 'e')
90
+ {
91
+ decimal *= 0.1L;
92
+ f += (*input - '0') * decimal;
93
+ ++input;
94
+ }
95
+ }
96
+
97
+ // Parse exponent
98
+ if (*input == 'e')
99
+ {
100
+ ++input;
101
+ if (*input == '+')
102
+ {
103
+ ++input; // Skip + as unformat_signed_int can't handle it
104
+ }
105
+ int e;
106
+ unformat_signed_int(input, inputEnd, e);
107
+ f *= pow(10L, e);
108
+ }
109
+
110
+ output = static_cast<T>(f);
111
+ }
112
+ }
113
+
114
+ namespace ay
115
+ {
116
+ // Not defined on purpose for the general case. Note that you can define custom unformatters by defining new specialisations
117
+ // for this function.
118
+ template <typename T>
119
+ void unformat_arg(const char* input, const char* inputEnd, T& output) noexcept;
120
+
121
+ template <typename T>
122
+ T unformat_arg(const char* input, const char* inputEnd) noexcept
123
+ {
124
+ T output;
125
+ unformat_arg(input, inputEnd, output);
126
+ return output;
127
+ }
128
+
129
+ #ifdef UNFORMAT_CPP17
130
+ template <typename T>
131
+ T unformat_arg(std::string_view input) noexcept
132
+ {
133
+ return unformat_arg<T>(input.data(), input.data() + input.length());
134
+ }
135
+ #endif
136
+
137
+ template <typename T>
138
+ T unformat_arg(std::string input) noexcept
139
+ {
140
+ return unformat_arg<T>(input.c_str(), input.c_str() + input.length());
141
+ }
142
+
143
+ template <>
144
+ inline void unformat_arg<char>(const char* input, const char* inputEnd, char& output) noexcept
145
+ {
146
+ output = input[0];
147
+ }
148
+
149
+ template <>
150
+ inline void unformat_arg<unsigned char>(const char* input, const char* inputEnd, unsigned char& output) noexcept
151
+ {
152
+ output = input[0];
153
+ }
154
+
155
+ #ifdef UNFORMAT_CPP17
156
+ template <>
157
+ inline void unformat_arg<std::string_view>(const char* input, const char* inputEnd, std::string_view& output) noexcept
158
+ {
159
+ output = std::string_view(input, inputEnd - input);
160
+ }
161
+ #endif
162
+
163
+ template <>
164
+ inline void unformat_arg<std::string>(const char* input, const char* inputEnd, std::string& output) noexcept
165
+ {
166
+ output.assign(input, inputEnd - input);
167
+ }
168
+
169
+ template <>
170
+ inline void unformat_arg<float>(const char* input, const char* inputEnd, float& output) noexcept
171
+ {
172
+ unformat_real<float>(input, inputEnd, output);
173
+ }
174
+
175
+ template <>
176
+ inline void unformat_arg<double>(const char* input, const char* inputEnd, double& output) noexcept
177
+ {
178
+ unformat_real<double>(input, inputEnd, output);
179
+ }
180
+
181
+ template <>
182
+ inline void unformat_arg<short>(const char* input, const char* inputEnd, short& output) noexcept
183
+ {
184
+ unformat_signed_int<short>(input, inputEnd, output);
185
+ }
186
+
187
+ template <>
188
+ inline void unformat_arg<int>(const char* input, const char* inputEnd, int& output) noexcept
189
+ {
190
+ unformat_signed_int<int>(input, inputEnd, output);
191
+ }
192
+
193
+ template <>
194
+ inline void unformat_arg<long>(const char* input, const char* inputEnd, long& output) noexcept
195
+ {
196
+ unformat_signed_int<long>(input, inputEnd, output);
197
+ }
198
+
199
+ template <>
200
+ inline void unformat_arg<long long>(const char* input, const char* inputEnd, long long& output) noexcept
201
+ {
202
+ unformat_signed_int<long long>(input, inputEnd, output);
203
+ }
204
+
205
+ template <>
206
+ inline void unformat_arg<unsigned short>(const char* input, const char* inputEnd, unsigned short& output) noexcept
207
+ {
208
+ unformat_unsigned_int<unsigned short>(input, inputEnd, output);
209
+ }
210
+
211
+ template <>
212
+ inline void unformat_arg<unsigned int>(const char* input, const char* inputEnd, unsigned int& output) noexcept
213
+ {
214
+ unformat_unsigned_int<unsigned int>(input, inputEnd, output);
215
+ }
216
+
217
+ template <>
218
+ inline void unformat_arg<unsigned long>(const char* input, const char* inputEnd, unsigned long& output) noexcept
219
+ {
220
+ unformat_unsigned_int<unsigned long>(input, inputEnd, output);
221
+ }
222
+
223
+ template <>
224
+ inline void unformat_arg<unsigned long long>(const char* input, const char* inputEnd, unsigned long long& output) noexcept
225
+ {
226
+ unformat_unsigned_int<unsigned long long>(input, inputEnd, output);
227
+ }
228
+
229
+ struct format;
230
+
231
+ constexpr format make_format_non_template(const char* str, std::size_t N);
232
+
233
+ struct format
234
+ {
235
+ constexpr format() {}
236
+
237
+ template <std::size_t N>
238
+ constexpr format(const char(&str)[N])
239
+ {
240
+ *this = make_format_non_template(str, N);
241
+ }
242
+
243
+ format(const char* str)
244
+ {
245
+ *this = make_format_non_template(str, std::strlen(str));
246
+ }
247
+
248
+ static constexpr std::size_t MAX_COUNT{ 16 };
249
+ std::size_t offsets[MAX_COUNT]{};
250
+ char endChar[MAX_COUNT]{};
251
+ std::size_t count{ 0 };
252
+ };
253
+
254
+ template <std::size_t N>
255
+ constexpr format make_format(const char(&str)[N]) noexcept
256
+ {
257
+ return make_format_non_template(str, N);
258
+ }
259
+
260
+ constexpr format make_format_non_template(const char* str, std::size_t N)
261
+ {
262
+ format format;
263
+
264
+ std::size_t from = 0;
265
+ for (std::size_t to = 0; to < N - 1; to++)
266
+ {
267
+ if (str[to] == '{' && str[to + 1] == '}')
268
+ {
269
+ if (format.count >= format::MAX_COUNT)
270
+ {
271
+ // Stops compilation in a constexpr context
272
+ throw std::exception("Max number of {} has been exceeded.");
273
+ }
274
+ format.offsets[format.count] = to - from;
275
+ format.endChar[format.count] = str[to + 2]; // May be '\0' which is fine
276
+ ++format.count;
277
+ // Advance markers
278
+ from = to + 2;
279
+ to = from;
280
+ }
281
+ }
282
+
283
+ return format;
284
+ }
285
+
286
+ // Empty function to end recursion, no more args to process
287
+ inline void unformat_internal(std::size_t inputPos, const char* input, const format& format) noexcept
288
+ {
289
+ }
290
+
291
+ template <typename T, typename... TRest>
292
+ void unformat_internal(std::size_t inputPos, const char* input, const format& format, T& first, TRest&... rest) noexcept
293
+ {
294
+ const std::size_t argNo = format.count - sizeof...(rest) - 1;
295
+
296
+ // Get the location of the first brace
297
+ const auto offset = format.offsets[argNo];
298
+
299
+ // Find input string
300
+ inputPos += offset;
301
+ auto inputEnd = inputPos;
302
+ while (input[inputEnd] != format.endChar[argNo])
303
+ {
304
+ ++inputEnd;
305
+ }
306
+
307
+ // Process this arg
308
+ unformat_arg(&input[inputPos], &input[inputEnd], first);
309
+
310
+ // Process TRest
311
+ unformat_internal(inputEnd, input, format, rest...);
312
+ }
313
+
314
+ // Parses and extracts data from 'input' given a braced styled "{}" 'format' into 'args...'
315
+ // For example:
316
+ // std::string name, int age;
317
+ // constexpr auto format = make_format("{} is {} years old.");
318
+ // unformat("Harry is 18 years old.", format, name, age);
319
+ //
320
+ // Then the following data is extracted:
321
+ // name == "Harry" and age == 18
322
+ template <typename... Args>
323
+ void unformat(const char* input, const format& format, Args&... args) noexcept
324
+ {
325
+ unformat_internal(0, input, format, args...);
326
+ }
327
+
328
+ // Parses and extracts data from 'input' given a braced styled "{}" 'format' into 'args...'
329
+ // For example:
330
+ // std::string name, int age;
331
+ // constexpr auto format = make_format("{} is {} years old.");
332
+ // unformat("Harry is 18 years old.", format, name, age);
333
+ //
334
+ // Then the following data is extracted:
335
+ // name == "Harry" and age == 18
336
+ template <typename... Args>
337
+ void unformat(const std::string& input, const format& format, Args&... args) noexcept
338
+ {
339
+ unformat_internal(0, input.c_str(), format, args...);
340
+ }
341
+ }