Skip to content

Commit

Permalink
update toml++ to v2.4.0 (#55)
Browse files Browse the repository at this point in the history
other small changes:
- removed dependency on some of toml++'s internal macros
- updated benchmark script to show relative speedup/slowdown factor
- updated README with new benchmark data
- updated `tloptional`
- made use of `tloptional` over `std::optional` switched based on a configurable `#define`
- added an explicit .clang-format config
  • Loading branch information
marzer authored May 23, 2021
1 parent f9d7c41 commit 970d1bc
Show file tree
Hide file tree
Showing 11 changed files with 239 additions and 70 deletions.
166 changes: 166 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

3 changes: 2 additions & 1 deletion .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ jobs:

steps:
- uses: actions/checkout@v2
- uses: DoozyX/clang-format-lint-action@v0.5
- uses: DoozyX/clang-format-lint-action@v0.12
with:
source: "./include ./src"
clangFormatVersion: 12

publish:
runs-on: ubuntu-latest
Expand Down
29 changes: 9 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
[![Conda Status](https://anaconda.org/dorafmon/pytomlpp/badges/version.svg)](https://anaconda.org/dorafmon/pytomlpp)
[![PyPI version](https://badge.fury.io/py/pytomlpp.svg)](https://badge.fury.io/py/pytomlpp)

This is an unofficial python wrapper for `toml++` (https://marzer.github.io/tomlplusplus/).
This is an python wrapper for `toml++` (https://marzer.github.io/tomlplusplus/).

Some points you may want to know before use:
* Using `toml++` means that this module is fully compatible with TOML [v1.0.0-rc.3](https://toml.io/en/v1.0.0-rc.3).
* Using `toml++` means that this module is fully compatible with TOML [v1.0.0](https://toml.io/en/v1.0.0).
* We convert toml structure to native python data structures (dict/list etc.) when parsing, this is more inline with what `json` module does.
* The binding is using [pybind11](https://github.com/pybind/pybind11).
* The project is tested using [toml-test](https://github.com/BurntSushi/toml-test) and [pytest](https://github.com/pytest-dev/pytest).
Expand All @@ -29,27 +29,16 @@ Out[6]: '"你好" = "world"'
```

# Why bother?
There are some exisitng python TOML parser on the market but from my experience they are all purely implemented in python which is a bit slow.
There are some existing python TOML parsers on the market but from my experience they are implemented purely in python which is a bit slow.

```
In [1]: import pytomlpp
In [2]: import toml
In [3]: def run_parser(parser_func, toml_string):
...: for i in range(1000):
...: parser_func(toml_string)
...:
In [4]: %timeit run_parser(pytomlpp.loads, toml_string)
310 ms ± 56.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [5]: %timeit run_parser(toml.loads, toml_string)
3.5 s ± 162 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [6]: pytomlpp.lib_version
Out[6]: '1.3.2'
Parsing data.toml 5000 times:
pytomlpp: 0.662 s
toml: 5.277 s (7.9x slower)
qtoml: 8.020 s (12.1x slower)
tomlkit: 32.898 s (49.6x slower)
```
Test it for yourself using [the benchmark script](benchmark/run.py).

# Installing

Expand Down
1 change: 1 addition & 0 deletions benchmark/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pytomlpp
toml
tomlkit
qtoml
36 changes: 26 additions & 10 deletions benchmark/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,32 @@
import qtoml
import timeit

def benchmark(name, func, number=5000):
def benchmark(name, run_count, func, compare_to=None):
print(f'{name:>10}: Running...', end='', flush=True)
res = str(timeit.timeit(func, number=number)).split('.')
print('\b'*10 + f'{res[0]:>3}.{res[1]} s')
time_taken = timeit.timeit(func, number=run_count)
res = str(time_taken).split('.')
print('\b'*10, end='')
print(f'{res[0]:>4}.{res[1][:3]} s', end='')
if compare_to is not None:
delta = time_taken / compare_to
relation = 'slower'
if delta < 1.0:
delta = 1.0 / delta
relation = 'faster'
delta = int(delta * 10.0) / 10.0
print(f' ({delta}x {relation})', end='')
print('')
return time_taken

test_data = ''
with open('data.toml', 'r', encoding='utf-8') as f:
test_data = f.read()
def run(run_count = 5000):
test_data = ''
with open('data.toml', 'r', encoding='utf-8') as f:
test_data = f.read()
print(f'Parsing data.toml {run_count} times:')
baseline = benchmark('pytomlpp', run_count, lambda: pytomlpp.loads(test_data))
benchmark('toml', run_count, lambda: toml.loads(test_data), compare_to=baseline)
benchmark('qtoml', run_count, lambda: qtoml.loads(test_data), compare_to=baseline)
benchmark('tomlkit', run_count, lambda: tomlkit.parse(test_data), compare_to=baseline)

benchmark('pytomlpp', lambda: pytomlpp.loads(test_data))
benchmark('toml', lambda: toml.loads(test_data))
benchmark('qtoml', lambda: qtoml.loads(test_data))
benchmark('tomlkit', lambda: tomlkit.parse(test_data))
if __name__ == '__main__':
run()
25 changes: 16 additions & 9 deletions include/pytomlpp/pytomlpp.hpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
#pragma once

// pytomlpp config
#ifndef PYTOMLPP_USE_TL_OPTIONAL
#ifdef __APPLE__
#define PYTOMLPP_USE_TL_OPTIONAL 1
#else
#define PYTOMLPP_USE_TL_OPTIONAL 0
#endif
#endif // PYTOMLPP_USE_TL_OPTIONAL
#ifndef PYTOMLPP_PROFILING
#define PYTOMLPP_PROFILING 0 // see a profiling summary on shutdown
#endif

// toml++ config
#define TOML_OPTIONAL_TYPE tl::optional
#define TOML_WINDOWS_COMPAT 0
#define TOML_LARGE_FILES 1
#define TOML_HEADER_ONLY 0
#define TOML_UNDEF_MACROS 0 // leaves some toml++'s macros for us to use
#ifdef __APPLE__
#define TOML_INT_CHARCONV 0
#endif

// pytomlpp config
#ifndef PYTOMLPP_PROFILING
#define PYTOMLPP_PROFILING 0 // see a profiling summary on shutdown
#if PYTOMLPP_USE_TL_OPTIONAL
#define TOML_OPTIONAL_TYPE tl::optional
#endif

// common includes
#include <tomlplusplus/include/toml++/toml_preprocessor.h>
TOML_DISABLE_WARNINGS
#if PYTOMLPP_USE_TL_OPTIONAL
#include <optional.hpp>
#endif
#include <pybind11/pybind11.h>
#include <sstream>
#include <tomlplusplus/include/toml++/toml.h>
TOML_ENABLE_WARNINGS

// namespace and type forward declarations
namespace py = pybind11;
Expand Down
3 changes: 0 additions & 3 deletions src/encoding_decoding.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#include <pytomlpp/pytomlpp.hpp>

TOML_DISABLE_WARNINGS
#include <pybind11/stl.h>
TOML_ENABLE_WARNINGS

namespace pytomlpp {
py::list toml_array_to_py_list(toml::array &&a) {
Expand Down
2 changes: 0 additions & 2 deletions src/pytomlpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

#include <pytomlpp/pytomlpp.hpp>
#if PYTOMLPP_PROFILING
TOML_DISABLE_WARNINGS
#include <chrono>
#include <iomanip>
#include <pybind11/iostream.h>
TOML_ENABLE_WARNINGS
#endif // PYTOMLPP_PROFILING

namespace {
Expand Down
4 changes: 0 additions & 4 deletions src/type_casters.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#include <pytomlpp/pytomlpp.hpp>

TOML_DISABLE_WARNINGS
//#include <pybind11/chrono.h>
#include <datetime.h>
TOML_ENABLE_WARNINGS

namespace {
void lazy_init_py_date_time() noexcept {
Expand Down
Loading

0 comments on commit 970d1bc

Please sign in to comment.